Add args to timeline controller

This commit is contained in:
jaina heartles 2022-11-13 23:00:20 -08:00
parent 4e81441a0d
commit 4773a86313
4 changed files with 109 additions and 18 deletions

View file

@ -57,6 +57,39 @@ pub const Community = services.communities.Community;
pub const CommunityQueryArgs = services.communities.QueryArgs; pub const CommunityQueryArgs = services.communities.QueryArgs;
pub const CommunityQueryResult = services.communities.QueryResult; pub const CommunityQueryResult = services.communities.QueryResult;
pub const NoteQueryArgs = services.notes.QueryArgs;
pub const TimelineArgs = struct {
pub const PageDirection = NoteQueryArgs.PageDirection;
pub const Prev = NoteQueryArgs.Prev;
max_items: usize = 20,
created_before: ?DateTime = null,
created_after: ?DateTime = null,
prev: ?Prev = null,
page_direction: PageDirection = .forward,
fn from(args: NoteQueryArgs) TimelineArgs {
return .{
.max_items = args.max_items,
.created_before = args.created_before,
.created_after = args.created_after,
.prev = args.prev,
.page_direction = args.page_direction,
};
}
};
pub const TimelineResult = struct {
items: []services.notes.Note,
prev_page: TimelineArgs,
next_page: TimelineArgs,
};
pub fn isAdminSetup(db: sql.Db) !bool { pub fn isAdminSetup(db: sql.Db) !bool {
_ = services.communities.adminCommunityId(db) catch |err| switch (err) { _ = services.communities.adminCommunityId(db) catch |err| switch (err) {
error.NotFound => return false, error.NotFound => return false,
@ -352,18 +385,25 @@ fn ApiConn(comptime DbConn: type) type {
return try services.communities.query(self.db, args, self.arena.allocator()); return try services.communities.query(self.db, args, self.arena.allocator());
} }
pub fn globalTimeline(self: *Self) ![]services.notes.Note { pub fn globalTimeline(self: *Self, args: TimelineArgs) !TimelineResult {
const result = try services.notes.query(self.db, .{}, self.arena.allocator()); const all_args = std.mem.zeroInit(NoteQueryArgs, args);
return result.items; const result = try services.notes.query(self.db, all_args, self.arena.allocator());
return TimelineResult{
.items = result.items,
.prev_page = TimelineArgs.from(result.prev_page),
.next_page = TimelineArgs.from(result.next_page),
};
} }
pub fn localTimeline(self: *Self) ![]services.notes.Note { pub fn localTimeline(self: *Self, args: TimelineArgs) !TimelineResult {
const result = try services.notes.query( var all_args = std.mem.zeroInit(NoteQueryArgs, args);
self.db, all_args.community_id = self.community.id;
.{ .community_id = self.community.id }, const result = try services.notes.query(self.db, all_args, self.arena.allocator());
self.arena.allocator(), return TimelineResult{
); .items = result.items,
return result.items; .prev_page = TimelineArgs.from(result.prev_page),
.next_page = TimelineArgs.from(result.next_page),
};
} }
}; };
} }

View file

@ -63,7 +63,7 @@ const max_max_items = 100;
pub const QueryArgs = struct { pub const QueryArgs = struct {
pub const PageDirection = common.PageDirection; pub const PageDirection = common.PageDirection;
pub const Prev = std.meta.Child(std.meta.field(@This(), .prev).field_type); pub const Prev = std.meta.Child(std.meta.fieldInfo(@This(), .prev).field_type);
max_items: usize = 20, max_items: usize = 20,

View file

@ -1,11 +1,27 @@
const std = @import("std");
const api = @import("api");
const query_utils = @import("../query.zig");
pub const global = struct { pub const global = struct {
pub const method = .GET; pub const method = .GET;
pub const path = "/timelines/global"; pub const path = "/timelines/global";
pub fn handler(_: anytype, res: anytype, srv: anytype) !void { pub const Query = api.TimelineArgs;
const results = try srv.globalTimeline();
try res.json(.ok, results); pub fn handler(req: anytype, res: anytype, srv: anytype) !void {
const results = try srv.globalTimeline(req.query);
var link = std.ArrayList(u8).init(req.allocator);
const link_writer = link.writer();
defer link.deinit();
try writeLink(link_writer, srv.community, path, results.next_page, "next");
try link_writer.writeByte(',');
try writeLink(link_writer, srv.community, path, results.prev_page, "prev");
try res.headers.put("Link", link.items);
try res.json(.ok, results.items);
} }
}; };
@ -13,9 +29,45 @@ pub const local = struct {
pub const method = .GET; pub const method = .GET;
pub const path = "/timelines/local"; pub const path = "/timelines/local";
pub fn handler(_: anytype, res: anytype, srv: anytype) !void { pub const Query = api.TimelineArgs;
const results = try srv.localTimeline();
try res.json(.ok, results); pub fn handler(req: anytype, res: anytype, srv: anytype) !void {
const results = try srv.localTimeline(req.query);
var link = std.ArrayList(u8).init(req.allocator);
const link_writer = link.writer();
defer link.deinit();
try writeLink(link_writer, srv.community, path, results.next_page, "next");
try link_writer.writeByte(',');
try writeLink(link_writer, srv.community, path, results.prev_page, "prev");
try res.headers.put("Link", link.items);
try res.json(.ok, results.items);
} }
}; };
// TOOD: unify with communities.zig
fn writeLink(
writer: anytype,
community: api.Community,
path: []const u8,
params: anytype,
rel: []const u8,
) !void {
// TODO: percent-encode
try std.fmt.format(
writer,
"<{s}://{s}/{s}?",
.{ @tagName(community.scheme), community.host, path },
);
try query_utils.formatQuery(params, writer);
try std.fmt.format(
writer,
">; rel=\"{s}\"",
.{rel},
);
}

View file

@ -279,7 +279,6 @@ fn format(comptime prefix: []const u8, comptime name: []const u8, params: anytyp
} }
}, },
.Union => { .Union => {
//inline for (std.meta.tags(T)) |tag| {
inline for (std.meta.fields(T)) |field| { inline for (std.meta.fields(T)) |field| {
const tag = @field(std.meta.Tag(T), field.name); const tag = @field(std.meta.Tag(T), field.name);
const tag_name = field.name; const tag_name = field.name;