const std = @import("std"); const util = @import("util"); const services = @import("../services.zig"); const pkg = @import("../lib.zig"); const Uuid = util.Uuid; const DateTime = util.DateTime; const ApiContext = pkg.ApiContext; const CreateOptions = pkg.invites.CreateOptions; const Invite = pkg.invites.Invite; pub fn create( alloc: std.mem.Allocator, ctx: ApiContext, svcs: anytype, options: CreateOptions, ) !Uuid { // Only logged in users can make invites const user_id = ctx.userId() orelse return error.TokenRequired; const community_id = if (options.to_community) |id| blk: { // Only admins can send invites for other communities if (!ctx.isAdmin()) return error.PermissionDenied; break :blk id; } else ctx.community.id; // Users can only make user invites if (options.kind != .user and !ctx.isAdmin()) return error.PermissionDenied; return try svcs.createInvite(alloc, .{ .created_by = user_id, .community_id = community_id, .name = options.name, .lifespan = options.lifespan, .max_uses = options.max_uses, .kind = options.kind, }); } pub fn isValid(invite: services.invites.Invite) bool { if (invite.max_uses != null and invite.times_used >= invite.max_uses.?) return false; if (invite.expires_at != null and DateTime.now().isAfter(invite.expires_at.?)) return false; return true; } fn getInviteImpl( alloc: std.mem.Allocator, ctx: ApiContext, svcs: anytype, invite: services.invites.Invite, ) !Invite { errdefer util.deepFree(alloc, invite); if (!Uuid.eql(invite.community_id, ctx.community.id) and !ctx.isAdmin()) return error.NotFound; if (!isValid(invite)) return error.NotFound; const community = try svcs.getCommunity(alloc, invite.community_id); defer util.deepFree(alloc, community); const url = try std.fmt.allocPrint( alloc, "{s}://{s}/invite/{s}", .{ @tagName(community.scheme), community.host, invite.code }, ); errdefer util.deepFree(alloc, url); return Invite{ .id = invite.id, .created_by = invite.created_by, .community_id = invite.community_id, .name = invite.name, .code = invite.code, .url = url, .created_at = invite.created_at, .times_used = invite.times_used, .expires_at = invite.expires_at, .max_uses = invite.max_uses, .kind = invite.kind, }; } pub fn get( alloc: std.mem.Allocator, ctx: ApiContext, svcs: anytype, id: Uuid, ) !Invite { const invite = try svcs.getInvite(alloc, id); return getInviteImpl(alloc, ctx, svcs, invite); } pub fn getByCode( alloc: std.mem.Allocator, ctx: ApiContext, svcs: anytype, code: []const u8, ) !Invite { const invite = try svcs.getInviteByCode(alloc, code, ctx.community.id); return getInviteImpl(alloc, ctx, svcs, invite); }