Allow registration with invite
This commit is contained in:
parent
01ef4427f5
commit
76f2b818ab
3 changed files with 21 additions and 5 deletions
|
@ -77,6 +77,7 @@ pub const RegistrationInfo = struct {
|
|||
username: []const u8,
|
||||
password: []const u8,
|
||||
email: ?[]const u8,
|
||||
invite_code: ?[]const u8,
|
||||
};
|
||||
|
||||
pub const LoginResult = struct {
|
||||
|
@ -211,7 +212,7 @@ fn ApiConn(comptime DbConn: type) type {
|
|||
pub fn register(self: *Self, info: RegistrationInfo) !models.Actor {
|
||||
const actor_id = Uuid.randV4(prng.random());
|
||||
const user_id = Uuid.randV4(prng.random());
|
||||
// TODO: transaction?
|
||||
// TODO: lock for transaction
|
||||
|
||||
if (try self.db.existsWhereEq(models.LocalUser, .username, info.username)) {
|
||||
return error.UsernameUnavailable;
|
||||
|
@ -221,10 +222,20 @@ fn ApiConn(comptime DbConn: type) type {
|
|||
return error.InconsistentDb;
|
||||
}
|
||||
|
||||
const now = DateTime.now();
|
||||
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 uses_left = if (invite.max_uses) |max_uses| invite.uses < max_uses else true;
|
||||
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;
|
||||
// TODO: increment uses
|
||||
break :blk invite.id;
|
||||
} else null;
|
||||
|
||||
// use internal alloc because necessary buffer is *big*
|
||||
var buf: [pw_hash_buf_size]u8 = undefined;
|
||||
const hash = try PwHash.strHash(info.password, .{ .allocator = self.internal_alloc, .params = pw_hash_params, .encoding = pw_hash_encoding }, &buf);
|
||||
const now = DateTime.now();
|
||||
|
||||
const actor = models.Actor{
|
||||
.id = actor_id,
|
||||
|
@ -236,6 +247,7 @@ fn ApiConn(comptime DbConn: type) type {
|
|||
.actor_id = actor_id,
|
||||
.username = info.username,
|
||||
.email = info.email,
|
||||
.invite_id = invite_id,
|
||||
.hashed_password = hash,
|
||||
.password_changed_at = now,
|
||||
.created_at = now,
|
||||
|
@ -243,7 +255,6 @@ fn ApiConn(comptime DbConn: type) type {
|
|||
try self.db.insert(models.Actor, actor);
|
||||
try self.db.insert(models.LocalUser, user);
|
||||
|
||||
// TODO: return token instead
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
|
|
@ -151,14 +151,16 @@ pub const Database = struct {
|
|||
\\CREATE TABLE IF NOT EXISTS
|
||||
\\local_user(
|
||||
\\ id TEXT NOT NULL,
|
||||
\\ actor_id TEXT,
|
||||
\\
|
||||
\\ username TEXT NOT NULL,
|
||||
\\ actor_id TEXT,
|
||||
\\ email TEXT,
|
||||
\\ invite_id TEXT,
|
||||
\\
|
||||
\\ hashed_password TEXT NOT NULL,
|
||||
\\ password_changed_at INTEGER NOT NULL,
|
||||
\\
|
||||
\\ created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
\\ password_changed_at INTEGER NOT NULL,
|
||||
\\
|
||||
\\ UNIQUE(actor_id),
|
||||
\\ FOREIGN KEY(actor_id) REFERENCES actor(id),
|
||||
|
@ -219,6 +221,8 @@ pub const Database = struct {
|
|||
\\ created_at INTEGER NOT NULL,
|
||||
\\ expires_at INTEGER
|
||||
\\) STRICT;
|
||||
,
|
||||
\\ALTER TABLE local_user ADD COLUMN invite_id TEXT REFERENCES invite(id);
|
||||
};
|
||||
|
||||
pub fn init() !Database {
|
||||
|
|
|
@ -77,6 +77,7 @@ pub const LocalUser = struct {
|
|||
|
||||
username: []const u8,
|
||||
email: ?[]const u8,
|
||||
invite_id: ?Ref(Invite),
|
||||
|
||||
hashed_password: []const u8, // encoded in PHC format, with salt
|
||||
password_changed_at: DateTime,
|
||||
|
|
Loading…
Reference in a new issue