const std = @import("std"); const builtin = @import("builtin"); const util = @import("util"); const models = @import("../db/models.zig"); const DbError = @import("../db.zig").ExecError; const getRandom = @import("../api.zig").getRandom; const Uuid = util.Uuid; const DateTime = util.DateTime; // 9 random bytes = 12 random b64 const rand_len = 8; const code_len = 12; const Encoder = std.base64.url_safe.Encoder; const Decoder = std.base64.url_safe.Decoder; pub const InviteType = enum { system, community_owner, user, pub const jsonStringify = defaultJsonStringify(@This()); }; fn defaultJsonStringify(comptime T: type) fn (T, std.json.StringifyOptions, anytype) anyerror!void { return struct { pub fn jsonStringify(s: T, _: std.json.StringifyOptions, writer: anytype) !void { return std.fmt.format(writer, "\"{s}\"", .{@tagName(s)}); } }.jsonStringify; } pub const Invite = struct { id: Uuid, created_by: Uuid, // User ID to_community: ?Uuid, name: []const u8, code: []const u8, created_at: DateTime, times_used: usize, expires_at: ?DateTime, max_uses: ?usize, invite_type: InviteType, }; fn cloneStr(str: []const u8, alloc: std.mem.Allocator) ![]const u8 { const new = try alloc.alloc(u8, str.len); std.mem.copy(u8, new, str); return new; } pub const InviteOptions = struct { name: ?[]const u8 = null, max_uses: ?usize = null, expires_at: ?DateTime = null, invite_type: InviteType = .user, }; pub fn create(db: anytype, created_by: Uuid, to_community: ?Uuid, options: InviteOptions, alloc: std.mem.Allocator) !Invite { var code_bytes: [rand_len]u8 = undefined; getRandom().bytes(&code_bytes); const code = try alloc.alloc(u8, code_len); errdefer alloc.free(code); _ = Encoder.encode(code, &code_bytes); const name = if (options.name) |name| try cloneStr(name, alloc) else try cloneStr(code, alloc); const id = Uuid.randV4(getRandom()); const created_at = DateTime.now(); const invite = Invite{ .id = id, .created_by = created_by, .to_community = to_community, .name = name, .code = code, .created_at = created_at, .times_used = 0, .expires_at = options.expires_at, .max_uses = options.max_uses, .invite_type = options.invite_type, }; try db.insert("invite", invite); return invite; }