From 1e31b71afd1ead4644e99df6838a55481176e09a Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Sun, 23 Nov 2025 16:41:43 +0100 Subject: add fonts and create-user endpoint --- README.md | 2 +- src/routes/api/auth/create-user.zig | 29 +++++++++++++++++++++++++++++ src/routes/api/auth/root.zig | 1 + src/routes/handler-info.zig | 10 +++++++++- src/server.zig | 20 +++++++++++--------- static/fonts/noto-sans/default.ttf | Bin 0 -> 2044548 bytes static/fonts/noto-sans/italic.ttf | Bin 0 -> 2300468 bytes static/fonts/pacifico/regular.ttf | Bin 0 -> 315408 bytes static/index.css | 16 ++++++++++++++++ static/index.html | 3 --- static/index.js | 6 ++++-- static/manifest.json | 2 +- static/pages/settings/index.js | 10 ++++++---- static/service-worker/index.js | 21 +++++++++++++++++++++ static/service-worker/worker.js | 18 ++++++++++++++++++ 15 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 src/routes/api/auth/create-user.zig create mode 100644 static/fonts/noto-sans/default.ttf create mode 100644 static/fonts/noto-sans/italic.ttf create mode 100644 static/fonts/pacifico/regular.ttf create mode 100644 static/service-worker/index.js create mode 100644 static/service-worker/worker.js diff --git a/README.md b/README.md index db6b884..de30e9d 100644 --- a/README.md +++ b/README.md @@ -13,5 +13,5 @@ ### Backend - [x] Not all files are delivered. -- [ ] **Removing file makes date ordering wrong**. +- [X] **Removing file makes date ordering wrong**. - [ ] Cache shuffle data in backend and drop them when next day starts. diff --git a/src/routes/api/auth/create-user.zig b/src/routes/api/auth/create-user.zig new file mode 100644 index 0000000..6bd9a82 --- /dev/null +++ b/src/routes/api/auth/create-user.zig @@ -0,0 +1,29 @@ +const std = @import("std"); + +const memora = @import("memora"); +const Context = memora.Context; +const Storage = memora.Storage; + +pub const access = .admins; + +pub const Body = struct { + name: []const u8, + full_name: []const u8, + birthday: []const u8, + password: []const u8, +}; + +pub fn post(ctx: *Context, body: Body) anyerror!void { + var user = try Storage.User.new( + ctx.storage, + body.name, + body.full_name, + body.birthday, + body.password, + false, + ctx.storage.allocator, + ); + defer user.deinit(); + + try user.sync(); +} diff --git a/src/routes/api/auth/root.zig b/src/routes/api/auth/root.zig index 5f45891..fa93c92 100644 --- a/src/routes/api/auth/root.zig +++ b/src/routes/api/auth/root.zig @@ -2,3 +2,4 @@ const HandlerInfo = @import("../../handler-info.zig"); pub const login: HandlerInfo = .from_type(@import("login.zig")); pub const @"first-login": HandlerInfo = .from_type(@import("first-login.zig")); +pub const @"create-user": HandlerInfo = .from_type(@import("create-user.zig")); diff --git a/src/routes/handler-info.zig b/src/routes/handler-info.zig index 5183628..9e10bd5 100644 --- a/src/routes/handler-info.zig +++ b/src/routes/handler-info.zig @@ -122,6 +122,11 @@ pub fn handle( .value = context.response.headers.content_type }); + try headers.append(allocator, .{ + .name = "Service-Worker-Allowed", + .value = "/", + }); + if (context.response.headers.fingerprint) |auth_token| { var value = std.Io.Writer.Allocating.init(arena.allocator()); @@ -176,7 +181,10 @@ fn HandlerWrapper(T: type, name: []const u8) type { ctx.allocator, writer.written(), .{}, - ) catch return error.BadRequest; + ) catch |err| { + log.warn("failed to parse JSON {}", .{err}); + return error.BadRequest; + }; break :args .{ ctx, body }; } else { @compileError("invalid amount of arguments for request function"); diff --git a/src/server.zig b/src/server.zig index 184af92..5a9be74 100644 --- a/src/server.zig +++ b/src/server.zig @@ -52,16 +52,18 @@ fn handle_connection( var writer = connection.stream.writer(&write_buf); var http_server = std.http.Server.init(reader.interface(), &writer.interface); - var request = http_server.receiveHead() catch return; - log.info("{s} {s}", .{ - std.enums.tagName(std.http.Method, request.head.method) orelse "", - request.head.target, - }); + while (true) { + var request = http_server.receiveHead() catch return; + log.info("{s} {s}", .{ + std.enums.tagName(std.http.Method, request.head.method) orelse "", + request.head.target, + }); - const handler_info = routes.get(request.head.target); - handler_info.handle(&request, &self.storage, allocator) catch |err| { - std.log.err("{}", .{err}); - }; + const handler_info = routes.get(request.head.target); + handler_info.handle(&request, &self.storage, allocator) catch |err| { + std.log.err("{}", .{err}); + }; + } } pub fn deinit(self: *Self) void { diff --git a/static/fonts/noto-sans/default.ttf b/static/fonts/noto-sans/default.ttf new file mode 100644 index 0000000..9530d84 Binary files /dev/null and b/static/fonts/noto-sans/default.ttf differ diff --git a/static/fonts/noto-sans/italic.ttf b/static/fonts/noto-sans/italic.ttf new file mode 100644 index 0000000..6245ba0 Binary files /dev/null and b/static/fonts/noto-sans/italic.ttf differ diff --git a/static/fonts/pacifico/regular.ttf b/static/fonts/pacifico/regular.ttf new file mode 100644 index 0000000..e7def95 Binary files /dev/null and b/static/fonts/pacifico/regular.ttf differ diff --git a/static/index.css b/static/index.css index 67c1407..d5d74cd 100644 --- a/static/index.css +++ b/static/index.css @@ -52,3 +52,19 @@ input { width: 100%; height: 100%; } + +@font-face { + font-family: Pacifico; + src: url(/fonts/pacifico/regular.ttf); +} + +@font-face { + font-family: "Noto Sans"; + src: url(/fonts/noto-sans/default.ttf); +} + +@font-face { + font-family: "Noto Sans"; + font-style: italic + src: url(/fonts/noto-sans/italic.ttf); +} diff --git a/static/index.html b/static/index.html index c69eb16..b3f609d 100644 --- a/static/index.html +++ b/static/index.html @@ -11,9 +11,6 @@ Memora - - - diff --git a/static/index.js b/static/index.js index d5d5c60..28c6228 100644 --- a/static/index.js +++ b/static/index.js @@ -1,8 +1,9 @@ import * as sfw from 'sfw'; - import * as api from './api/index.js'; - import { literal as m } from './month.js'; +import * as service_worker from './service-worker/index.js'; + +//service_worker.register(); import LoginView from './pages/login/index.js'; import MainView from './pages/main/index.js'; @@ -60,6 +61,7 @@ const settings = SettingsView.new({ onlogout: () => { login.show(); main.active_view = image_viewer; + settings.profile = null; }, }); diff --git a/static/manifest.json b/static/manifest.json index ae569c2..e91b5dc 100644 --- a/static/manifest.json +++ b/static/manifest.json @@ -12,6 +12,6 @@ "sizes": "192x192" } ], - "start_url": "https://debug.dom0.nathanreiner.xyz", + "start_url": ".", "display": "standalone" } diff --git a/static/pages/settings/index.js b/static/pages/settings/index.js index cc985a5..36c1d09 100644 --- a/static/pages/settings/index.js +++ b/static/pages/settings/index.js @@ -87,11 +87,13 @@ export default class SettingsView extends sfw.element.Container { set profile(profile) { this.#profile = profile; - this.#profile_image.src = `/api/profile/image/load/${profile.name}`; - this.#profile_image.onerror = () => this.#profile_image.removeAttribute('src'); + if (this.#profile) { + this.#profile_image.src = `/api/profile/image/load/${profile.name}`; + this.#profile_image.onerror = () => this.#profile_image.removeAttribute('src'); - this.#name.value = profile.full_name; - this.#birthday.value = profile.birthday; + this.#name.value = profile.full_name; + this.#birthday.value = profile.birthday; + } } get profile() { diff --git a/static/service-worker/index.js b/static/service-worker/index.js new file mode 100644 index 0000000..cff4b95 --- /dev/null +++ b/static/service-worker/index.js @@ -0,0 +1,21 @@ +export const register = async () => { + if (!'serviceWorker' in navigator) { + console.warn('service worker not supported by browser'); + return; + } + + try { + const registration = await navigator.serviceWorker.register("/service-worker/worker.js", { + scope: "/", + }); + if (registration.installing) { + console.log("Service worker installing"); + } else if (registration.waiting) { + console.log("Service worker installed"); + } else if (registration.active) { + console.log("Service worker active"); + } + } catch (error) { + console.error(`Registration failed with ${error}`); + } +} diff --git a/static/service-worker/worker.js b/static/service-worker/worker.js new file mode 100644 index 0000000..ad5a374 --- /dev/null +++ b/static/service-worker/worker.js @@ -0,0 +1,18 @@ +const putInCache = async (request, response) => { + const cache = await caches.open("v1"); + await cache.put(request, response); +}; + +const cacheFirst = async (request, event) => { + const responseFromCache = await caches.match(request); + if (responseFromCache) { + return responseFromCache; + } + const responseFromNetwork = await fetch(request); + event.waitUntil(putInCache(request, responseFromNetwork.clone())); + return responseFromNetwork; +}; + +self.addEventListener("fetch", (event) => { + event.respondWith(cacheFirst(event.request, event)); +}); -- cgit v1.2.3-70-g09d2