| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- using Invercargill;
- using Invercargill.DataStructures;
- using Spry;
- using Spry.Authentication;
- using Statum;
- namespace ClankerSaddle {
- /** One row of the users table, with its row actions. */
- public class ManagedUserRowView : Object {
- public int64 id { get; set; }
- public string username { get; set; default = ""; }
- public string email { get; set; default = ""; }
- public string forename { get; set; default = ""; }
- public string surname { get; set; default = ""; }
- public string name_display { get; set; default = ""; }
- public string date_of_birth { get; set; default = ""; }
- public bool enabled { get; set; }
- public bool is_admin { get; set; }
- public bool is_me { get; set; }
- public string created_display { get; set; default = ""; }
- public Statum.Model.ActionDto? alter { get; set; }
- public Statum.Model.ActionDto? set_enabled { get; set; }
- public Statum.Model.ActionDto? grant_admin { get; set; }
- public Statum.Model.ActionDto? revoke_admin { get; set; }
- public Statum.Model.ActionDto? delete { get; set; }
- }
- /** Public data of the `users` slot. */
- public class UsersPublic : Object {
- public Statum.Model.ActionDto create { get; set; }
- }
- /**
- * Entrypoint for /users: the account table every row of which
- * carries its admin role badge, enabled state and row actions (edit
- * expander, enable/disable, grant/revoke admin, delete). Admin-only
- * (the authoritative guard; the nav link is hidden for non-admins
- * but the guard is what keeps the page closed).
- *
- * Rows are newest-first: the goal brief's list convention. The
- * enable/disable action seals the row's NEXT state so the button
- * never races the table, and the edit expander is prefilled from the
- * same row (one round trip, no separate fetch).
- */
- public class UsersEntrypoint : StatumEntrypoint {
- private UserService users_service = Inversion.inject<UserService>();
- public override async DirectiveBuilder handle() throws GLib.Error {
- var guard = yield SpryAuth.require_permission(directives(), request, users_service,
- SpryAuth.ADMIN_PERMISSION, "/login");
- if (guard != null) {
- return (!)guard;
- }
- var me = SpryAuth.current(request);
- var rows = new Vector<ManagedUserRowView>();
- foreach (var user in yield users_service.list_users(0, 1000)) {
- bool is_admin = SpryAuth.permission_matches(user.permissions.to_array(),
- SpryAuth.ADMIN_PERMISSION);
- var sealed_row = new ManagedUserPrivate() {
- user_id = user.id,
- enabled = !user.enabled
- };
- var view = new ManagedUserRowView() {
- id = user.id,
- username = user.username,
- email = user.email,
- forename = user.forename,
- surname = user.surname,
- name_display = @"$(user.forename) $(user.surname)".strip(),
- date_of_birth = user.date_of_birth.format("%Y-%m-%d"),
- enabled = user.enabled,
- is_admin = is_admin,
- is_me = me.user_id == user.id,
- created_display = format_stamp(user.created),
- alter = action_registry.author_private<AlterManagedUserAction, ManagedUserPrivate>(
- new ManagedUserPrivate() { user_id = user.id }),
- set_enabled = action_registry.author_private<SetManagedUserEnabledAction, ManagedUserPrivate>(sealed_row),
- delete = action_registry.author_private<DeleteManagedUserAction, ManagedUserPrivate>(
- new ManagedUserPrivate() { user_id = user.id })
- };
- if (is_admin) {
- view.revoke_admin = action_registry.author_private<RevokeUserAdminAction, ManagedUserPrivate>(
- new ManagedUserPrivate() { user_id = user.id });
- } else {
- view.grant_admin = action_registry.author_private<GrantUserAdminAction, ManagedUserPrivate>(
- new ManagedUserPrivate() { user_id = user.id });
- }
- rows.add(view);
- }
- // Newest first. The ids are autoincrement, so id-descending
- // IS created-descending — including the same-minute ties the
- // display stamp (minute resolution) cannot distinguish.
- var sorted = rows.to_array();
- for (int i = 1; i < sorted.length; i++) {
- var row = sorted[i];
- int j = i - 1;
- while (j >= 0 && sorted[j].id < row.id) {
- sorted[j + 1] = sorted[j];
- j--;
- }
- sorted[j + 1] = row;
- }
- var pub = new UsersPublic();
- pub.create = action_registry.author<CreateUserAction>();
- var props = (PropertyDictionary) GObjectMapping.to_properties(pub);
- props["users"] = StateJson.list_array<ManagedUserRowView>(sorted);
- var slot = state_service.new_slot(Scope.PAGE, new State() {
- type_name = "users",
- public_data = props,
- private_data = new PropertyDictionary()
- });
- return directives().set(slot);
- }
- }
- }
|