2022-07-13 03:40:48 +00:00
|
|
|
const std = @import("std");
|
2022-07-13 04:16:33 +00:00
|
|
|
const util = @import("util");
|
2022-09-15 01:12:07 +00:00
|
|
|
const sql = @import("sql");
|
2023-01-03 01:21:08 +00:00
|
|
|
const services = @import("./services.zig");
|
|
|
|
const types = @import("./types.zig");
|
2022-07-13 03:40:48 +00:00
|
|
|
|
2022-10-04 02:41:59 +00:00
|
|
|
const DateTime = util.DateTime;
|
|
|
|
const Uuid = util.Uuid;
|
2022-07-13 03:40:48 +00:00
|
|
|
|
2023-01-03 01:21:08 +00:00
|
|
|
pub usingnamespace types;
|
2023-01-04 19:03:23 +00:00
|
|
|
pub const Account = types.accounts.Account;
|
2023-01-03 01:21:08 +00:00
|
|
|
pub const Actor = types.actors.Actor;
|
2023-01-04 19:03:23 +00:00
|
|
|
pub const Community = types.communities.Community;
|
|
|
|
pub const Invite = types.invites.Invite;
|
|
|
|
pub const Note = types.notes.Note;
|
|
|
|
pub const Token = types.tokens.Token;
|
2022-12-21 15:19:13 +00:00
|
|
|
|
2022-11-19 11:13:05 +00:00
|
|
|
pub const ClusterMeta = struct {
|
|
|
|
community_count: usize,
|
|
|
|
user_count: usize,
|
|
|
|
note_count: usize,
|
|
|
|
};
|
|
|
|
|
2022-10-04 05:41:22 +00:00
|
|
|
pub fn isAdminSetup(db: sql.Db) !bool {
|
2023-01-04 19:03:23 +00:00
|
|
|
const svc = services.Services(sql.Db){ .db = db };
|
|
|
|
_ = svc.getAdminCommunityId() catch |err| switch (err) {
|
2022-09-29 21:52:01 +00:00
|
|
|
error.NotFound => return false,
|
2023-01-04 19:03:23 +00:00
|
|
|
else => |e| return e,
|
2022-09-29 21:52:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-04 05:41:22 +00:00
|
|
|
pub fn setupAdmin(db: sql.Db, origin: []const u8, username: []const u8, password: []const u8, allocator: std.mem.Allocator) anyerror!void {
|
2023-01-03 01:17:42 +00:00
|
|
|
const svc = @import("./services.zig").Services(sql.Db){ .db = db };
|
|
|
|
const tx = try svc.beginTx();
|
|
|
|
errdefer tx.rollbackTx();
|
2022-09-29 21:52:01 +00:00
|
|
|
var arena = std.heap.ArenaAllocator.init(allocator);
|
|
|
|
defer arena.deinit();
|
|
|
|
|
2023-01-03 01:17:42 +00:00
|
|
|
const community_id = try tx.createCommunity(
|
|
|
|
arena.allocator(),
|
2022-09-29 21:52:01 +00:00
|
|
|
origin,
|
|
|
|
.{ .name = "Cluster Admin", .kind = .admin },
|
|
|
|
);
|
|
|
|
|
2023-01-03 01:17:42 +00:00
|
|
|
const user = try @import("./methods/auth.zig").createLocalAccount(
|
|
|
|
arena.allocator(),
|
2023-01-02 01:32:17 +00:00
|
|
|
tx,
|
|
|
|
username,
|
|
|
|
password,
|
|
|
|
community_id,
|
|
|
|
.{ .role = .admin },
|
|
|
|
);
|
2022-09-29 21:52:01 +00:00
|
|
|
|
2023-01-03 01:17:42 +00:00
|
|
|
try tx.transferCommunityOwnership(community_id, user);
|
2022-09-29 21:52:01 +00:00
|
|
|
|
2023-01-03 01:17:42 +00:00
|
|
|
try tx.commitTx();
|
2022-09-29 21:52:01 +00:00
|
|
|
|
|
|
|
std.log.info(
|
|
|
|
"Created admin user {s} (id {}) with cluster admin origin {s} (id {})",
|
2022-10-04 02:41:59 +00:00
|
|
|
.{ username, user, origin, community_id },
|
2022-09-29 21:52:01 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-26 02:07:05 +00:00
|
|
|
pub const ApiSource = struct {
|
2022-10-13 06:19:59 +00:00
|
|
|
db_conn_pool: *sql.ConnPool,
|
2022-07-15 00:58:08 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub const Conn = ApiConn(sql.Db, method_impl);
|
2022-07-26 02:07:05 +00:00
|
|
|
|
2022-09-05 08:52:49 +00:00
|
|
|
const root_username = "root";
|
|
|
|
|
2022-10-13 06:19:59 +00:00
|
|
|
pub fn init(pool: *sql.ConnPool) !ApiSource {
|
2022-09-29 21:52:01 +00:00
|
|
|
return ApiSource{
|
2022-10-13 06:19:59 +00:00
|
|
|
.db_conn_pool = pool,
|
2022-09-05 08:52:49 +00:00
|
|
|
};
|
2022-09-07 23:14:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn connectUnauthorized(self: *ApiSource, host: []const u8, alloc: std.mem.Allocator) !Conn {
|
2022-10-13 06:19:59 +00:00
|
|
|
const db = try self.db_conn_pool.acquire();
|
2022-10-16 12:48:12 +00:00
|
|
|
errdefer db.releaseConnection();
|
2023-01-04 19:03:23 +00:00
|
|
|
var conn = Conn{
|
2022-10-04 05:41:22 +00:00
|
|
|
.db = db,
|
2023-01-01 23:58:17 +00:00
|
|
|
.context = .{
|
2023-01-04 19:03:23 +00:00
|
|
|
.community = undefined,
|
2023-01-01 23:58:17 +00:00
|
|
|
},
|
2022-11-20 23:42:34 +00:00
|
|
|
.allocator = alloc,
|
2022-07-26 02:07:05 +00:00
|
|
|
};
|
2023-01-04 19:03:23 +00:00
|
|
|
|
|
|
|
conn.context.community = try conn.getServices().getCommunityByHost(alloc, host);
|
|
|
|
|
|
|
|
return conn;
|
2022-07-26 02:07:05 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 08:52:49 +00:00
|
|
|
pub fn connectToken(self: *ApiSource, host: []const u8, token: []const u8, alloc: std.mem.Allocator) !Conn {
|
2023-01-02 01:32:17 +00:00
|
|
|
var conn = try self.connectUnauthorized(host, alloc);
|
|
|
|
errdefer conn.close();
|
2023-01-03 01:17:42 +00:00
|
|
|
conn.context.token_info = try @import("./methods/auth.zig").verifyToken(alloc, conn.context, conn.getServices(), token);
|
2023-01-02 01:32:17 +00:00
|
|
|
return conn;
|
2022-07-13 03:40:48 +00:00
|
|
|
}
|
2022-07-26 02:07:05 +00:00
|
|
|
};
|
2022-07-13 03:40:48 +00:00
|
|
|
|
2023-01-01 23:58:17 +00:00
|
|
|
pub const ApiContext = struct {
|
|
|
|
token_info: ?Token.Info = null,
|
|
|
|
community: Community,
|
|
|
|
|
|
|
|
pub fn userId(self: ApiContext) ?Uuid {
|
2023-01-04 19:03:23 +00:00
|
|
|
if (self.token_info) |t| return t.account_id else return null;
|
2023-01-01 23:58:17 +00:00
|
|
|
}
|
2023-01-02 20:38:42 +00:00
|
|
|
|
|
|
|
pub fn isAdmin(self: ApiContext) bool {
|
|
|
|
return self.userId() != null and self.community.kind == .admin;
|
|
|
|
}
|
2023-01-01 23:58:17 +00:00
|
|
|
};
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
const method_impl = struct {
|
|
|
|
const actors = @import("./methods/actors.zig");
|
2023-01-03 01:21:08 +00:00
|
|
|
const auth = @import("./methods/auth.zig");
|
2023-01-04 19:03:23 +00:00
|
|
|
const communities = @import("./methods/communities.zig");
|
|
|
|
const drive = @import("./methods/drive.zig");
|
|
|
|
const follows = @import("./methods/follows.zig");
|
|
|
|
const invites = @import("./methods/invites.zig");
|
|
|
|
const notes = @import("./methods/notes.zig");
|
2023-01-03 01:21:08 +00:00
|
|
|
const timelines = @import("./methods/timelines.zig");
|
|
|
|
};
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
fn ApiConn(comptime DbConn: type, comptime methods: anytype) type {
|
2022-07-26 02:07:05 +00:00
|
|
|
return struct {
|
|
|
|
const Self = @This();
|
2023-01-03 01:21:08 +00:00
|
|
|
const Services = @import("./services.zig").Services(DbConn);
|
2022-07-18 07:37:10 +00:00
|
|
|
|
2022-07-26 02:07:05 +00:00
|
|
|
db: DbConn,
|
2023-01-01 23:58:17 +00:00
|
|
|
context: ApiContext,
|
2022-11-20 23:42:34 +00:00
|
|
|
allocator: std.mem.Allocator,
|
2022-07-18 06:11:42 +00:00
|
|
|
|
2022-07-26 02:07:05 +00:00
|
|
|
pub fn close(self: *Self) void {
|
2023-01-01 23:58:17 +00:00
|
|
|
util.deepFree(self.allocator, self.context.community);
|
|
|
|
if (self.context.token_info) |info| util.deepFree(self.allocator, info);
|
2022-10-13 06:19:59 +00:00
|
|
|
self.db.releaseConnection();
|
2022-07-26 02:07:05 +00:00
|
|
|
}
|
2022-07-18 06:11:42 +00:00
|
|
|
|
2023-01-03 01:21:08 +00:00
|
|
|
fn getServices(self: *Self) Services {
|
|
|
|
return Services{ .db = self.db };
|
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn createCommunity(self: *Self, origin: []const u8, name: ?[]const u8) !Uuid {
|
|
|
|
return try methods.communities.create(
|
2022-11-20 23:42:34 +00:00
|
|
|
self.allocator,
|
2023-01-04 19:03:23 +00:00
|
|
|
self.context,
|
|
|
|
self.getServices(),
|
|
|
|
origin,
|
|
|
|
name,
|
2022-12-12 03:52:11 +00:00
|
|
|
);
|
2022-07-27 05:02:09 +00:00
|
|
|
}
|
2022-09-08 06:56:29 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn createInvite(self: *Self, options: types.invites.CreateOptions) !Uuid {
|
|
|
|
return methods.invites.create(self.allocator, self.context, self.getServices(), options);
|
2022-12-10 06:38:04 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 20:38:42 +00:00
|
|
|
pub fn login(self: *Self, username: []const u8, password: []const u8) !Token {
|
2023-01-03 01:17:42 +00:00
|
|
|
return methods.auth.login(self.allocator, self.context, self.getServices(), username, password);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn register(
|
|
|
|
self: *Self,
|
|
|
|
username: []const u8,
|
|
|
|
password: []const u8,
|
2023-01-04 19:03:23 +00:00
|
|
|
opt: types.auth.RegistrationOptions,
|
|
|
|
) !Uuid {
|
2023-01-03 01:17:42 +00:00
|
|
|
return methods.auth.register(self.allocator, self.context, self.getServices(), username, password, opt);
|
2023-01-02 20:38:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn getActor(self: *Self, user_id: Uuid) !Actor {
|
|
|
|
return methods.actors.get(self.allocator, self.context, self.getServices(), user_id);
|
2022-09-08 07:52:23 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn createNote(self: *Self, content: []const u8) !Uuid {
|
|
|
|
return methods.notes.create(self.allocator, self.context, self.getServices(), content);
|
2022-09-08 07:52:23 +00:00
|
|
|
}
|
|
|
|
|
2022-12-21 15:19:13 +00:00
|
|
|
pub fn getNote(self: *Self, note_id: Uuid) !Note {
|
2023-01-04 19:03:23 +00:00
|
|
|
return methods.notes.get(self.allocator, self.context, self.getServices(), note_id);
|
2022-09-08 07:52:23 +00:00
|
|
|
}
|
2022-09-10 04:02:51 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn queryCommunities(self: *Self, args: types.communities.QueryArgs) !types.communities.QueryResult {
|
|
|
|
return methods.communities.query(self.allocator, self.context, self.getServices(), args);
|
2022-09-10 04:02:51 +00:00
|
|
|
}
|
2022-11-12 12:39:49 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn globalTimeline(self: *Self, args: types.timelines.TimelineArgs) !methods.timelines.TimelineResult {
|
2023-01-03 01:21:08 +00:00
|
|
|
return methods.timelines.globalTimeline(self.allocator, self.context, self.getServices(), args);
|
2022-11-12 12:39:49 +00:00
|
|
|
}
|
2022-11-12 13:23:55 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn localTimeline(self: *Self, args: types.timelines.TimelineArgs) !methods.timelines.TimelineResult {
|
2023-01-03 01:21:08 +00:00
|
|
|
return methods.timelines.localTimeline(self.allocator, self.context, self.getServices(), args);
|
2022-11-12 13:23:55 +00:00
|
|
|
}
|
2022-11-14 08:14:29 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn homeTimeline(self: *Self, args: types.timelines.TimelineArgs) !methods.timelines.TimelineResult {
|
2023-01-03 01:21:08 +00:00
|
|
|
return methods.timelines.homeTimeline(self.allocator, self.context, self.getServices(), args);
|
2022-11-14 23:00:01 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn queryFollowers(self: *Self, user_id: Uuid, args: types.follows.FollowerQueryArgs) !types.follows.FollowerQueryResult {
|
|
|
|
return methods.follows.queryFollowers(self.allocator, self.context, self.getServices(), user_id, args);
|
2022-11-14 08:14:29 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn queryFollowing(self: *Self, user_id: Uuid, args: types.follows.FollowingQueryArgs) !types.follows.FollowingQueryResult {
|
|
|
|
return methods.follows.queryFollowing(self.allocator, self.context, self.getServices(), user_id, args);
|
2022-11-14 08:14:29 +00:00
|
|
|
}
|
2022-11-14 09:03:11 +00:00
|
|
|
|
|
|
|
pub fn follow(self: *Self, followee: Uuid) !void {
|
2023-01-04 19:03:23 +00:00
|
|
|
try methods.follows.follow(self.allocator, self.context, self.getServices(), followee);
|
2022-11-14 09:03:11 +00:00
|
|
|
}
|
2022-11-19 11:13:05 +00:00
|
|
|
|
2022-11-19 11:33:35 +00:00
|
|
|
pub fn unfollow(self: *Self, followee: Uuid) !void {
|
2023-01-04 19:03:23 +00:00
|
|
|
try methods.follows.unfollow(self.allocator, self.context, self.getServices(), followee);
|
2022-11-19 11:33:35 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 11:13:05 +00:00
|
|
|
pub fn getClusterMeta(self: *Self) !ClusterMeta {
|
|
|
|
return try self.db.queryRow(
|
|
|
|
ClusterMeta,
|
|
|
|
\\SELECT
|
|
|
|
\\ COUNT(DISTINCT note.id) AS note_count,
|
|
|
|
\\ COUNT(DISTINCT actor.id) AS user_count,
|
|
|
|
\\ COUNT(DISTINCT community.id) AS community_count
|
|
|
|
\\FROM note, actor, community
|
|
|
|
\\WHERE
|
|
|
|
\\ actor.community_id = community.id AND
|
|
|
|
\\ community.kind != 'admin'
|
|
|
|
,
|
|
|
|
.{},
|
2022-11-20 23:42:34 +00:00
|
|
|
self.allocator,
|
2022-11-19 11:13:05 +00:00
|
|
|
);
|
|
|
|
}
|
2022-12-03 07:44:27 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn driveUpload(self: *Self, meta: types.drive.UploadArgs, body: []const u8) !Uuid {
|
|
|
|
return try methods.drive.upload(self.allocator, self.context, self.getServices(), meta, body);
|
2022-12-03 15:09:29 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn driveMkdir(self: *Self, parent_path: []const u8, name: []const u8) !Uuid {
|
|
|
|
return try methods.drive.mkdir(self.allocator, self.context, self.getServices(), parent_path, name);
|
2022-12-06 09:48:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn driveDelete(self: *Self, path: []const u8) !void {
|
2023-01-04 19:03:23 +00:00
|
|
|
return try methods.drive.delete(self.allocator, self.context, self.getServices(), path);
|
2022-12-06 09:48:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn driveMove(self: *Self, src: []const u8, dest: []const u8) !void {
|
|
|
|
return try methods.drive.move(self.allocator, self.context, self.getServices(), src, dest);
|
2022-12-06 09:48:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn driveGet(self: *Self, path: []const u8) !types.drive.DriveEntry {
|
|
|
|
return try methods.drive.get(self.allocator, self.context, self.getServices(), path);
|
2022-12-06 09:48:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn driveUpdate(self: *Self, path: []const u8, meta: types.files.UpdateArgs) !void {
|
|
|
|
return try methods.drive.update(self.allocator, self.context, self.getServices(), path, meta);
|
2022-12-03 07:44:27 +00:00
|
|
|
}
|
2022-12-06 10:53:41 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn fileDereference(self: *Self, id: Uuid) !types.files.DerefResult {
|
|
|
|
return try methods.drive.dereference(self.allocator, self.context, self.getServices(), id);
|
2022-12-06 10:53:41 +00:00
|
|
|
}
|
2022-12-07 09:59:46 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn updateUserProfile(self: *Self, id: Uuid, data: types.actors.ProfileUpdateArgs) !void {
|
|
|
|
try methods.actors.updateProfile(self.allocator, self.context, self.getServices(), id, data);
|
2022-12-07 09:59:46 +00:00
|
|
|
}
|
2022-12-10 09:41:56 +00:00
|
|
|
|
2023-01-04 19:03:23 +00:00
|
|
|
pub fn validateInvite(self: *Self, code: []const u8) !Invite {
|
|
|
|
return try methods.invites.getByCode(self.allocator, self.context, self.getServices(), code);
|
2022-12-10 09:41:56 +00:00
|
|
|
}
|
2022-07-26 02:07:05 +00:00
|
|
|
};
|
|
|
|
}
|