Track invite uses and handle properly
This commit is contained in:
parent
76f2b818ab
commit
ae9a062caf
4 changed files with 13 additions and 12 deletions
|
@ -86,6 +86,12 @@ pub const LoginResult = struct {
|
||||||
issued_at: DateTime,
|
issued_at: DateTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const InviteOptions = struct {
|
||||||
|
name: []const u8 = "",
|
||||||
|
max_uses: ?i64 = null,
|
||||||
|
lifetime: ?i64 = null, // unix seconds, TODO make a TimeSpan type
|
||||||
|
};
|
||||||
|
|
||||||
threadlocal var prng: std.rand.DefaultPrng = undefined;
|
threadlocal var prng: std.rand.DefaultPrng = undefined;
|
||||||
|
|
||||||
pub fn initThreadPrng(seed: u64) void {
|
pub fn initThreadPrng(seed: u64) void {
|
||||||
|
@ -225,7 +231,8 @@ fn ApiConn(comptime DbConn: type) type {
|
||||||
const now = DateTime.now();
|
const now = DateTime.now();
|
||||||
const invite_id = if (info.invite_code) |invite_code| blk: {
|
const invite_id = if (info.invite_code) |invite_code| blk: {
|
||||||
const invite = (try self.db.getBy(models.Invite, .invite_code, invite_code, self.arena.allocator())) orelse return error.InvalidInvite;
|
const invite = (try self.db.getBy(models.Invite, .invite_code, invite_code, self.arena.allocator())) orelse return error.InvalidInvite;
|
||||||
const uses_left = if (invite.max_uses) |max_uses| invite.uses < max_uses else true;
|
const uses = try self.db.countWhereEq(models.LocalUser, .invite_id, invite.id);
|
||||||
|
const uses_left = if (invite.max_uses) |max_uses| uses < max_uses else true;
|
||||||
const expired = if (invite.expires_at) |expires_at| now.seconds_since_epoch > expires_at.seconds_since_epoch else false;
|
const expired = if (invite.expires_at) |expires_at| now.seconds_since_epoch > expires_at.seconds_since_epoch else false;
|
||||||
|
|
||||||
if (!uses_left or expired) return error.InvalidInvite;
|
if (!uses_left or expired) return error.InvalidInvite;
|
||||||
|
@ -306,11 +313,6 @@ fn ApiConn(comptime DbConn: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const InviteOptions = struct {
|
|
||||||
name: []const u8 = "",
|
|
||||||
max_uses: ?i64 = null,
|
|
||||||
lifetime: ?i64 = null, // unix seconds, TODO make a TimeSpan type
|
|
||||||
};
|
|
||||||
pub fn createInvite(self: *Self, options: InviteOptions) !models.Invite {
|
pub fn createInvite(self: *Self, options: InviteOptions) !models.Invite {
|
||||||
const id = Uuid.randV4(prng.random());
|
const id = Uuid.randV4(prng.random());
|
||||||
|
|
||||||
|
@ -334,7 +336,6 @@ fn ApiConn(comptime DbConn: type) type {
|
||||||
.created_by = user_id,
|
.created_by = user_id,
|
||||||
.invite_code = code_str,
|
.invite_code = code_str,
|
||||||
|
|
||||||
.uses = 0,
|
|
||||||
.max_uses = options.max_uses,
|
.max_uses = options.max_uses,
|
||||||
|
|
||||||
.created_at = now,
|
.created_at = now,
|
||||||
|
|
|
@ -3,16 +3,19 @@ const http = @import("http");
|
||||||
const Uuid = @import("util").Uuid;
|
const Uuid = @import("util").Uuid;
|
||||||
|
|
||||||
const utils = @import("../../controllers.zig").utils;
|
const utils = @import("../../controllers.zig").utils;
|
||||||
const NoteCreateInfo = @import("../../api.zig").NoteCreateInfo;
|
const InviteOptions = @import("../../api.zig").InviteOptions;
|
||||||
|
|
||||||
const RequestServer = root.RequestServer;
|
const RequestServer = root.RequestServer;
|
||||||
const RouteArgs = http.RouteArgs;
|
const RouteArgs = http.RouteArgs;
|
||||||
|
|
||||||
pub fn create(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs) !void {
|
pub fn create(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs) !void {
|
||||||
|
const opt = try utils.parseRequestBody(InviteOptions, ctx);
|
||||||
|
defer utils.freeRequestBody(opt, ctx.alloc);
|
||||||
|
|
||||||
var api = try utils.getApiConn(srv, ctx);
|
var api = try utils.getApiConn(srv, ctx);
|
||||||
defer api.close();
|
defer api.close();
|
||||||
|
|
||||||
const invite = try api.createInvite(.{});
|
const invite = try api.createInvite(opt);
|
||||||
|
|
||||||
try utils.respondJson(ctx, .created, invite);
|
try utils.respondJson(ctx, .created, invite);
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,6 @@ pub const Database = struct {
|
||||||
\\
|
\\
|
||||||
\\ username TEXT NOT NULL,
|
\\ username TEXT NOT NULL,
|
||||||
\\ email TEXT,
|
\\ email TEXT,
|
||||||
\\ invite_id TEXT,
|
|
||||||
\\
|
\\
|
||||||
\\ hashed_password TEXT NOT NULL,
|
\\ hashed_password TEXT NOT NULL,
|
||||||
\\ password_changed_at INTEGER NOT NULL,
|
\\ password_changed_at INTEGER NOT NULL,
|
||||||
|
@ -215,7 +214,6 @@ pub const Database = struct {
|
||||||
\\ invite_code TEXT NOT NULL,
|
\\ invite_code TEXT NOT NULL,
|
||||||
\\ created_by TEXT NOT NULL REFERENCES local_user(id),
|
\\ created_by TEXT NOT NULL REFERENCES local_user(id),
|
||||||
\\
|
\\
|
||||||
\\ uses INTEGER NOT NULL,
|
|
||||||
\\ max_uses INTEGER,
|
\\ max_uses INTEGER,
|
||||||
\\
|
\\
|
||||||
\\ created_at INTEGER NOT NULL,
|
\\ created_at INTEGER NOT NULL,
|
||||||
|
|
|
@ -111,7 +111,6 @@ pub const Invite = struct {
|
||||||
invite_code: []const u8,
|
invite_code: []const u8,
|
||||||
created_by: Ref(LocalUser),
|
created_by: Ref(LocalUser),
|
||||||
|
|
||||||
uses: i64,
|
|
||||||
max_uses: ?i64,
|
max_uses: ?i64,
|
||||||
|
|
||||||
created_at: DateTime,
|
created_at: DateTime,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue