| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- using Statum;
- using Invercargill;
- using Invercargill.DataStructures;
- namespace Example {
- /**
- * `POST /_statum/action/{guid}` — logs in: reads the submitted name, builds a
- * session `auth` slot from typed models (public + private), embedding a
- * `logout` action reference, and redirects home.
- */
- public class LoginAction : StatumAction {
- public override async DirectiveBuilder handle() throws GLib.Error {
- var name = "guest";
- if (request.form != null) {
- var submitted = request.form.get_field("name");
- if (submitted != null && ((!)submitted).length > 0) {
- name = (!)submitted;
- }
- }
- var is_admin = name == "admin";
- var pub = new AuthPublic();
- pub.name = name;
- pub.role = is_admin ? "admin" : "member";
- pub.logout = action_registry.author<LogoutAction>();
- pub.update_announcement = action_registry.author<UpdateAnnouncementAction>();
- var priv = new AuthPrivate();
- priv.is_admin = is_admin;
- return directives()
- .set_private_typed<AuthPublic, AuthPrivate>("auth", Scope.SESSION, pub, priv)
- .navigate("/");
- }
- }
- /**
- * `POST /_statum/action/{guid}` — logs out: clears the held `auth` slot and
- * redirects home.
- */
- public class LogoutAction : StatumAction {
- public override async DirectiveBuilder handle() throws GLib.Error {
- HeldSlot auth;
- if (request.held.try_get("auth", out auth)) {
- yield state_service.clear_slot(auth.key);
- return directives().clear(auth.key).navigate("/");
- }
- return directives().navigate("/");
- }
- }
- /**
- * `POST /_statum/action/{guid}` — bumps the counter by the typed private
- * `delta`, using the typed {@link DirectiveBuilder.update_held} so the
- * `bump` action reference is preserved automatically across the update.
- *
- * Actions are instantiated by GType (no generic type argument), so
- * `private_type` is overridden to name the private model — otherwise
- * `typeof(CounterPrivate)` erodes to `void` and {@link request_private}
- * yields `null`.
- */
- public class BumpCounterAction : TypedStatumAction<CounterPrivate> {
- protected override Type private_type { get { return typeof(CounterPrivate); } }
- public override async DirectiveBuilder handle() throws GLib.Error {
- var delta = request_private != null ? ((!)request_private).delta : 1;
- return directives().update_held<CounterPublic>("counter", c => c.value += delta);
- }
- }
- /**
- * `POST /_statum/action/{guid}` — updates the global announcement from the
- * dashboard. Reads the `text` form field, updates the global slot (which
- * pushes to all subscribed clients via SSE), and returns to the dashboard.
- */
- public class UpdateAnnouncementAction : StatumAction {
- public override async DirectiveBuilder handle() throws GLib.Error {
- var text = "Updated";
- if (request.form != null) {
- var submitted = request.form.get_field("text");
- if (submitted != null && ((!)submitted).length > 0) {
- text = (!)submitted;
- }
- }
- yield state_service.update_global_typed<AnnouncementPublic>("announcement", a => {
- a.text = text;
- });
- yield topic_registry.trigger("announcement:latest");
- return directives().notify("info", "Announcement updated").navigate("/dashboard");
- }
- }
- }
|