proposalsDiscussion.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. eslint-disable @typescript-eslint/naming-convention
  3. */
  4. import { EventContext, StoreContext, DatabaseManager } from '@dzlzv/hydra-common'
  5. import {
  6. Membership,
  7. ProposalDiscussionPostStatusActive,
  8. ProposalDiscussionPostStatusLocked,
  9. ProposalDiscussionPost,
  10. ProposalDiscussionThread,
  11. ProposalDiscussionPostCreatedEvent,
  12. ProposalDiscussionPostUpdatedEvent,
  13. ProposalDiscussionThreadModeClosed,
  14. ProposalDiscussionWhitelist,
  15. ProposalDiscussionThreadModeOpen,
  16. ProposalDiscussionThreadModeChangedEvent,
  17. ProposalDiscussionPostDeletedEvent,
  18. ProposalDiscussionPostStatusRemoved,
  19. } from 'query-node/dist/model'
  20. import { bytesToString, deserializeMetadata, genericEventFields, MemoryCache } from './common'
  21. import { ProposalsDiscussion } from './generated/types'
  22. import { ProposalsDiscussionPostMetadata } from '@joystream/metadata-protobuf'
  23. import { In } from 'typeorm'
  24. async function getPost(store: DatabaseManager, id: string) {
  25. const post = await store.get(ProposalDiscussionPost, { where: { id } })
  26. if (!post) {
  27. throw new Error(`Proposal discussion post not found by id: ${id}`)
  28. }
  29. return post
  30. }
  31. async function getThread(store: DatabaseManager, id: string) {
  32. const thread = await store.get(ProposalDiscussionThread, { where: { id } })
  33. if (!thread) {
  34. throw new Error(`Proposal discussion thread not found by id: ${id}`)
  35. }
  36. return thread
  37. }
  38. export async function proposalsDiscussion_ThreadCreated({ event }: EventContext & StoreContext): Promise<void> {
  39. const [threadId] = new ProposalsDiscussion.ThreadCreatedEvent(event).params
  40. MemoryCache.lastCreatedProposalThreadId = threadId
  41. }
  42. export async function proposalsDiscussion_PostCreated({ event, store }: EventContext & StoreContext): Promise<void> {
  43. const { editable } = new ProposalsDiscussion.AddPostCall(event).args // FIXME: batch and sudo extrinsics handling
  44. const [postId, memberId, threadId, metadataBytes] = new ProposalsDiscussion.PostCreatedEvent(event).params
  45. const eventTime = new Date(event.blockTimestamp)
  46. const metadata = deserializeMetadata(ProposalsDiscussionPostMetadata, metadataBytes)
  47. const repliesTo =
  48. typeof metadata?.repliesTo === 'number'
  49. ? await store.get(ProposalDiscussionPost, { where: { id: metadata.repliesTo.toString() } })
  50. : undefined
  51. const text = typeof metadata?.text === 'string' ? metadata.text : bytesToString(metadataBytes)
  52. const post = new ProposalDiscussionPost({
  53. id: postId.toString(),
  54. createdAt: eventTime,
  55. updatedAt: eventTime,
  56. author: new Membership({ id: memberId.toString() }),
  57. status: editable.isTrue ? new ProposalDiscussionPostStatusActive() : new ProposalDiscussionPostStatusLocked(),
  58. text,
  59. repliesTo,
  60. thread: new ProposalDiscussionThread({ id: threadId.toString() }),
  61. })
  62. await store.save<ProposalDiscussionPost>(post)
  63. const postCreatedEvent = new ProposalDiscussionPostCreatedEvent({
  64. ...genericEventFields(event),
  65. post: post,
  66. text,
  67. })
  68. await store.save<ProposalDiscussionPostCreatedEvent>(postCreatedEvent)
  69. }
  70. export async function proposalsDiscussion_PostUpdated({ event, store }: EventContext & StoreContext): Promise<void> {
  71. const [postId, , , newTextBytes] = new ProposalsDiscussion.PostUpdatedEvent(event).params
  72. const post = await getPost(store, postId.toString())
  73. const newText = bytesToString(newTextBytes)
  74. post.text = newText
  75. post.updatedAt = new Date(event.blockTimestamp)
  76. await store.save<ProposalDiscussionPost>(post)
  77. const postUpdatedEvent = new ProposalDiscussionPostUpdatedEvent({
  78. ...genericEventFields(event),
  79. post,
  80. text: newText,
  81. })
  82. await store.save<ProposalDiscussionPostUpdatedEvent>(postUpdatedEvent)
  83. }
  84. export async function proposalsDiscussion_ThreadModeChanged({
  85. event,
  86. store,
  87. }: EventContext & StoreContext): Promise<void> {
  88. const [threadId, threadMode, memberId] = new ProposalsDiscussion.ThreadModeChangedEvent(event).params
  89. const eventTime = new Date(event.blockTimestamp)
  90. const thread = await getThread(store, threadId.toString())
  91. if (threadMode.isClosed) {
  92. const newMode = new ProposalDiscussionThreadModeClosed()
  93. const whitelistMemberIds = threadMode.asClosed
  94. const members = await store.getMany(Membership, {
  95. where: { id: In(whitelistMemberIds.map((id) => id.toString())) },
  96. })
  97. const whitelist = new ProposalDiscussionWhitelist({
  98. createdAt: eventTime,
  99. updatedAt: eventTime,
  100. members,
  101. })
  102. await store.save<ProposalDiscussionWhitelist>(whitelist)
  103. newMode.whitelistId = whitelist.id
  104. thread.mode = newMode
  105. } else if (threadMode.isOpen) {
  106. const newMode = new ProposalDiscussionThreadModeOpen()
  107. thread.mode = newMode
  108. } else {
  109. throw new Error(`Unrecognized proposal thread mode: ${threadMode.type}`)
  110. }
  111. thread.updatedAt = eventTime
  112. await store.save<ProposalDiscussionThread>(thread)
  113. const threadModeChangedEvent = new ProposalDiscussionThreadModeChangedEvent({
  114. ...genericEventFields(event),
  115. actor: new Membership({ id: memberId.toString() }),
  116. newMode: thread.mode,
  117. thread: thread,
  118. })
  119. await store.save<ProposalDiscussionThreadModeChangedEvent>(threadModeChangedEvent)
  120. }
  121. export async function proposalsDiscussion_PostDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  122. const [memberId, , postId, hide] = new ProposalsDiscussion.PostDeletedEvent(event).params
  123. const eventTime = new Date(event.blockTimestamp)
  124. const post = await getPost(store, postId.toString())
  125. const postDeletedEvent = new ProposalDiscussionPostDeletedEvent({
  126. ...genericEventFields(event),
  127. post,
  128. actor: new Membership({ id: memberId.toString() }),
  129. })
  130. await store.save<ProposalDiscussionPostDeletedEvent>(postDeletedEvent)
  131. const newStatus = hide.isTrue ? new ProposalDiscussionPostStatusRemoved() : new ProposalDiscussionPostStatusLocked()
  132. newStatus.deletedInEventId = postDeletedEvent.id
  133. post.status = newStatus
  134. post.updatedAt = eventTime
  135. await store.save<ProposalDiscussionPost>(post)
  136. }