123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- import { fixBlockTimestamp } from './eventFix'
- import { Bytes } from '@polkadot/types'
- import { MemberId } from '@joystream/types/members'
- import { SubstrateEvent } from '@dzlzv/hydra-common'
- import { DatabaseManager } from '@dzlzv/hydra-db-utils'
- import { FindConditions } from 'typeorm'
- import {
- convertBytesToString,
- inconsistentState,
- logger,
- extractExtrinsicArgs,
- extractSudoCallParameters,
- } from './common'
- import { Members } from '../../generated/types'
- import { MembershipEntryMethod, Membership } from 'query-node'
- import { EntryMethod } from '@joystream/types/augment'
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function members_MemberRegistered(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
- // read event data
- const { accountId, memberId, entryMethod } = new Members.MemberRegisteredEvent(event).data
- const { avatarUri, about, handle } = extractExtrinsicArgs(event, Members.BuyMembershipCall, {
- handle: 1,
- avatarUri: 2,
- about: 3,
- })
- // create new membership
- const member = new Membership({
- // main data
- id: memberId.toString(),
- rootAccount: accountId.toString(),
- controllerAccount: accountId.toString(),
- handle: convertBytesToString(handle.unwrapOr(null)),
- about: convertBytesToString(about.unwrapOr(null)),
- avatarUri: convertBytesToString(avatarUri.unwrapOr(null)),
- createdInBlock: event.blockNumber,
- entry: convertEntryMethod(entryMethod),
- // fill in auto-generated fields
- createdAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
- updatedAt: new Date(fixBlockTimestamp(event.blockTimestamp).toNumber()),
- })
- // save membership
- await db.save<Membership>(member)
- // emit log event
- logger.info('Member has been registered', { ids: memberId })
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function members_MemberUpdatedAboutText(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
- // read event data
- const { text, memberId } = isUpdateMembershipExtrinsic(event)
- ? unpackUpdateMembershipOptions(
- extractExtrinsicArgs(event, Members.UpdateMembershipCall, { memberId: 0, about: 3 })
- )
- : extractExtrinsicArgs(event, Members.ChangeMemberAboutTextCall, { memberId: 0, text: 1 })
- // load member
- const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
- // ensure member exists
- if (!member) {
- return inconsistentState(`Non-existing member about text update requested`, memberId)
- }
- // update member
- member.about = convertBytesToString(text)
- // set last update time
- member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
- // save member
- await db.save<Membership>(member)
- // emit log event
- logger.info("Member's about text has been updated", { ids: memberId })
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
- // read event data
- const { uri, memberId } = isUpdateMembershipExtrinsic(event)
- ? unpackUpdateMembershipOptions(
- extractExtrinsicArgs(event, Members.UpdateMembershipCall, { memberId: 0, avatarUri: 2 })
- )
- : extractExtrinsicArgs(event, Members.ChangeMemberAvatarCall, { memberId: 0, uri: 1 })
- // load member
- const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
- // ensure member exists
- if (!member) {
- return inconsistentState(`Non-existing member avatar update requested`, memberId)
- }
- // update member
- member.avatarUri = convertBytesToString(uri)
- // set last update time
- member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
- // save member
- await db.save<Membership>(member)
- // emit log event
- logger.info("Member's avatar has been updated", { ids: memberId })
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function members_MemberUpdatedHandle(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
- // read event data
- const { handle, memberId } = isUpdateMembershipExtrinsic(event)
- ? unpackUpdateMembershipOptions(
- extractExtrinsicArgs(event, Members.UpdateMembershipCall, { memberId: 0, handle: 1 })
- )
- : extractExtrinsicArgs(event, Members.ChangeMemberHandleCall, { memberId: 0, handle: 1 })
- // load member
- const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
- // ensure member exists
- if (!member) {
- return inconsistentState(`Non-existing member handle update requested`, memberId)
- }
- // update member
- member.handle = convertBytesToString(handle)
- // set last update time
- member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
- // save member
- await db.save<Membership>(member)
- // emit log event
- logger.info("Member's avatar has been updated", { ids: memberId })
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function members_MemberSetRootAccount(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
- // read event data
- const { newRootAccount, memberId } = extractExtrinsicArgs(event, Members.SetRootAccountCall, {
- memberId: 0,
- newRootAccount: 1,
- })
- // load member
- const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
- // ensure member exists
- if (!member) {
- return inconsistentState(`Non-existing member root account update requested`, memberId)
- }
- // update member
- member.rootAccount = newRootAccount.toString()
- // set last update time
- member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
- // save member
- await db.save<Membership>(member)
- // emit log event
- logger.info("Member's root has been updated", { ids: memberId })
- }
- // eslint-disable-next-line @typescript-eslint/naming-convention
- export async function members_MemberSetControllerAccount(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
- // read event data
- const { newControllerAccount, memberId } = extractExtrinsicArgs(event, Members.SetControllerAccountCall, {
- memberId: 0,
- newControllerAccount: 1,
- })
- // load member
- const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
- // ensure member exists
- if (!member) {
- return inconsistentState(`Non-existing member controller account update requested`, memberId)
- }
- // update member
- member.controllerAccount = newControllerAccount.toString()
- // set last update time
- member.updatedAt = new Date(fixBlockTimestamp(event.blockTimestamp).toNumber())
- // save member
- await db.save<Membership>(member)
- // emit log event
- logger.info("Member's controller has been updated", { ids: memberId })
- }
- /// ///////////////// Helpers ////////////////////////////////////////////////////
- function convertEntryMethod(entryMethod: EntryMethod): MembershipEntryMethod {
- // paid membership?
- if (entryMethod.isPaid) {
- return MembershipEntryMethod.PAID
- }
- // paid membership?
- if (entryMethod.isScreening) {
- return MembershipEntryMethod.SCREENING
- }
- // paid membership?
- if (entryMethod.isGenesis) {
- return MembershipEntryMethod.GENESIS
- }
- // should never happen
- logger.error('Not implemented entry method', { entryMethod: entryMethod.toString() })
- throw new Error('Not implemented entry method')
- }
- /*
- Returns true if event is emitted inside of `update_membership` extrinsic.
- */
- function isUpdateMembershipExtrinsic(event: SubstrateEvent): boolean {
- if (!event.extrinsic) {
- // this should never happen
- return false
- }
- if (event.extrinsic.method === 'updateMembership') {
- return true
- }
- // no sudo was used to update membership -> this is not updateMembership
- if (event.extrinsic.section !== 'sudo') {
- return false
- }
- const sudoCallParameters = extractSudoCallParameters<unknown[]>(event)
- // very trivial check if update_membership extrinsic was used
- return sudoCallParameters.args.length === 4 // memberId, handle, avatarUri, about
- }
- interface IUnpackedUpdateMembershipOptions {
- memberId: MemberId
- handle: Bytes
- uri: Bytes
- text: Bytes
- }
- /*
- Returns unwrapped data + unite naming of uri/avatarUri and about/text
- */
- function unpackUpdateMembershipOptions(args: Members.UpdateMembershipCall['args']): IUnpackedUpdateMembershipOptions {
- return {
- memberId: args.memberId,
- handle: args.handle.unwrapOrDefault(),
- uri: args.avatarUri.unwrapOrDefault(),
- text: args.about.unwrapOrDefault(),
- }
- }
|