StacksEntrypoint.vala 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. using Spry;
  4. using Spry.Authentication;
  5. using Statum;
  6. using ClankerSaddle.Data;
  7. using ClankerSaddle.Services;
  8. namespace ClankerSaddle {
  9. /** A stack row on the stacks page, with its member names. */
  10. public class StackRowView : Object {
  11. public int64 id { get; set; }
  12. public string name { get; set; default = ""; }
  13. public string summary { get; set; default = ""; }
  14. public string created_display { get; set; default = ""; }
  15. public int64 member_count { get; set; }
  16. }
  17. /** Public data of the `stacks` slot. */
  18. public class StacksPublic : Object {
  19. public Statum.Model.ActionDto create { get; set; }
  20. }
  21. /**
  22. * Entrypoint for /stacks (goal 8 task 2 B): every stack with its
  23. * member count and a link to its page, plus the create form. A
  24. * stack is a named bundle of reference projects applied one-click
  25. * to a project's or a goal's link set.
  26. */
  27. public class StacksEntrypoint : StatumEntrypoint {
  28. private StackService stack_service = Inversion.inject<StackService>();
  29. private ProjectService project_service = Inversion.inject<ProjectService>();
  30. private UserService users = Inversion.inject<UserService>();
  31. public override async DirectiveBuilder handle() throws GLib.Error {
  32. var guard = yield SpryAuth.require_login(directives(), request, users);
  33. if (guard != null) {
  34. return (!)guard;
  35. }
  36. var rows = new Vector<StackRowView>();
  37. foreach (var stack in yield stack_service.list_stacks()) {
  38. rows.add(new StackRowView() {
  39. id = stack.id,
  40. name = stack.name,
  41. summary = stack.summary ?? "",
  42. created_display = format_stamp(stack.created_at),
  43. member_count = (yield stack_service.list_members(stack.id)).length
  44. });
  45. }
  46. var pub = new StacksPublic();
  47. pub.create = action_registry.author<CreateStackAction>();
  48. var props = (PropertyDictionary) GObjectMapping.to_properties(pub);
  49. props["stacks"] = StateJson.list<StackRowView>(rows.to_immutable_buffer());
  50. var slot = state_service.new_slot(Scope.PAGE, new State() {
  51. type_name = "stacks",
  52. public_data = props,
  53. private_data = new PropertyDictionary()
  54. });
  55. return directives().set(slot);
  56. }
  57. }
  58. /** A member project of a stack, with its remove action. */
  59. public class StackMemberView : Object {
  60. public int64 member_id { get; set; }
  61. public int64 project_id { get; set; }
  62. public string name { get; set; default = ""; }
  63. public string git_url { get; set; default = ""; }
  64. public string relationship { get; set; default = ""; }
  65. public Statum.Model.ActionDto? remove { get; set; }
  66. }
  67. /** A project option in the member-add select. */
  68. public class StackProjectOptionView : Object {
  69. public int64 id { get; set; }
  70. public string name { get; set; default = ""; }
  71. }
  72. /** Public data of the `stack` slot. */
  73. public class StackDetailPublic : Object {
  74. public bool exists { get; set; }
  75. public int64 id { get; set; }
  76. public string name { get; set; default = ""; }
  77. public string summary { get; set; default = ""; }
  78. public string created_display { get; set; default = ""; }
  79. public Statum.Model.ActionDto? update { get; set; }
  80. public Statum.Model.ActionDto? add_member { get; set; }
  81. public Statum.Model.ActionDto? delete { get; set; }
  82. }
  83. /**
  84. * Entrypoint for /stacks/{stack_id}: the stack's editable card,
  85. * its member projects with relationship badges and remove actions,
  86. * and the add-member form (every project, relationship select).
  87. */
  88. public class StackDetailEntrypoint : StatumEntrypoint {
  89. private StackService stack_service = Inversion.inject<StackService>();
  90. private ProjectService project_service = Inversion.inject<ProjectService>();
  91. private UserService users = Inversion.inject<UserService>();
  92. public override async DirectiveBuilder handle() throws GLib.Error {
  93. var guard = yield SpryAuth.require_login(directives(), request, users);
  94. if (guard != null) {
  95. return (!)guard;
  96. }
  97. int64 stack_id = int64.parse(request.route("stack_id") ?? "0");
  98. var stack = yield stack_service.get_stack(stack_id);
  99. if (stack == null) {
  100. return directives().set_typed<StackDetailPublic>("stack", Scope.PAGE,
  101. new StackDetailPublic() { exists = false });
  102. }
  103. var sealed = new StackActionPrivate() { stack_id = stack_id };
  104. var pub = new StackDetailPublic() {
  105. exists = true,
  106. id = ((!)stack).id,
  107. name = ((!)stack).name,
  108. summary = ((!)stack).summary ?? "",
  109. created_display = format_stamp(((!)stack).created_at),
  110. update = action_registry.author_private<UpdateStackAction, StackActionPrivate>(sealed),
  111. add_member = action_registry.author_private<AddStackMemberAction, StackActionPrivate>(sealed),
  112. delete = action_registry.author_private<DeleteStackAction, StackActionPrivate>(sealed)
  113. };
  114. var members = new Vector<StackMemberView>();
  115. foreach (var member in yield stack_service.list_members(stack_id)) {
  116. var project = yield project_service.get_project(member.project_id);
  117. if (project == null) {
  118. continue;
  119. }
  120. members.add(new StackMemberView() {
  121. member_id = member.id,
  122. project_id = member.project_id,
  123. name = ((!)project).name,
  124. git_url = ((!)project).git_url,
  125. relationship = member.relationship,
  126. remove = action_registry.author_private<RemoveStackMemberAction, StackMemberActionPrivate>(
  127. new StackMemberActionPrivate() { stack_id = stack_id, member_id = member.id })
  128. });
  129. }
  130. var options = new Vector<StackProjectOptionView>();
  131. foreach (var project in yield project_service.list_projects()) {
  132. options.add(new StackProjectOptionView() {
  133. id = project.id,
  134. name = project.name
  135. });
  136. }
  137. var props = (PropertyDictionary) GObjectMapping.to_properties(pub);
  138. props["members"] = StateJson.list<StackMemberView>(members.to_immutable_buffer());
  139. props["options"] = StateJson.list<StackProjectOptionView>(options.to_immutable_buffer());
  140. var slot = state_service.new_slot(Scope.PAGE, new State() {
  141. type_name = "stack",
  142. public_data = props,
  143. private_data = new PropertyDictionary()
  144. });
  145. return directives().set(slot);
  146. }
  147. }
  148. }