Browse Source

Merge pull request #2918 from thesan/olympia-pioneer-query-node-update

query node - pioneer update
Lezek123 3 years ago
parent
commit
0e05e05f96

+ 13 - 4
metadata-protobuf/compiled/index.d.ts

@@ -615,8 +615,11 @@ export interface IMembershipMetadata {
     /** MembershipMetadata name */
     /** MembershipMetadata name */
     name?: (string|null);
     name?: (string|null);
 
 
-    /** MembershipMetadata avatar */
-    avatar?: (number|null);
+    /** MembershipMetadata avatarObject */
+    avatarObject?: (number|null);
+
+    /** MembershipMetadata avatarUri */
+    avatarUri?: (string|null);
 
 
     /** MembershipMetadata about */
     /** MembershipMetadata about */
     about?: (string|null);
     about?: (string|null);
@@ -634,12 +637,18 @@ export class MembershipMetadata implements IMembershipMetadata {
     /** MembershipMetadata name. */
     /** MembershipMetadata name. */
     public name: string;
     public name: string;
 
 
-    /** MembershipMetadata avatar. */
-    public avatar: number;
+    /** MembershipMetadata avatarObject. */
+    public avatarObject?: (number|null);
+
+    /** MembershipMetadata avatarUri. */
+    public avatarUri?: (string|null);
 
 
     /** MembershipMetadata about. */
     /** MembershipMetadata about. */
     public about: string;
     public about: string;
 
 
+    /** MembershipMetadata avatar. */
+    public avatar?: ("avatarObject"|"avatarUri");
+
     /**
     /**
      * Creates a new MembershipMetadata instance using the specified properties.
      * Creates a new MembershipMetadata instance using the specified properties.
      * @param [properties] Properties to set
      * @param [properties] Properties to set

+ 62 - 15
metadata-protobuf/compiled/index.js

@@ -1418,7 +1418,8 @@ $root.MembershipMetadata = (function() {
      * @exports IMembershipMetadata
      * @exports IMembershipMetadata
      * @interface IMembershipMetadata
      * @interface IMembershipMetadata
      * @property {string|null} [name] MembershipMetadata name
      * @property {string|null} [name] MembershipMetadata name
-     * @property {number|null} [avatar] MembershipMetadata avatar
+     * @property {number|null} [avatarObject] MembershipMetadata avatarObject
+     * @property {string|null} [avatarUri] MembershipMetadata avatarUri
      * @property {string|null} [about] MembershipMetadata about
      * @property {string|null} [about] MembershipMetadata about
      */
      */
 
 
@@ -1446,12 +1447,20 @@ $root.MembershipMetadata = (function() {
     MembershipMetadata.prototype.name = "";
     MembershipMetadata.prototype.name = "";
 
 
     /**
     /**
-     * MembershipMetadata avatar.
-     * @member {number} avatar
+     * MembershipMetadata avatarObject.
+     * @member {number|null|undefined} avatarObject
      * @memberof MembershipMetadata
      * @memberof MembershipMetadata
      * @instance
      * @instance
      */
      */
-    MembershipMetadata.prototype.avatar = 0;
+    MembershipMetadata.prototype.avatarObject = null;
+
+    /**
+     * MembershipMetadata avatarUri.
+     * @member {string|null|undefined} avatarUri
+     * @memberof MembershipMetadata
+     * @instance
+     */
+    MembershipMetadata.prototype.avatarUri = null;
 
 
     /**
     /**
      * MembershipMetadata about.
      * MembershipMetadata about.
@@ -1461,6 +1470,20 @@ $root.MembershipMetadata = (function() {
      */
      */
     MembershipMetadata.prototype.about = "";
     MembershipMetadata.prototype.about = "";
 
 
+    // OneOf field names bound to virtual getters and setters
+    var $oneOfFields;
+
+    /**
+     * MembershipMetadata avatar.
+     * @member {"avatarObject"|"avatarUri"|undefined} avatar
+     * @memberof MembershipMetadata
+     * @instance
+     */
+    Object.defineProperty(MembershipMetadata.prototype, "avatar", {
+        get: $util.oneOfGetter($oneOfFields = ["avatarObject", "avatarUri"]),
+        set: $util.oneOfSetter($oneOfFields)
+    });
+
     /**
     /**
      * Creates a new MembershipMetadata instance using the specified properties.
      * Creates a new MembershipMetadata instance using the specified properties.
      * @function create
      * @function create
@@ -1487,10 +1510,12 @@ $root.MembershipMetadata = (function() {
             writer = $Writer.create();
             writer = $Writer.create();
         if (message.name != null && Object.hasOwnProperty.call(message, "name"))
         if (message.name != null && Object.hasOwnProperty.call(message, "name"))
             writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
             writer.uint32(/* id 1, wireType 2 =*/10).string(message.name);
-        if (message.avatar != null && Object.hasOwnProperty.call(message, "avatar"))
-            writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.avatar);
+        if (message.avatarObject != null && Object.hasOwnProperty.call(message, "avatarObject"))
+            writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.avatarObject);
         if (message.about != null && Object.hasOwnProperty.call(message, "about"))
         if (message.about != null && Object.hasOwnProperty.call(message, "about"))
             writer.uint32(/* id 3, wireType 2 =*/26).string(message.about);
             writer.uint32(/* id 3, wireType 2 =*/26).string(message.about);
+        if (message.avatarUri != null && Object.hasOwnProperty.call(message, "avatarUri"))
+            writer.uint32(/* id 4, wireType 2 =*/34).string(message.avatarUri);
         return writer;
         return writer;
     };
     };
 
 
@@ -1529,7 +1554,10 @@ $root.MembershipMetadata = (function() {
                 message.name = reader.string();
                 message.name = reader.string();
                 break;
                 break;
             case 2:
             case 2:
-                message.avatar = reader.uint32();
+                message.avatarObject = reader.uint32();
+                break;
+            case 4:
+                message.avatarUri = reader.string();
                 break;
                 break;
             case 3:
             case 3:
                 message.about = reader.string();
                 message.about = reader.string();
@@ -1569,12 +1597,22 @@ $root.MembershipMetadata = (function() {
     MembershipMetadata.verify = function verify(message) {
     MembershipMetadata.verify = function verify(message) {
         if (typeof message !== "object" || message === null)
         if (typeof message !== "object" || message === null)
             return "object expected";
             return "object expected";
+        var properties = {};
         if (message.name != null && message.hasOwnProperty("name"))
         if (message.name != null && message.hasOwnProperty("name"))
             if (!$util.isString(message.name))
             if (!$util.isString(message.name))
                 return "name: string expected";
                 return "name: string expected";
-        if (message.avatar != null && message.hasOwnProperty("avatar"))
-            if (!$util.isInteger(message.avatar))
-                return "avatar: integer expected";
+        if (message.avatarObject != null && message.hasOwnProperty("avatarObject")) {
+            properties.avatar = 1;
+            if (!$util.isInteger(message.avatarObject))
+                return "avatarObject: integer expected";
+        }
+        if (message.avatarUri != null && message.hasOwnProperty("avatarUri")) {
+            if (properties.avatar === 1)
+                return "avatar: multiple values";
+            properties.avatar = 1;
+            if (!$util.isString(message.avatarUri))
+                return "avatarUri: string expected";
+        }
         if (message.about != null && message.hasOwnProperty("about"))
         if (message.about != null && message.hasOwnProperty("about"))
             if (!$util.isString(message.about))
             if (!$util.isString(message.about))
                 return "about: string expected";
                 return "about: string expected";
@@ -1595,8 +1633,10 @@ $root.MembershipMetadata = (function() {
         var message = new $root.MembershipMetadata();
         var message = new $root.MembershipMetadata();
         if (object.name != null)
         if (object.name != null)
             message.name = String(object.name);
             message.name = String(object.name);
-        if (object.avatar != null)
-            message.avatar = object.avatar >>> 0;
+        if (object.avatarObject != null)
+            message.avatarObject = object.avatarObject >>> 0;
+        if (object.avatarUri != null)
+            message.avatarUri = String(object.avatarUri);
         if (object.about != null)
         if (object.about != null)
             message.about = String(object.about);
             message.about = String(object.about);
         return message;
         return message;
@@ -1617,15 +1657,22 @@ $root.MembershipMetadata = (function() {
         var object = {};
         var object = {};
         if (options.defaults) {
         if (options.defaults) {
             object.name = "";
             object.name = "";
-            object.avatar = 0;
             object.about = "";
             object.about = "";
         }
         }
         if (message.name != null && message.hasOwnProperty("name"))
         if (message.name != null && message.hasOwnProperty("name"))
             object.name = message.name;
             object.name = message.name;
-        if (message.avatar != null && message.hasOwnProperty("avatar"))
-            object.avatar = message.avatar;
+        if (message.avatarObject != null && message.hasOwnProperty("avatarObject")) {
+            object.avatarObject = message.avatarObject;
+            if (options.oneofs)
+                object.avatar = "avatarObject";
+        }
         if (message.about != null && message.hasOwnProperty("about"))
         if (message.about != null && message.hasOwnProperty("about"))
             object.about = message.about;
             object.about = message.about;
+        if (message.avatarUri != null && message.hasOwnProperty("avatarUri")) {
+            object.avatarUri = message.avatarUri;
+            if (options.oneofs)
+                object.avatar = "avatarUri";
+        }
         return object;
         return object;
     };
     };
 
 

+ 4 - 1
metadata-protobuf/proto/Membership.proto

@@ -2,6 +2,9 @@ syntax = "proto2";
 
 
 message MembershipMetadata {
 message MembershipMetadata {
   optional string name = 1; // Member's real name
   optional string name = 1; // Member's real name
-  optional uint32 avatar = 2; // Member's avatar - index into external [assets array](#.Assets)
+  oneof avatar {
+    uint32 avatar_object = 2; // Member's avatar - index into external [assets array](#.Assets)
+    string avatar_uri = 4; // Url to member's avatar
+  }
   optional string about = 3; // Member's md-formatted about text
   optional string about = 3; // Member's md-formatted about text
 }
 }

+ 66 - 31
query-node/mappings/src/council.ts

@@ -1,4 +1,4 @@
-import { EventContext, StoreContext, DatabaseManager } from '@joystream/hydra-common'
+import { EventContext, StoreContext, DatabaseManager, SubstrateEvent } from '@joystream/hydra-common'
 import { CURRENT_NETWORK, deserializeMetadata, genericEventFields } from './common'
 import { CURRENT_NETWORK, deserializeMetadata, genericEventFields } from './common'
 import BN from 'bn.js'
 import BN from 'bn.js'
 import { FindConditions, SelectQueryBuilder } from 'typeorm'
 import { FindConditions, SelectQueryBuilder } from 'typeorm'
@@ -48,6 +48,7 @@ import {
   ElectedCouncil,
   ElectedCouncil,
   CastVote,
   CastVote,
   CandidacyNoteMetadata,
   CandidacyNoteMetadata,
+  CandidacyStatus,
 
 
   // Misc
   // Misc
   Membership,
   Membership,
@@ -170,7 +171,7 @@ async function getAccountCastVote(
 
 
   if (!castVote) {
   if (!castVote) {
     throw new Error(
     throw new Error(
-      `No vote cast by the given account in the curent election round. accountId '${account}', cycleId '${electionRound?.cycleId}'`
+      `No vote cast by the given account in the current election round. accountId '${account}', cycleId '${electionRound?.cycleId}'`
     )
     )
   }
   }
 
 
@@ -221,12 +222,16 @@ async function updateCouncilStage(
 async function startNextElectionRound(
 async function startNextElectionRound(
   store: DatabaseManager,
   store: DatabaseManager,
   electedCouncil: ElectedCouncil,
   electedCouncil: ElectedCouncil,
-  blockNumber: number,
+  event: SubstrateEvent,
   electionProblem?: ElectionProblem
   electionProblem?: ElectionProblem
 ): Promise<ElectionRound> {
 ): Promise<ElectionRound> {
   // finish last election round
   // finish last election round
   const lastElectionRound = await getCurrentElectionRound(store)
   const lastElectionRound = await getCurrentElectionRound(store)
   lastElectionRound.isFinished = true
   lastElectionRound.isFinished = true
+  lastElectionRound.endedAtBlock = event.blockNumber
+  lastElectionRound.endedAtTime = new Date(event.blockTimestamp)
+  lastElectionRound.endedAtNetwork = CURRENT_NETWORK
+
   lastElectionRound.nextElectedCouncil = electedCouncil
   lastElectionRound.nextElectedCouncil = electedCouncil
 
 
   // save last election
   // save last election
@@ -248,7 +253,7 @@ async function startNextElectionRound(
 
 
   const stage = new CouncilStageAnnouncing()
   const stage = new CouncilStageAnnouncing()
   stage.candidatesCount = new BN(0)
   stage.candidatesCount = new BN(0)
-  await updateCouncilStage(store, stage, blockNumber, electionProblem)
+  await updateCouncilStage(store, stage, event.blockNumber, electionProblem)
 
 
   return electionRound
   return electionRound
 }
 }
@@ -257,14 +262,11 @@ async function startNextElectionRound(
   Converts successful council candidate records to council member records.
   Converts successful council candidate records to council member records.
 */
 */
 async function convertCandidatesToCouncilMembers(
 async function convertCandidatesToCouncilMembers(
-  store: DatabaseManager,
-  candidates: Candidate[],
+  candidates: Array<Candidate & { memberId: string }>,
   blockNumber: number
   blockNumber: number
 ): Promise<CouncilMember[]> {
 ): Promise<CouncilMember[]> {
-  const councilMembers = await candidates.reduce(async (councilMembersPromise, candidate) => {
-    const councilMembers = await councilMembersPromise
-
-    const member = new Membership({ id: candidate.member.id.toString() })
+  return candidates.map((candidate) => {
+    const member = new Membership({ id: candidate.memberId })
 
 
     const councilMember = new CouncilMember({
     const councilMember = new CouncilMember({
       // id: candidate.id // TODO: are ids needed?
       // id: candidate.id // TODO: are ids needed?
@@ -279,10 +281,27 @@ async function convertCandidatesToCouncilMembers(
       accumulatedReward: new BN(0),
       accumulatedReward: new BN(0),
     })
     })
 
 
-    return [...councilMembers, councilMember]
-  }, Promise.resolve([] as CouncilMember[]))
+    return councilMember
+  })
+}
 
 
-  return councilMembers
+/**
+  Mark the candidacies as aborted when there is not enough candidates or elected councilor
+ */
+async function abortCandidacies(store: DatabaseManager) {
+  const electionRound = await getCurrentElectionRound(store)
+  const candidates = await store.getMany(Candidate, {
+    where: { electionRoundId: electionRound.id, status: CandidacyStatus.ACTIVE },
+  })
+
+  await Promise.all(
+    candidates.map((candidate) => {
+      if (candidate.status === CandidacyStatus.ACTIVE) {
+        candidate.status = CandidacyStatus.FAILED
+      }
+      return store.save<Candidate>(candidate)
+    })
+  )
 }
 }
 
 
 /// /////////////// Council events /////////////////////////////////////////////
 /// /////////////// Council events /////////////////////////////////////////////
@@ -306,11 +325,11 @@ export async function council_AnnouncingPeriodStarted({ event, store }: EventCon
 
 
   // restart elections
   // restart elections
   const electedCouncil = await getCurrentElectedCouncil(store)
   const electedCouncil = await getCurrentElectedCouncil(store)
-  await startNextElectionRound(store, electedCouncil, event.blockNumber)
+  await startNextElectionRound(store, electedCouncil, event)
 }
 }
 
 
 /*
 /*
-  The event is emitted when a candidacy announcment period has ended, but not enough members announced.
+  The event is emitted when a candidacy announcement period has ended, but not enough members announced.
 */
 */
 export async function council_NotEnoughCandidates({ event, store }: EventContext & StoreContext): Promise<void> {
 export async function council_NotEnoughCandidates({ event, store }: EventContext & StoreContext): Promise<void> {
   // common event processing
   // common event processing
@@ -323,11 +342,13 @@ export async function council_NotEnoughCandidates({ event, store }: EventContext
 
 
   await store.save<NotEnoughCandidatesEvent>(notEnoughCandidatesEvent)
   await store.save<NotEnoughCandidatesEvent>(notEnoughCandidatesEvent)
 
 
+  await abortCandidacies(store)
+
   // specific event processing
   // specific event processing
 
 
   // restart elections
   // restart elections
   const electedCouncil = await getCurrentElectedCouncil(store)
   const electedCouncil = await getCurrentElectedCouncil(store)
-  await startNextElectionRound(store, electedCouncil, event.blockNumber, ElectionProblem.NOT_ENOUGH_CANDIDATES)
+  await startNextElectionRound(store, electedCouncil, event, ElectionProblem.NOT_ENOUGH_CANDIDATES)
 }
 }
 
 
 /*
 /*
@@ -376,7 +397,7 @@ export async function council_NewCandidate({ event, store }: EventContext & Stor
 
 
   const electionRound = await getCurrentElectionRound(store)
   const electionRound = await getCurrentElectionRound(store)
 
 
-  // prepare note metadata record (empty until explicitily set via different extrinsic)
+  // prepare note metadata record (empty until explicitly set via different extrinsic)
   const noteMetadata = new CandidacyNoteMetadata({
   const noteMetadata = new CandidacyNoteMetadata({
     bulletPoints: [],
     bulletPoints: [],
   })
   })
@@ -387,14 +408,13 @@ export async function council_NewCandidate({ event, store }: EventContext & Stor
     stakingAccountId: stakingAccount.toString(),
     stakingAccountId: stakingAccount.toString(),
     rewardAccountId: rewardAccount.toString(),
     rewardAccountId: rewardAccount.toString(),
     member,
     member,
-
+    status: CandidacyStatus.ACTIVE,
     electionRound,
     electionRound,
     stake: balance,
     stake: balance,
     stakeLocked: true,
     stakeLocked: true,
-    candidacyWithdrawn: false,
     votePower: new BN(0),
     votePower: new BN(0),
     noteMetadata,
     noteMetadata,
-    votesRecieved: [],
+    votesReceived: [],
   })
   })
   await store.save<Candidate>(candidate)
   await store.save<Candidate>(candidate)
 
 
@@ -422,7 +442,7 @@ export async function council_NewCouncilElected({ event, store }: EventContext &
 
 
   // specific event processing
   // specific event processing
 
 
-  // mark old council as resinged
+  // mark old council as resigned
   const oldElectedCouncil = await getCurrentElectedCouncil(store)
   const oldElectedCouncil = await getCurrentElectedCouncil(store)
   oldElectedCouncil.isResigned = true
   oldElectedCouncil.isResigned = true
   oldElectedCouncil.endedAtBlock = event.blockNumber
   oldElectedCouncil.endedAtBlock = event.blockNumber
@@ -432,16 +452,29 @@ export async function council_NewCouncilElected({ event, store }: EventContext &
 
 
   // get election round and its candidates
   // get election round and its candidates
   const electionRound = await getCurrentElectionRound(store)
   const electionRound = await getCurrentElectionRound(store)
+  const candidates = (await store.getMany(Candidate, {
+    where: { electionRoundId: electionRound.id, status: CandidacyStatus.ACTIVE },
+  })) as Array<Candidate & { memberId: string }>
 
 
-  // TODO: uncomment when following query will be working (after some QN patches make it to Olympia)
-  // const electedCandidates = await store.getMany(Candidate, { where: { electionRoundId: electionRound.id, member: { id_in: electedMemberIds } } })
-  const electedCandidates = (
-    await store.getMany(Candidate, { where: { electionRoundId: electionRound.id }, relations: ['member'] })
-  ).filter((item: Candidate) => electedMemberIds.find((tmpId) => tmpId === item.member.id.toString()))
+  const electedCandidates = candidates.filter((candidate) => electedMemberIds.includes(candidate.memberId))
+
+  // Set elected candidates status
+  electedCandidates.forEach((candidate) => {
+    candidate.status = CandidacyStatus.ELECTED
+  })
+  // Store candidates new statuses
+  await Promise.all(
+    candidates.map((candidate) => {
+      if (candidate.status === CandidacyStatus.ACTIVE) {
+        candidate.status = CandidacyStatus.FAILED
+      }
+      return store.save<Candidate>(candidate)
+    })
+  )
 
 
   // create new council record
   // create new council record
   const electedCouncil = new ElectedCouncil({
   const electedCouncil = new ElectedCouncil({
-    councilMembers: await convertCandidatesToCouncilMembers(store, electedCandidates, event.blockNumber),
+    councilMembers: await convertCandidatesToCouncilMembers(electedCandidates, event.blockNumber),
     updates: [],
     updates: [],
     electedAtBlock: event.blockNumber,
     electedAtBlock: event.blockNumber,
     electedAtTime: new Date(event.blockTimestamp),
     electedAtTime: new Date(event.blockTimestamp),
@@ -511,11 +544,13 @@ export async function council_NewCouncilNotElected({ event, store }: EventContex
 
 
   await store.save<NewCouncilNotElectedEvent>(newCouncilNotElectedEvent)
   await store.save<NewCouncilNotElectedEvent>(newCouncilNotElectedEvent)
 
 
+  await abortCandidacies(store)
+
   // specific event processing
   // specific event processing
 
 
   // restart elections
   // restart elections
   const electedCouncil = await getCurrentElectedCouncil(store)
   const electedCouncil = await getCurrentElectedCouncil(store)
-  await startNextElectionRound(store, electedCouncil, event.blockNumber, ElectionProblem.NEW_COUNCIL_NOT_ELECTED)
+  await startNextElectionRound(store, electedCouncil, event, ElectionProblem.NEW_COUNCIL_NOT_ELECTED)
 }
 }
 
 
 /*
 /*
@@ -560,7 +595,7 @@ export async function council_CandidacyWithdraw({ event, store }: EventContext &
   // specific event processing
   // specific event processing
 
 
   // mark candidacy as withdrawn
   // mark candidacy as withdrawn
-  candidate.candidacyWithdrawn = true
+  candidate.status = CandidacyStatus.WITHDRAWN
   await store.save<Candidate>(candidate)
   await store.save<Candidate>(candidate)
 }
 }
 
 
@@ -572,7 +607,7 @@ export async function council_CandidacyNoteSet({ event, store }: EventContext &
 
 
   const [memberId, note] = new Council.CandidacyNoteSetEvent(event).params
   const [memberId, note] = new Council.CandidacyNoteSetEvent(event).params
 
 
-  // load candidate recored
+  // load candidate recorded
   const electionRound = await getCurrentElectionRound(store)
   const electionRound = await getCurrentElectionRound(store)
   const candidate = await getCandidate(store, memberId.toString(), electionRound, ['noteMetadata'])
   const candidate = await getCandidate(store, memberId.toString(), electionRound, ['noteMetadata'])
 
 
@@ -739,7 +774,7 @@ export async function council_CouncilorRewardUpdated({ event, store }: EventCont
 }
 }
 
 
 /*
 /*
-  The event is emitted when funds are transfered from the council budget to an account.
+  The event is emitted when funds are transferred from the council budget to an account.
 */
 */
 export async function council_RequestFunded({ event, store }: EventContext & StoreContext): Promise<void> {
 export async function council_RequestFunded({ event, store }: EventContext & StoreContext): Promise<void> {
   // common event processing
   // common event processing

+ 13 - 4
query-node/mappings/src/membership.ts

@@ -27,6 +27,7 @@ import {
   LeaderInvitationQuotaUpdatedEvent,
   LeaderInvitationQuotaUpdatedEvent,
   MembershipEntryPaid,
   MembershipEntryPaid,
   MembershipEntryInvited,
   MembershipEntryInvited,
+  AvatarUri,
 } from 'query-node/dist/model'
 } from 'query-node/dist/model'
 
 
 async function getMemberById(store: DatabaseManager, id: MemberId): Promise<Membership> {
 async function getMemberById(store: DatabaseManager, id: MemberId): Promise<Membership> {
@@ -69,16 +70,19 @@ async function createNewMemberFromParams(
   params: BuyMembershipParameters | InviteMembershipParameters
   params: BuyMembershipParameters | InviteMembershipParameters
 ): Promise<Membership> {
 ): Promise<Membership> {
   const { defaultInviteCount } = await getLatestMembershipSystemSnapshot(store)
   const { defaultInviteCount } = await getLatestMembershipSystemSnapshot(store)
-  const { root_account: rootAccount, controller_account: controllerAccount, handle, metadata: metatadaBytes } = params
-  const metadata = deserializeMetadata(MembershipMetadata, metatadaBytes)
+  const { root_account: rootAccount, controller_account: controllerAccount, handle, metadata: metadataBytes } = params
+  const metadata = deserializeMetadata(MembershipMetadata, metadataBytes)
   const eventTime = new Date(event.blockTimestamp)
   const eventTime = new Date(event.blockTimestamp)
 
 
+  const avatar = new AvatarUri()
+  avatar.avatarUri = metadata?.avatarUri ?? ''
+
   const metadataEntity = new MemberMetadata({
   const metadataEntity = new MemberMetadata({
     createdAt: eventTime,
     createdAt: eventTime,
     updatedAt: eventTime,
     updatedAt: eventTime,
     name: metadata?.name || undefined,
     name: metadata?.name || undefined,
     about: metadata?.about || undefined,
     about: metadata?.about || undefined,
-    // TODO: avatar
+    avatar,
   })
   })
 
 
   const member = new Membership({
   const member = new Membership({
@@ -158,7 +162,12 @@ export async function members_MemberProfileUpdated({ store, event }: EventContex
     member.metadata.about = (metadata.about || null) as string | undefined
     member.metadata.about = (metadata.about || null) as string | undefined
     member.metadata.updatedAt = eventTime
     member.metadata.updatedAt = eventTime
   }
   }
-  // TODO: avatar
+
+  if (typeof metadata?.avatarUri === 'string') {
+    member.metadata.avatar = new AvatarUri()
+    member.metadata.avatar.avatarUri = metadata.avatarUri
+  }
+
   if (newHandle.isSome) {
   if (newHandle.isSome) {
     member.handle = bytesToString(newHandle.unwrap())
     member.handle = bytesToString(newHandle.unwrap())
     member.updatedAt = eventTime
     member.updatedAt = eventTime

+ 21 - 5
query-node/schemas/council.graphql

@@ -46,6 +46,13 @@ enum ElectionProblem {
   NEW_COUNCIL_NOT_ELECTED
   NEW_COUNCIL_NOT_ELECTED
 }
 }
 
 
+enum CandidacyStatus {
+  ACTIVE
+  WITHDRAWN
+  ELECTED
+  FAILED
+}
+
 type Candidate @entity {
 type Candidate @entity {
   "Account used for staking currency needed for the candidacy."
   "Account used for staking currency needed for the candidacy."
   stakingAccountId: String!
   stakingAccountId: String!
@@ -65,8 +72,8 @@ type Candidate @entity {
   "Reflects if the stake is still locked for candidacy or has been already released by the member."
   "Reflects if the stake is still locked for candidacy or has been already released by the member."
   stakeLocked: Boolean!
   stakeLocked: Boolean!
 
 
-  "Reflects if the candidacy was withdrawn before voting started."
-  candidacyWithdrawn: Boolean!
+  "Current candidate status"
+  status: CandidacyStatus!
 
 
   "Sum of power of all votes received."
   "Sum of power of all votes received."
   votePower: BigInt!
   votePower: BigInt!
@@ -80,8 +87,8 @@ type Candidate @entity {
   "The metadata contained in note."
   "The metadata contained in note."
   noteMetadata: CandidacyNoteMetadata!
   noteMetadata: CandidacyNoteMetadata!
 
 
-  "Votes recieved in referendums by this member."
-  votesRecieved: [CastVote!]! @derivedFrom(field: "voteFor")
+  "Votes received in referendums by this member."
+  votesReceived: [CastVote!]! @derivedFrom(field: "voteFor")
 }
 }
 
 
 type CouncilMember @entity {
 type CouncilMember @entity {
@@ -100,7 +107,7 @@ type CouncilMember @entity {
   "Stake used for the council membership."
   "Stake used for the council membership."
   stake: BigInt!
   stake: BigInt!
 
 
-  "Block number in which council member recieved the last reward payment."
+  "Block number in which council member received the last reward payment."
   lastPaymentBlock: BigInt!
   lastPaymentBlock: BigInt!
 
 
   "Reward amount that should have been paid but couldn't be paid off due to insufficient budget."
   "Reward amount that should have been paid but couldn't be paid off due to insufficient budget."
@@ -222,6 +229,15 @@ type ElectionRound @entity {
   "Sign if election has already finished."
   "Sign if election has already finished."
   isFinished: Boolean!
   isFinished: Boolean!
 
 
+  "Block number at which the election ended."
+  endedAtBlock: Int
+
+  "Time at which the election ended."
+  endedAtTime: DateTime
+
+  "Network running at the time the election ended."
+  endedAtNetwork: Network
+
   "Vote cast in the election round."
   "Vote cast in the election round."
   castVotes: [CastVote!]! @derivedFrom(field: "electionRound")
   castVotes: [CastVote!]! @derivedFrom(field: "electionRound")
 
 

+ 16 - 16
query-node/schemas/forumEvents.graphql

@@ -1,4 +1,4 @@
-type CategoryCreatedEvent @entity {
+type CategoryCreatedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -24,7 +24,7 @@ type CategoryCreatedEvent @entity {
   # The actor is always lead
   # The actor is always lead
 }
 }
 
 
-type CategoryArchivalStatusUpdatedEvent @entity {
+type CategoryArchivalStatusUpdatedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -54,7 +54,7 @@ type CategoryArchivalStatusUpdatedEvent @entity {
   actor: Worker!
   actor: Worker!
 }
 }
 
 
-type CategoryDeletedEvent @entity {
+type CategoryDeletedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -81,7 +81,7 @@ type CategoryDeletedEvent @entity {
   actor: Worker!
   actor: Worker!
 }
 }
 
 
-type ThreadCreatedEvent @entity {
+type ThreadCreatedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -113,7 +113,7 @@ type ThreadCreatedEvent @entity {
   # The author is already part of the Thread entity itself and is immutable
   # The author is already part of the Thread entity itself and is immutable
 }
 }
 
 
-type ThreadModeratedEvent @entity {
+type ThreadModeratedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -143,7 +143,7 @@ type ThreadModeratedEvent @entity {
   actor: Worker!
   actor: Worker!
 }
 }
 
 
-type ThreadMetadataUpdatedEvent @entity {
+type ThreadMetadataUpdatedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -172,7 +172,7 @@ type ThreadMetadataUpdatedEvent @entity {
   # Only author can update the thread title, so no actor information required
   # Only author can update the thread title, so no actor information required
 }
 }
 
 
-type ThreadDeletedEvent @entity {
+type ThreadDeletedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -198,7 +198,7 @@ type ThreadDeletedEvent @entity {
   # Only author can delete the thread, so no actor information required
   # Only author can delete the thread, so no actor information required
 }
 }
 
 
-type ThreadMovedEvent @entity {
+type ThreadMovedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -231,7 +231,7 @@ type ThreadMovedEvent @entity {
   actor: Worker!
   actor: Worker!
 }
 }
 
 
-type PostAddedEvent @entity {
+type PostAddedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -261,7 +261,7 @@ type PostAddedEvent @entity {
   text: String!
   text: String!
 }
 }
 
 
-type PostModeratedEvent @entity {
+type PostModeratedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -291,7 +291,7 @@ type PostModeratedEvent @entity {
   actor: Worker!
   actor: Worker!
 }
 }
 
 
-type PostDeletedEvent @entity {
+type PostDeletedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -321,7 +321,7 @@ type PostDeletedEvent @entity {
   rationale: String!
   rationale: String!
 }
 }
 
 
-type PostTextUpdatedEvent @entity {
+type PostTextUpdatedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -365,7 +365,7 @@ type PostReactionResultInvalid @variant {
 
 
 union PostReactionResult = PostReactionResultCancel | PostReactionResultValid | PostReactionResultInvalid
 union PostReactionResult = PostReactionResultCancel | PostReactionResultValid | PostReactionResultInvalid
 
 
-type PostReactedEvent @entity {
+type PostReactedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -395,7 +395,7 @@ type PostReactedEvent @entity {
   reactingMember: Membership!
   reactingMember: Membership!
 }
 }
 
 
-type VoteOnPollEvent @entity {
+type VoteOnPollEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -422,7 +422,7 @@ type VoteOnPollEvent @entity {
   votingMember: Membership!
   votingMember: Membership!
 }
 }
 
 
-type CategoryStickyThreadUpdateEvent @entity {
+type CategoryStickyThreadUpdateEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"
@@ -452,7 +452,7 @@ type CategoryStickyThreadUpdateEvent @entity {
   actor: Worker!
   actor: Worker!
 }
 }
 
 
-type CategoryMembershipOfModeratorUpdatedEvent @entity {
+type CategoryMembershipOfModeratorUpdatedEvent implements Event @entity {
   ### GENERIC DATA ###
   ### GENERIC DATA ###
 
 
   "(network}-{blockNumber}-{indexInBlock}"
   "(network}-{blockNumber}-{indexInBlock}"

+ 13 - 1
query-node/schemas/membership.graphql

@@ -1,9 +1,21 @@
+type AvatarObject @variant {
+  "The avatar data object"
+  avatarObject: DataObject!
+}
+
+type AvatarUri @variant {
+  "The avatar URL"
+  avatarUri: String!
+}
+
+union Avatar = AvatarObject | AvatarUri
+
 type MemberMetadata @entity {
 type MemberMetadata @entity {
   "Member's name"
   "Member's name"
   name: String
   name: String
 
 
   "Avatar data object"
   "Avatar data object"
-  avatar: DataObject
+  avatar: Avatar
 
 
   "Short text chosen by member to share information about themselves"
   "Short text chosen by member to share information about themselves"
   about: String
   about: String

File diff suppressed because it is too large
+ 529 - 366
tests/integration-tests/src/graphql/generated/schema.ts


Some files were not shown because too many files changed in this diff