diff --git a/src/services/election.ts b/src/services/election.ts index a41755e..d9e82bd 100644 --- a/src/services/election.ts +++ b/src/services/election.ts @@ -233,7 +233,9 @@ export class ElectionService extends Service implements ElectionServicePropertie title: choice.title, value: choice.value, results: this.calculateChoiceResults(electionInfo.metadata.type.name, electionInfo.result, qIndex, cIndex), + ...(choice.meta && { meta: choice.meta }), })), + ...(question.meta && { meta: question.meta }), })), resultsType: electionInfo.metadata?.type, raw: electionInfo, diff --git a/src/types/election/election.ts b/src/types/election/election.ts index 8d3a46c..d0423b4 100644 --- a/src/types/election/election.ts +++ b/src/types/election/election.ts @@ -107,7 +107,7 @@ interface JsonMap { } interface JsonArray extends Array {} -export type ElectionMeta = AnyJson | JsonArray | JsonMap; +export type CustomMeta = AnyJson | JsonArray | JsonMap; /** * Define election parameters. @@ -132,7 +132,7 @@ export interface IElectionParameters { /** * Metadata (anything added by the election creator) */ - meta?: ElectionMeta; + meta?: CustomMeta; startDate?: string | number | Date; endDate: string | number | Date; census: Census; @@ -172,7 +172,7 @@ export abstract class Election { protected _description: MultiLanguage; protected _header: string; protected _streamUri: string; - protected _meta: ElectionMeta; + protected _meta: CustomMeta; protected _startDate: Date; protected _endDate: Date; protected _electionType: IElectionType; @@ -232,7 +232,7 @@ export abstract class Election { return this._streamUri; } - get meta(): ElectionMeta { + get meta(): CustomMeta { return this._meta; } diff --git a/src/types/election/unpublished.ts b/src/types/election/unpublished.ts index fd0025f..fb87bee 100644 --- a/src/types/election/unpublished.ts +++ b/src/types/election/unpublished.ts @@ -8,7 +8,7 @@ import { } from '../metadata'; import invariant from 'tiny-invariant'; import { Census } from '../census'; -import { Election, ElectionMeta, IElectionParameters, IElectionType, IVoteType } from './election'; +import { Election, CustomMeta, IElectionParameters, IElectionType, IVoteType } from './election'; import { SDK_VERSION } from '../../version'; import { Asymmetric } from '../../util/encryption'; @@ -42,7 +42,11 @@ export class UnpublishedElection extends Election { public addQuestion( title: string | MultiLanguage, description: string | MultiLanguage, - choices: Array<{ title: string; value: number } | { title: MultiLanguage; value: number }> + choices: Array< + | { title: string; value: number; meta?: CustomMeta } + | { title: MultiLanguage; value: number; meta?: CustomMeta } + >, + meta?: CustomMeta ): UnpublishedElection { this._questions.push({ title: typeof title === 'string' ? { default: title } : title, @@ -51,8 +55,10 @@ export class UnpublishedElection extends Election { return { title: typeof choice.title === 'string' ? { default: choice.title } : choice.title, value: choice.value, + ...(choice.meta && { meta: choice.meta }), } as IChoice; }), + ...(meta && { meta: meta }), }); return this; @@ -110,10 +116,12 @@ export class UnpublishedElection extends Election { return { title: question.title, description: question.description, + meta: question.meta, choices: question.choices.map((choice) => { return { title: choice.title, value: choice.value, + meta: choice.meta, }; }), }; @@ -204,11 +212,11 @@ export class UnpublishedElection extends Election { this._streamUri = value; } - get meta(): ElectionMeta { + get meta(): CustomMeta { return super.meta; } - set meta(value: ElectionMeta) { + set meta(value: CustomMeta) { invariant(!value || value['sdk'] === undefined, 'Field `sdk` is restricted in metadata'); this._meta = value; } diff --git a/src/types/metadata/election.ts b/src/types/metadata/election.ts index d93a6ff..c86658e 100644 --- a/src/types/metadata/election.ts +++ b/src/types/metadata/election.ts @@ -1,5 +1,6 @@ import { object, array, string, number } from 'yup'; import { MultiLanguage, multiLanguageStringKeys } from '../../util/lang'; +import { CustomMeta } from '../election'; /** * Asserts that the given metadata is valid. @@ -23,6 +24,7 @@ export function checkValidElectionMetadata(electionMetadata: ElectionMetadata): export interface IChoice { title: MultiLanguage; value: number; + meta?: CustomMeta; results?: string; answer?: number; } @@ -31,6 +33,7 @@ export interface IQuestion { title: MultiLanguage; description?: MultiLanguage; numAbstains?: string; + meta?: CustomMeta; choices: Array; } diff --git a/test/integration/election.test.ts b/test/integration/election.test.ts index 1c2a39a..d10f30e 100644 --- a/test/integration/election.test.ts +++ b/test/integration/election.test.ts @@ -77,6 +77,10 @@ describe('Election integration tests', () => { }, }; + election.questions[0].meta = { image: 'https://img.io/test1.png' }; + election.questions[0].choices[0].meta = { image: 'https://img.io/test2.png' }; + election.questions[0].choices[1].meta = { image: 'https://img.io/test3.png' }; + await client.createAccount(); await client @@ -104,6 +108,9 @@ describe('Election integration tests', () => { version: SDK_VERSION, }, }); + expect(publishedElection.questions[0].meta).toStrictEqual({ image: 'https://img.io/test1.png' }); + expect(publishedElection.questions[0].choices[0].meta).toStrictEqual({ image: 'https://img.io/test2.png' }); + expect(publishedElection.questions[0].choices[1].meta).toStrictEqual({ image: 'https://img.io/test3.png' }); expect(publishedElection.get('census.type')).toEqual('spreadsheet'); expect(publishedElection.electionType).toStrictEqual({ interruptible: true,