X-Git-Url: https://gitweb.ps.run/chirp/blobdiff_plain/159b5e88014eb1084a1a3be64d8b0259b409f74d..d8f54dd8ac187349c1194871a55d4675f28e5a43:/src/main.zig
diff --git a/src/main.zig b/src/main.zig
index 78c7cb0..164606f 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -29,8 +29,11 @@ const User = struct {
id: UserId,
name: Username,
display_name: DisplayName,
+ description: UserDescription,
password_hash: PasswordHash,
+
posts: PostList,
+
following: UserList,
followers: UserList,
@@ -82,6 +85,7 @@ const PostId = enum(u64) { _ };
const Timestamp = i64;
const Username = std.BoundedArray(u8, 32);
const DisplayName = std.BoundedArray(u8, 64);
+const UserDescription = std.BoundedArray(u8, 1024);
const PasswordHash = std.BoundedArray(u8, 128);
const SessionToken = u64;
const CookieValue = std.BoundedArray(u8, 128);
@@ -97,8 +101,8 @@ fn parse_enum(comptime E: type, buf: []const u8, base: u8) !E {
}
// https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding
-fn reencode(text: []const u8) !PostText {
- var result = try PostText.init(0);
+fn reencode(comptime T: type, text: []const u8) !T {
+ var result = try T.init(0);
const len = @min(text.len, 1024); // TODO: PostText length
@@ -107,28 +111,19 @@ fn reencode(text: []const u8) !PostText {
const c = text[idx];
if (c == '+') {
try result.append(' ');
- } else if (c == '%') {
- // special case of ...
- // assume only , no
- if (idx + 6 < text.len and std.mem.eql(u8, text[idx .. idx + 6], "%26%23")) {
- const num_start = idx + 6;
- var num_end = num_start;
- while (num_end < text.len and std.ascii.isDigit(text[num_end])) {
- num_end += 1;
- }
+ } else if (c == '%' and idx + 2 < text.len) {
+ const allow = &[_]u8{ 0x26, 0x23, 0x3b, 0x0a };
- if (num_end + 2 < text.len and
- text[num_end] == '%' and
- text[num_end + 1] == '3' and
- std.ascii.toLower(text[num_end + 2]) == 'b')
- {
- try std.fmt.format(result.writer(), "{s};", .{text[num_start..num_end]});
- idx = num_end + 2;
- continue;
- }
+ const escaped_value = std.fmt.parseUnsigned(u8, text[idx + 1 .. idx + 3], 16) catch continue;
+
+ if (escaped_value == 0x0d) {
+ try std.fmt.format(result.writer(), "
", .{});
+ } else if (std.mem.indexOfScalar(u8, allow, escaped_value) != null) {
+ try std.fmt.format(result.writer(), "{c}", .{escaped_value});
+ } else {
+ try std.fmt.format(result.writer(), "{x};", .{escaped_value});
}
- try std.fmt.format(result.writer(), "{s};", .{text[idx + 1 .. idx + 3]});
idx += 2;
} else {
try result.append(c);
@@ -166,6 +161,9 @@ fn decode(text: []const u8) !std.BoundedArray(u8, 1024) {
}
const Chirp = struct {
+ const PostsPerPage = 10;
+ const UsersPerPage = 10;
+
pub fn hash_password(password: []const u8) !PasswordHash {
var hash_buffer = try PasswordHash.init(128);
@@ -220,6 +218,7 @@ const Chirp = struct {
.id = user_id,
.name = username_array,
.display_name = display_name,
+ .description = try UserDescription.init(0),
.password_hash = try hash_password(password),
.posts = try PostList.init(txn),
.following = try UserList.init(txn),
@@ -269,7 +268,7 @@ const Chirp = struct {
try sessions.del(session_token);
}
- fn append_post(env: lmdb.Env, user_id: UserId, post_list: PostList, parent_id: ?PostId, quote_id: ?PostId, text: []const u8) !void {
+ fn append_post(env: lmdb.Env, user_id: UserId, post_list: PostList, parent_id: ?PostId, quote_id: ?PostId, text: []const u8) !PostId {
var post_id: PostId = undefined;
// TODO: do this in one commit
@@ -283,7 +282,7 @@ const Chirp = struct {
const posts = try Db.posts(txn);
post_id = try db.Prng.gen(posts.dbi, PostId);
- const decoded_text = try reencode(text);
+ const decoded_text = try reencode(PostText, text);
try posts.put(post_id, Post{
.id = post_id,
.parent_id = parent_id,
@@ -315,39 +314,45 @@ const Chirp = struct {
var quotes = try quote_post.quotes.open(txn);
try quotes.append(post_id);
}
+
+ return post_id;
}
fn post(env: lmdb.Env, user_id: UserId, text: []const u8) !void {
- const txn = try env.txn();
-
+ var txn = try env.txn();
const users = try Db.users(txn);
const user = try users.get(user_id);
-
txn.abort();
- try append_post(env, user_id, user.posts, null, null, text);
+ const post_id = try append_post(env, user_id, user.posts, null, null, text);
+ _ = post_id;
}
fn comment(env: lmdb.Env, user_id: UserId, parent_post_id: PostId, text: []const u8) !void {
- const txn = try env.txn();
+ var txn = try env.txn();
+ const users = try Db.users(txn);
+ const user = try users.get(user_id);
const posts = try Db.posts(txn);
const parent_post = try posts.get(parent_post_id);
-
txn.abort();
- try append_post(env, user_id, parent_post.comments, parent_post_id, null, text);
+ const post_id = try append_post(env, user_id, parent_post.comments, parent_post_id, null, text);
+
+ txn = try env.txn();
+ var replies_view = try user.posts.open(txn);
+ try replies_view.append(post_id);
+ try txn.commit();
}
fn quote(env: lmdb.Env, user_id: UserId, quote_post_id: PostId, text: []const u8) !void {
- const txn = try env.txn();
-
+ var txn = try env.txn();
const users = try Db.users(txn);
const user = try users.get(user_id);
-
txn.abort();
- try append_post(env, user_id, user.posts, null, quote_post_id, text);
+ const post_id = try append_post(env, user_id, user.posts, null, quote_post_id, text);
+ _ = post_id;
}
fn vote(env: lmdb.Env, post_id: PostId, user_id: UserId, kind: Vote.Kind) !void {
@@ -434,17 +439,86 @@ const Chirp = struct {
// }}}
// html {{{
-fn html_form(res: *http.Response, comptime fmt_action: []const u8, args_action: anytype, inputs: anytype) !void {
- try res.write("