gitoriaLog in with ident

tickets

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit38f9d10f38f9d10ftickets: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gate 249/0, connect 60/0mre38f9d10f/components/you.hl

5.3 KB

  1. // components/you.hl — `/you` (ticket #7): the logged-in user's own page.
  2. // * the display name, and the PER-APP IDENTITY ID ident gave tickets for this identity —
  3. // shown ONLY here and only to its owner (an admin adds a person to a project by it). Ticket #20: the
  4. // projects the user is a member of, with their role.
  5. // * API TOKENS for machine clients (CONCEPT point 5): create (the token is shown ONCE — only
  6. // its sha256 is stored), list, revoke. `Authorization: Bearer <token>` acts as this user.
  7. // Logged out: a hint. A login in the shell (no reload) fills the page via the face `youData`.
  8. parent './main.hl'
  9. import { siteName } from '../project.hl'
  10. import { youOf, userOfSession, createToken, revokeToken, tokenRows } from '../users.hl'
  11. import { projectsOfUser } from '../store.hl'
  12. session = null
  13. you = youOf(session)
  14. present = you != null
  15. absent = you == null
  16. youName = you != null ? you.name : ''
  17. identity = you != null ? you.identity : ''
  18. myProjects = projectsOfUser(userOfSession(session))
  19. hasProjects = myProjects.length > 0
  20. noProjects = myProjects.length == 0
  21. tokens = you != null ? you.tokens : []
  22. hasTokens = tokens.length > 0
  23. noTokens = tokens.length == 0
  24. newLabel = ''
  25. newToken = ''
  26. hasNewToken = false
  27. tokenMessage = ''
  28. __title = siteName + ' | you'
  29. View {
  30. youView {
  31. h1 { "You" }
  32. if (absent) { p { id = "youhint" class = "empty" "Log in with ident (top right) to see your account and your API tokens." } }
  33. if (present) {
  34. section { id = "account"
  35. h2 { "Account" }
  36. dl {
  37. dt { "Display name" }
  38. dd { id = "youname" youName }
  39. dt { "Your ident id" }
  40. dd { code { id = "youidentity" identity } }
  41. }
  42. p { class = "muted" "The id ident shows for the identity you logged in with. An admin of a project can add you with it." }
  43. }
  44. section { id = "myprojects"
  45. h2 { "Your projects" }
  46. if (noProjects) { p { id = "noprojects" class = "empty" "You are not a member of any project yet." } }
  47. ul { id = "projectlist"
  48. for (p of myProjects) { li { a { href = p.href p.title } " " span { class = "role" p.role } } }
  49. }
  50. }
  51. section { id = "tokens"
  52. h2 { "API tokens" }
  53. p { class = "muted" "For machine clients (the architect, the scheduler): a token acts as you on every API write — send it as " code { "Authorization: Bearer <token>" } ". It is shown once." }
  54. form { id = "tokenform"
  55. on submit(e) {
  56. e.preventDefault()
  57. emit makeToken(e)
  58. }
  59. label { "Label (optional, e.g. what uses it)"
  60. input { id = "tokenlabel" name = "label" maxlength = "60" autocomplete = "off" value = newLabel on input(e) { emit setLabel(e.target.value) } }
  61. }
  62. button { id = "tokencreate" type = "submit" "Create a token" }
  63. }
  64. if (hasNewToken) {
  65. tokenShown { id = "newtokenbox"
  66. p { "Your new token — copy it now, it is not shown again:" }
  67. code { id = "newtoken" newToken }
  68. button { id = "tokendone" type = "button" class = "quiet" "I copied it" on click(e) { emit hideToken(e) } }
  69. }
  70. }
  71. p { id = "tokenmessage" class = "message" tokenMessage }
  72. if (noTokens) { p { id = "notokens" class = "empty" "No tokens." } }
  73. ul { id = "tokenlist"
  74. for (t of tokens) {
  75. li {
  76. span { class = "label" t.label }
  77. time { t.created }
  78. button { type = "button" class = "quiet danger revoke" value = t.id "Revoke" on click(e) { emit revoke(e.target.value) } }
  79. }
  80. }
  81. }
  82. }
  83. }
  84. }
  85. }
  86. fill = (y) => {
  87. you = y
  88. present = y != null
  89. absent = y == null
  90. youName = y != null ? y.name : ''
  91. identity = y != null ? y.identity : ''
  92. showTokens(y != null ? y.tokens : [])
  93. }
  94. showTokens = (list) => {
  95. tokens = list
  96. hasTokens = list.length > 0
  97. noTokens = list.length == 0
  98. }
  99. on setLabel(v) { newLabel = v }
  100. on makeToken(e) {
  101. let r = emit server tokenCreate(newLabel)
  102. if (r == null || r.error != null) {
  103. tokenMessage = r != null ? r.error : 'could not create the token'
  104. return null
  105. }
  106. tokenMessage = ''
  107. newLabel = ''
  108. newToken = r.token
  109. hasNewToken = true
  110. showTokens(r.tokens)
  111. }
  112. on hideToken(e) {
  113. newToken = ''
  114. hasNewToken = false
  115. }
  116. on revoke(id) {
  117. let r = emit server tokenRevoke(id)
  118. if (r == null || r.error != null) {
  119. tokenMessage = r != null ? r.error : 'could not revoke the token'
  120. return null
  121. }
  122. tokenMessage = ''
  123. showTokens(r.tokens)
  124. }
  125. // a login / name / logout in the shell, without a reload
  126. on client signedIn(tag, info) {
  127. let y = emit server youData()
  128. fill(y)
  129. let mine = emit server myProjectsData()
  130. myProjects = mine != null && mine.projects != null ? mine.projects : []
  131. hasProjects = myProjects.length > 0
  132. noProjects = myProjects.length == 0
  133. }
  134. on client signedOut(tag) {
  135. fill(null)
  136. newToken = ''
  137. hasNewToken = false
  138. }
  139. // ---- the faces (#31: only a real session) -------------------------------------------------
  140. on server youData(session) { return youOf(session) }
  141. on server myProjectsData(session) { return { projects = projectsOfUser(userOfSession(session)) } }
  142. on server tokenCreate(label, session) {
  143. let u = userOfSession(session)
  144. if (u == null) { return { error = 'log in with ident first' } }
  145. if (u.name == '') { return { error = 'choose a display name first' } }
  146. return createToken(u.id, label)
  147. }
  148. on server tokenRevoke(id, session) {
  149. let u = userOfSession(session)
  150. if (u == null) { return { error = 'log in with ident first' } }
  151. return revokeToken(u.id, id)
  152. }

Branches

Latest commits

  • 38f9d10ftickets: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gate 249/0, connect 60/0mre
  • d3db6139tickets: Hybriel master 190aa11d (fc838894 GC correctness, #126 closure scopes, #127); gate 249/0, connect 60/0mre
  • bce182e3tickets: Hybriel master 7eea0d32 (#126 memory, #48 lambda copies its argument); migrate.hl lambdas take &logmre
  • 4137be0fantcolony#40: mission references point to the moved missionsmre
  • 9bfba36aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • 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