Add args to timeline controller
This commit is contained in:
parent
4e81441a0d
commit
4773a86313
4 changed files with 109 additions and 18 deletions
|
@ -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),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
|
|
|
@ -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},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue