119 lines
2.8 KiB
Zig
119 lines
2.8 KiB
Zig
const std = @import("std");
|
|
const util = @import("util");
|
|
const auth = @import("./auth.zig");
|
|
|
|
const Uuid = util.Uuid;
|
|
const DateTime = util.DateTime;
|
|
const getRandom = @import("../api.zig").getRandom;
|
|
|
|
const UserAuthInfo = struct {
|
|
password: []const u8,
|
|
email: []const u8,
|
|
invite_used: ?Uuid,
|
|
};
|
|
|
|
pub const CreateError = error{
|
|
UsernameTaken,
|
|
DbError,
|
|
};
|
|
|
|
const DbUser = struct {
|
|
id: Uuid,
|
|
|
|
username: []const u8,
|
|
community_id: Uuid,
|
|
};
|
|
|
|
const DbLocalUser = struct {
|
|
user_id: Uuid,
|
|
|
|
invite_id: ?Uuid,
|
|
email: ?[]const u8,
|
|
};
|
|
|
|
pub const Role = enum {
|
|
user,
|
|
admin,
|
|
};
|
|
|
|
pub const CreateOptions = struct {
|
|
invite_id: ?Uuid = null,
|
|
email: ?[]const u8 = null,
|
|
role: Role = .user,
|
|
};
|
|
|
|
fn lookupByUsernameInternal(db: anytype, username: []const u8, community_id: Uuid) CreateError!?Uuid {
|
|
return if (db.queryRow(
|
|
std.meta.Tuple(&.{Uuid}),
|
|
"SELECT user.id FROM user WHERE community_id = $1 AND username = $2",
|
|
.{ community_id, username },
|
|
null,
|
|
) catch return error.DbError) |result|
|
|
result[0]
|
|
else
|
|
null;
|
|
}
|
|
|
|
pub fn lookupByUsername(db: anytype, username: []const u8, community_id: Uuid) CreateError!Uuid {
|
|
return (lookupByUsernameInternal(db, username, community_id) catch return error.DbError) orelse error.NotFound;
|
|
}
|
|
|
|
pub fn create(
|
|
db: anytype,
|
|
username: []const u8,
|
|
password: []const u8,
|
|
community_id: Uuid,
|
|
options: CreateOptions,
|
|
password_alloc: std.mem.Allocator,
|
|
) CreateError!Uuid {
|
|
const id = Uuid.randV4(getRandom());
|
|
if ((try lookupByUsernameInternal(db, username, community_id)) != null) {
|
|
return error.UsernameTaken;
|
|
}
|
|
|
|
db.insert("user", .{
|
|
.id = id,
|
|
.username = username,
|
|
.community_id = community_id,
|
|
}) catch return error.DbError;
|
|
try auth.passwords.create(db, id, password, password_alloc);
|
|
db.insert("local_user", .{
|
|
.user_id = id,
|
|
.invite_id = options.invite_id,
|
|
.email = options.email,
|
|
}) catch return error.DbError;
|
|
|
|
return id;
|
|
}
|
|
|
|
pub const User = struct {
|
|
id: Uuid,
|
|
|
|
username: []const u8,
|
|
host: []const u8,
|
|
|
|
community_id: Uuid,
|
|
|
|
created_at: DateTime,
|
|
};
|
|
|
|
pub fn get(db: anytype, id: Uuid, alloc: std.mem.Allocator) !User {
|
|
const result = (try db.queryRow(
|
|
std.meta.Tuple(&.{ []const u8, []const u8, Uuid, DateTime }),
|
|
\\SELECT user.username, community.host, community.id, user.created_at
|
|
\\FROM user JOIN community ON user.community_id = community.id
|
|
\\WHERE user.id = $1
|
|
\\LIMIT 1
|
|
,
|
|
.{id},
|
|
alloc,
|
|
)) orelse return error.NotFound;
|
|
|
|
return User{
|
|
.id = id,
|
|
.username = result[0],
|
|
.host = result[1],
|
|
.community_id = result[2],
|
|
.created_at = result[3],
|
|
};
|
|
}
|