gitoriaLog in with ident

tickets

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commitc7bd2645c7bd2645tickets: Hybriel master 73267707 (#122 fixed); compactNow workaround removed (#110 covered)mrec7bd2645/components/connect.hl

4.5 KB

  1. // components/connect.hl — `/connect/:nonce` (ticket #21): another app (first: gitoria) asks to be connected to one
  2. // project. The person — logged in through ident, with a display name — picks a project they are ADMIN of, or makes a
  3. // new one, and confirms. Then the page links back to the app with a one-time code (connections.hl); the app's server
  4. // swaps the code for a key that reaches that one project. Everybody else sees the login hint; a used or expired
  5. // request says so. Everything is checked again by the store in the faces.
  6. parent './main.hl'
  7. import { requestOf, requestView, adminProjects, confirmRequest } from '../connections.hl'
  8. import { siteName } from '../project.hl'
  9. import { userOfSession, writerOfSession, canWriteSession } from '../users.hl'
  10. nonce = null
  11. session = null
  12. pending = requestOf(nonce)
  13. valid = pending != null
  14. gone = pending == null
  15. info = pending != null ? requestView(pending) : { app = '' label = '' hasLabel = false host = '' }
  16. appName = info.app
  17. appLabel = info.label
  18. hasLabel = info.hasLabel
  19. appHost = info.host
  20. canWrite = valid && canWriteSession(session)
  21. showForm = valid && canWriteSession(session)
  22. mustLogIn = valid && !canWriteSession(session)
  23. choices = adminProjects(userOfSession(session))
  24. choice = choices.length > 0 ? choices[0].id : ''
  25. makeNew = choices.length == 0
  26. newTitle = ''
  27. message = ''
  28. done = false
  29. doneUrl = ''
  30. doneProject = ''
  31. __title = siteName + ' | connect ' + (pending != null ? pending.app : 'an app')
  32. View {
  33. connectPage {
  34. if (gone) { p { id = "gone" class = "empty" "This connection request is used up or expired. Start again from the app." } }
  35. if (valid) {
  36. h1 { id = "connecttitle" "Connect " appName " to a project" }
  37. p { id = "connectwho" class = "hint"
  38. strong { appName }
  39. if (hasLabel) { " (" appLabel ")" }
  40. " at "
  41. strong { appHost }
  42. " asks for a key to ONE of your projects. With it the app can open tickets, comment and change their state there — for the people who work in it, within their roles. You can disconnect it on the project's page at any time."
  43. }
  44. }
  45. if (mustLogIn) { p { id = "loginhint" class = "hint" "Log in with ident (top right) and choose a display name to connect." } }
  46. if (showForm) {
  47. form { id = "connectform"
  48. on submit(e) {
  49. e.preventDefault()
  50. emit confirm(e)
  51. }
  52. label { "Project"
  53. select { id = "connectproject" name = "project" value = choice on change(e) { emit setChoice(e.target.value) }
  54. for (c of choices) { option { value = c.id c.title } }
  55. option { value = "" "A new project" }
  56. }
  57. }
  58. if (makeNew) {
  59. label { "Title of the new project"
  60. input { id = "connecttitleinput" name = "title" required = "required" maxlength = "100" autocomplete = "off" value = newTitle on input(e) { emit setNewTitle(e.target.value) } }
  61. }
  62. }
  63. button { id = "connectconfirm" type = "submit" "Connect" }
  64. p { id = "connectmessage" class = "message" message }
  65. }
  66. }
  67. if (done) {
  68. p { id = "connected" class = "notice" "Connected to " strong { doneProject } ". " }
  69. a { id = "connectcontinue" class = "button" href = doneUrl "Continue to " appName }
  70. }
  71. }
  72. }
  73. on setChoice(v) {
  74. choice = v
  75. makeNew = v == ''
  76. }
  77. on setNewTitle(v) { newTitle = v }
  78. on confirm(e) {
  79. if (makeNew && newTitle.trim() == '') { return null }
  80. let r = emit server connectConfirm(nonce, choice, newTitle)
  81. if (r == null || r.error != null) {
  82. message = r != null ? r.error : 'could not connect'
  83. return null
  84. }
  85. message = ''
  86. showForm = false
  87. doneUrl = r.url
  88. doneProject = r.project
  89. done = true
  90. }
  91. on client signedIn(tag, info) {
  92. let r = emit server connectChoices()
  93. if (r != null && r.projects != null) {
  94. choices = r.projects
  95. choice = r.projects.length > 0 ? r.projects[0].id : ''
  96. makeNew = r.projects.length == 0
  97. }
  98. canWrite = valid && info.named
  99. showForm = valid && info.named && !done
  100. mustLogIn = valid && !info.named
  101. }
  102. on client signedOut(tag) {
  103. canWrite = false
  104. showForm = false
  105. mustLogIn = valid
  106. choices = []
  107. }
  108. on server connectChoices(session) {
  109. let u = userOfSession(session)
  110. if (u == null) { return { error = 'log in first' } }
  111. return { projects = adminProjects(u) }
  112. }
  113. on server connectConfirm(nonce, projectId, title, session) {
  114. let w = writerOfSession(session)
  115. if (w.error != null) { return { error = w.error } }
  116. if (hlTypeName(nonce) != 'String' || hlTypeName(projectId) != 'String' || hlTypeName(title) != 'String') { return { error = 'nonce, project and title must be text' } }
  117. let r = confirmRequest(nonce, w.user, projectId, title)
  118. if (r.error != null) { return { error = r.error } }
  119. return { url = r.url project = r.project slug = r.slug }
  120. }

Branches

Latest commits

  • c7bd2645tickets: Hybriel master 73267707 (#122 fixed); compactNow workaround removed (#110 covered)mre
  • 2ab91ee9tickets: gate checks rows appear once (session sync); re-vendor to ff51cf46 stopped on hybriel#122, stays 837fe120mre
  • e01c2b1dtickets#24: installable app (manifest, service worker, offline list), own icon; gate waits for the hello's pongmre
  • 752fbb7fdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • 38bdd5e4deploy.sh: never send .git or .gitignore to Byrodinmre
  • f12fa1bcState of 2026-09-27, before the move to gitoriamre