diff --git a/client/cli/generate-permissions.ts b/client/cli/generate-permissions.ts index 8e3c84f899..6a0c6deadf 100644 --- a/client/cli/generate-permissions.ts +++ b/client/cli/generate-permissions.ts @@ -1,13 +1,12 @@ import * as fs from 'fs'; import * as yaml from 'js-yaml'; import * as path from 'path'; -import dedent from 'ts-dedent'; - import { overloadJsFunctions } from 'src/app/infrastructure/utils/overload-js-functions'; +import dedent from 'ts-dedent'; overloadJsFunctions(); -const SOURCE = path.resolve(path.join(__dirname, '../meta/permission.yml')); +const SOURCE = path.resolve(path.join(__dirname, '../../meta/permission.yml')); const BASE_PATH = path.resolve(path.join(__dirname, `..`)); const DOMAIN_DEFINITIONS_PATH = `src/app/domain/definitions`; @@ -33,21 +32,21 @@ const FILE_TEMPLATE_PERMISSION_RELATIONS = dedent` import { PermissionsMap } from './permission.config'; `; -const permissionMap: { [permission: string]: PermissionNode } = {}; +const permissionMap: Record = {}; /** * Helper class to generate the permission graph. Holds information about its permission as well as * its parents and children. */ class PermissionNode { - parents: PermissionNode[] = []; - children: PermissionNode[] = []; - permission: string; - enumKey: string; + public parents: PermissionNode[] = []; + public children: PermissionNode[] = []; + public permission: string; + public enumKey: string; public constructor(permission: string) { this.permission = permission; - this.enumKey = permission.replace(/[_\.]([a-z])/g, (_, c) => c.toUpperCase()); + this.enumKey = permission.replace(/[_.]([a-z])/g, (_, c) => c.toUpperCase()); } } @@ -137,7 +136,7 @@ function writePermissionRelations(nodes: PermissionNode[]): void { * @returns a set of all relatives of the given node in the given direction */ function getPermissionRelatives(node: PermissionNode, field: PermissionNodeRelativesField): Set { - let relatives = new Set(); + const relatives = new Set(); for (const relative of node[field]) { relatives.add(relative); relatives.update(getPermissionRelatives(relative, field)); diff --git a/client/package-lock.json b/client/package-lock.json index de0ebf566d..9e93fd0b91 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -50,6 +50,7 @@ "@tsparticles/plugin-emitters": "^3.9.1", "@tsparticles/shape-text": "^3.9.1", "@tsparticles/slim": "^3.9.1", + "big.js": "^7.0.1", "chart.js": "^4.5.1", "cm-chess": "^3.6.3", "cm-chessboard": "^8.12.11", @@ -86,6 +87,7 @@ "@angular/language-server": "^21.2.14", "@coreui/angular-chartjs": "^5.6.24", "@stylistic/eslint-plugin": "^5.10.0", + "@types/big.js": "^7.0.0", "@types/file-saver": "^2.0.7", "@types/jasmine": "~5.1.15", "@types/js-yaml": "^4.0.9", @@ -408,6 +410,40 @@ } } }, + "node_modules/@angular-devkit/architect/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/architect/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics": { "version": "21.2.12", "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.12.tgz", @@ -455,6 +491,40 @@ } } }, + "node_modules/@angular-devkit/schematics/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-eslint/builder": { "version": "21.4.0", "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.4.0.tgz", @@ -499,6 +569,40 @@ } } }, + "node_modules/@angular-eslint/builder/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-eslint/builder/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-eslint/bundled-angular-compiler": { "version": "21.2.0", "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-21.2.0.tgz", @@ -634,6 +738,40 @@ } } }, + "node_modules/@angular-eslint/schematics/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-eslint/schematics/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-eslint/template-parser": { "version": "21.4.0", "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-21.4.0.tgz", @@ -884,6 +1022,40 @@ } } }, + "node_modules/@angular/cli/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/cli/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/common": { "version": "21.2.14", "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.14.tgz", @@ -4784,6 +4956,40 @@ } } }, + "node_modules/@schematics/angular/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@schematics/angular/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sigstore/bundle": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", @@ -5957,6 +6163,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/big.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-7.0.0.tgz", + "integrity": "sha512-WfAGp7IbJvyB8EmWK4tJD24rJRAL6uVbw3LV/hJntFNam+os9KWKj0PzXo8rRRpjupYK8U0M8FoBB8dBhWF2dg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", @@ -6716,6 +6929,24 @@ "typescript": "*" } }, + "node_modules/angular-eslint/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/angular-eslint/node_modules/eslint-scope": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", @@ -6735,6 +6966,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/angular-eslint/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/angular-eslint/node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -7050,6 +7297,19 @@ "node": ">=0.6" } }, + "node_modules/big.js": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-7.0.1.tgz", + "integrity": "sha512-iFgV784tD8kq4ccF1xtNMZnXeZzVuXWWM+ERFzKQjv+A5G9HC8CY3DuV45vgzFFcW+u2tIvmF95+AzWgs6BjCg==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, "node_modules/binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", diff --git a/client/package.json b/client/package.json index 4180a9fc06..a40b52b769 100644 --- a/client/package.json +++ b/client/package.json @@ -73,6 +73,7 @@ "@tsparticles/plugin-emitters": "^3.9.1", "@tsparticles/shape-text": "^3.9.1", "@tsparticles/slim": "^3.9.1", + "big.js": "^7.0.1", "chart.js": "^4.5.1", "cm-chess": "^3.6.3", "cm-chessboard": "^8.12.11", @@ -109,6 +110,7 @@ "@angular/language-server": "^21.2.14", "@coreui/angular-chartjs": "^5.6.24", "@stylistic/eslint-plugin": "^5.10.0", + "@types/big.js": "^7.0.0", "@types/file-saver": "^2.0.7", "@types/jasmine": "~5.1.15", "@types/js-yaml": "^4.0.9", diff --git a/client/src/app/domain/definitions/permission-relations.ts b/client/src/app/domain/definitions/permission-relations.ts index 1da7f101d1..02e753edbb 100644 --- a/client/src/app/domain/definitions/permission-relations.ts +++ b/client/src/app/domain/definitions/permission-relations.ts @@ -4,13 +4,20 @@ import { PermissionsMap } from './permission.config'; export const permissionChildren: PermissionsMap = { 'agenda_item.can_manage': [Permission.agendaItemCanSeeInternal, Permission.agendaItemCanSee], + 'agenda_item.can_manage_polls': [ + Permission.agendaItemCanSeePolls, + Permission.agendaItemCanSeeInternal, + Permission.agendaItemCanSee + ], 'agenda_item.can_see': [], 'agenda_item.can_see_internal': [Permission.agendaItemCanSee], + 'agenda_item.can_see_polls': [Permission.agendaItemCanSeeInternal, Permission.agendaItemCanSee], 'assignment.can_manage': [Permission.assignmentCanNominateOther, Permission.assignmentCanSee], - 'assignment.can_manage_polls': [Permission.assignmentCanSee], + 'assignment.can_manage_polls': [Permission.assignmentCanSeePolls, Permission.assignmentCanSee], 'assignment.can_nominate_other': [Permission.assignmentCanSee], 'assignment.can_nominate_self': [Permission.assignmentCanSee], 'assignment.can_see': [], + 'assignment.can_see_polls': [Permission.assignmentCanSee], 'chat.can_manage': [], 'list_of_speakers.can_be_speaker': [], 'list_of_speakers.can_manage': [Permission.listOfSpeakersCanSee], @@ -37,12 +44,12 @@ export const permissionChildren: PermissionsMap = { Permission.motionCanForward ], 'motion.can_manage_metadata': [Permission.motionCanSee], - 'motion.can_manage_polls': [Permission.motionCanSee], + 'motion.can_manage_polls': [Permission.motionCanSeePolls, Permission.motionCanSee], 'motion.can_see': [], 'motion.can_see_internal': [Permission.motionCanSee], 'motion.can_see_origin': [Permission.motionCanSee], + 'motion.can_see_polls': [Permission.motionCanSee], 'motion.can_support': [Permission.motionCanSee], - 'poll.can_manage': [Permission.pollCanSeeProgress], 'poll.can_see_progress': [], 'projector.can_manage': [Permission.projectorCanSee], 'projector.can_see': [], @@ -62,8 +69,19 @@ export const permissionChildren: PermissionsMap = { export const permissionParents: PermissionsMap = { 'agenda_item.can_manage': [], - 'agenda_item.can_see': [Permission.agendaItemCanSeeInternal, Permission.agendaItemCanManage], - 'agenda_item.can_see_internal': [Permission.agendaItemCanManage], + 'agenda_item.can_manage_polls': [], + 'agenda_item.can_see': [ + Permission.agendaItemCanSeeInternal, + Permission.agendaItemCanManage, + Permission.agendaItemCanSeePolls, + Permission.agendaItemCanManagePolls + ], + 'agenda_item.can_see_internal': [ + Permission.agendaItemCanManage, + Permission.agendaItemCanSeePolls, + Permission.agendaItemCanManagePolls + ], + 'agenda_item.can_see_polls': [Permission.agendaItemCanManagePolls], 'assignment.can_manage': [], 'assignment.can_manage_polls': [], 'assignment.can_nominate_other': [Permission.assignmentCanManage], @@ -71,9 +89,11 @@ export const permissionParents: PermissionsMap = { 'assignment.can_see': [ Permission.assignmentCanNominateOther, Permission.assignmentCanManage, + Permission.assignmentCanSeePolls, Permission.assignmentCanManagePolls, Permission.assignmentCanNominateSelf ], + 'assignment.can_see_polls': [Permission.assignmentCanManagePolls], 'chat.can_manage': [], 'list_of_speakers.can_be_speaker': [], 'list_of_speakers.can_manage': [], @@ -101,15 +121,16 @@ export const permissionParents: PermissionsMap = { Permission.motionCanCreate, Permission.motionCanCreateAmendments, Permission.motionCanForward, + Permission.motionCanSeePolls, Permission.motionCanManagePolls, Permission.motionCanSupport, Permission.motionCanSeeOrigin ], 'motion.can_see_internal': [Permission.motionCanManage], 'motion.can_see_origin': [], + 'motion.can_see_polls': [Permission.motionCanManagePolls], 'motion.can_support': [], - 'poll.can_manage': [], - 'poll.can_see_progress': [Permission.pollCanManage], + 'poll.can_see_progress': [], 'projector.can_manage': [], 'projector.can_see': [Permission.projectorCanManage], 'tag.can_manage': [], diff --git a/client/src/app/domain/definitions/permission.config.ts b/client/src/app/domain/definitions/permission.config.ts index 4255c5d966..963f4f9af3 100644 --- a/client/src/app/domain/definitions/permission.config.ts +++ b/client/src/app/domain/definitions/permission.config.ts @@ -89,7 +89,12 @@ Optional combination of requests to speak with presence status is possible. ( > { display_name: _(`Can manage polls`), help_text: _(`Can create, change, start/stop and delete polls.`), - value: Permission.pollCanManage + value: Permission.agendaItemCanManagePolls + }, + { + display_name: _(`Can see ballot results`), + help_text: _(`Can see unpublished ballot results.`), + value: Permission.agendaItemCanSeePolls }, { display_name: _(`Can see moderation notes`), @@ -180,6 +185,11 @@ Further requirements: display_name: _(`Can manage motion polls`), help_text: _(`Can create, modify, start/stop and delete votings.`), value: Permission.motionCanManagePolls + }, + { + display_name: _(`Can see ballot results`), + help_text: _(`Can see unpublished ballot results.`), + value: Permission.motionCanSeePolls } ] }, @@ -208,6 +218,11 @@ Note: The right to vote is defined directly in the ballot.` help_text: _(`Can create, modify, start/stop and delete ballots.`), value: Permission.assignmentCanManagePolls }, + { + display_name: _(`Can see ballot results`), + help_text: _(`Can see unpublished ballot results.`), + value: Permission.assignmentCanSeePolls + }, { display_name: _(`Can nominate another participant`), help_text: _(`Can nominate other participants as candidates. @@ -335,6 +350,11 @@ Note: For privacy reasons, it is recommended to limit the rights to view the His Note: The chat menu item becomes visible to all participants, except admins, as soon as a chat has been created.`), value: Permission.chatCanManage + }, + { + display_name: _(`Can see poll progress`), + help_text: _(`Can see the progress bar of a running poll.`), + value: Permission.pollCanSeeProgress } ] } diff --git a/client/src/app/domain/definitions/permission.ts b/client/src/app/domain/definitions/permission.ts index 653a575683..86328d059f 100644 --- a/client/src/app/domain/definitions/permission.ts +++ b/client/src/app/domain/definitions/permission.ts @@ -5,13 +5,16 @@ */ export enum Permission { agendaItemCanManage = `agenda_item.can_manage`, + agendaItemCanManagePolls = `agenda_item.can_manage_polls`, agendaItemCanSee = `agenda_item.can_see`, agendaItemCanSeeInternal = `agenda_item.can_see_internal`, + agendaItemCanSeePolls = `agenda_item.can_see_polls`, assignmentCanManage = `assignment.can_manage`, assignmentCanManagePolls = `assignment.can_manage_polls`, assignmentCanNominateOther = `assignment.can_nominate_other`, assignmentCanNominateSelf = `assignment.can_nominate_self`, assignmentCanSee = `assignment.can_see`, + assignmentCanSeePolls = `assignment.can_see_polls`, chatCanManage = `chat.can_manage`, listOfSpeakersCanBeSpeaker = `list_of_speakers.can_be_speaker`, listOfSpeakersCanManage = `list_of_speakers.can_manage`, @@ -35,8 +38,8 @@ export enum Permission { motionCanSee = `motion.can_see`, motionCanSeeInternal = `motion.can_see_internal`, motionCanSeeOrigin = `motion.can_see_origin`, + motionCanSeePolls = `motion.can_see_polls`, motionCanSupport = `motion.can_support`, - pollCanManage = `poll.can_manage`, pollCanSeeProgress = `poll.can_see_progress`, projectorCanManage = `projector.can_manage`, projectorCanSee = `projector.can_see`, diff --git a/client/src/app/domain/models/meeting-users/meeting-user.ts b/client/src/app/domain/models/meeting-users/meeting-user.ts index 2d2b26aaea..0aa6de914e 100644 --- a/client/src/app/domain/models/meeting-users/meeting-user.ts +++ b/client/src/app/domain/models/meeting-users/meeting-user.ts @@ -18,14 +18,16 @@ export class MeetingUser extends BaseDecimalModel { public vote_delegated_to_id!: Id; // meeting_user/vote_delegations_from_ids; + public poll_voted_ids: Id[]; public group_ids!: Id[]; // (group/meeting_user_ids)[]; public speaker_ids!: Id[]; // (speaker/meeting_user_id)[]; public personal_note_ids!: Id[]; // (personal_note/meeting_user_id)[]; public motion_supporter_ids!: Id[]; // (motion_supporter/meeting_user_id); public submitted_motion_ids!: Id[]; // (motion_submitter/meeting_user_id)[]; public assignment_candidate_ids!: Id[]; // (assignment_candidate/meeting_user_id)[]; - public vote_delegated_vote_ids!: Id[]; public vote_delegations_from_ids!: Id[]; // meeting_user/vote_delegated_to_id; + public acting_ballot_ids: Id[]; + public represented_ballot_ids: Id[]; public chat_message_ids!: Id[]; // (chat_message/meeting_user_id)[]; public structure_level_ids!: Id[]; // structure_level/meeting_user_ids @@ -52,6 +54,9 @@ export class MeetingUser extends BaseDecimalModel { `assignment_candidate_ids`, `vote_delegated_to_id`, `vote_delegations_from_ids`, + `poll_voted_ids`, + `acting_ballot_ids`, + `represented_ballot_ids`, `chat_message_ids`, `group_ids`, `structure_level_ids` diff --git a/client/src/app/domain/models/meetings/meeting.ts b/client/src/app/domain/models/meetings/meeting.ts index f88342a09d..26ad9c2d0c 100644 --- a/client/src/app/domain/models/meetings/meeting.ts +++ b/client/src/app/domain/models/meetings/meeting.ts @@ -4,7 +4,8 @@ import { HasProperties } from '../../interfaces/has-properties'; import { AgendaItemCreation, AgendaItemType } from '../agenda/agenda-item'; import { BaseModel } from '../base/base-model'; import { ChangeRecoMode, LineNumberingMode } from '../motions/motions.constants'; -import { PollBackendDurationType, PollMethod, PollPercentBase, PollType } from '../poll/poll-constants'; +import { PollVisibility } from '../poll'; +import { BaseOnehundredPercentBase } from '../poll/poll-config-types'; import { ApplauseType } from './applause'; import { BallotPaperSelection, @@ -147,11 +148,9 @@ export class Settings { public motion_poll_ballot_paper_selection!: BallotPaperSelection; public motion_poll_ballot_paper_number!: number; - public motion_poll_default_type!: PollType; - public motion_poll_default_onehundred_percent_base!: PollPercentBase; + public motion_poll_default_type!: PollVisibility; + public motion_poll_default_onehundred_percent_base!: BaseOnehundredPercentBase; public motion_poll_default_group_ids!: Id[]; // (group/used_as_motion_poll_default_id)[]; - public motion_poll_default_backend!: PollBackendDurationType; - public motion_poll_default_method!: PollMethod; public motion_poll_projection_name_order_first!: `first_name` | `last_name`; public motion_poll_projection_max_columns!: number; @@ -183,11 +182,9 @@ export class Settings { public assignment_poll_add_candidates_to_list_of_speakers!: boolean; public assignment_poll_enable_max_votes_per_option!: boolean; public assignment_poll_sort_poll_result_by_votes!: boolean; - public assignment_poll_default_type!: PollType; - public assignment_poll_default_method!: PollMethod; - public assignment_poll_default_onehundred_percent_base!: PollPercentBase; + public assignment_poll_default_type!: PollVisibility; + public assignment_poll_default_onehundred_percent_base!: BaseOnehundredPercentBase; public assignment_poll_default_group_ids!: Id[]; // (group/used_as_assignment_poll_default_id)[]; - public assignment_poll_default_backend!: PollBackendDurationType; // topic poll public topic_poll_default_group_ids: Id[]; // (group/used_as_poll_default_id)[]; @@ -196,11 +193,9 @@ export class Settings { public poll_ballot_paper_selection: BallotPaperSelection; public poll_ballot_paper_number: number; public poll_sort_poll_result_by_votes: boolean; - public poll_default_type: PollType; - public poll_default_method: PollMethod; - public poll_default_onehundred_percent_base: PollPercentBase; + public poll_default_type: PollVisibility; + public poll_default_onehundred_percent_base: BaseOnehundredPercentBase; public poll_default_group_ids: Id[]; // (group/used_as_poll_default_id)[]; - public poll_default_backend: PollBackendDurationType; public poll_default_live_voting_enabled: boolean; // SSO @@ -414,14 +409,10 @@ export class Meeting extends BaseModel { `motion_poll_ballot_paper_selection`, `motion_poll_ballot_paper_number`, `motion_poll_default_type`, - `motion_poll_default_method`, `motion_poll_default_onehundred_percent_base`, `motion_poll_default_group_ids`, - `motion_poll_default_backend`, `motion_poll_projection_name_order_first`, `motion_poll_projection_max_columns`, - `poll_candidate_list_ids`, - `poll_candidate_ids`, `meeting_user_ids`, `users_enable_presence_view`, `users_enable_vote_weight`, @@ -448,18 +439,14 @@ export class Meeting extends BaseModel { `assignment_poll_enable_max_votes_per_option`, `assignment_poll_sort_poll_result_by_votes`, `assignment_poll_default_type`, - `assignment_poll_default_method`, `assignment_poll_default_onehundred_percent_base`, `assignment_poll_default_group_ids`, - `assignment_poll_default_backend`, `poll_ballot_paper_selection`, `poll_ballot_paper_number`, `poll_sort_poll_result_by_votes`, `poll_default_type`, - `poll_default_method`, `poll_default_onehundred_percent_base`, `poll_default_group_ids`, - `poll_default_backend`, `poll_default_live_voting_enabled`, `topic_poll_default_group_ids`, `projector_ids`, @@ -490,8 +477,6 @@ export class Meeting extends BaseModel { `motion_change_recommendation_ids`, `motion_state_ids`, `poll_ids`, - `option_ids`, - `vote_ids`, `assignment_ids`, `assignment_candidate_ids`, `personal_note_ids`, diff --git a/client/src/app/domain/models/poll-candidate-lists/poll-candidate-list.ts b/client/src/app/domain/models/poll-candidate-lists/poll-candidate-list.ts deleted file mode 100644 index fbfeff3909..0000000000 --- a/client/src/app/domain/models/poll-candidate-lists/poll-candidate-list.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Id } from '../../definitions/key-types'; -import { HasMeetingId } from '../../interfaces'; -import { BaseModel } from '../base/base-model'; - -export class PollCandidateList extends BaseModel { - public static COLLECTION = `poll_candidate_list`; - - public option_id!: Id; // option/content_object_id; - public poll_candidate_ids!: Id[]; // poll_candidate/poll_candidate_list_id; - - public constructor(input?: any) { - super(PollCandidateList.COLLECTION, input); - } - - public static readonly REQUESTABLE_FIELDS: (keyof PollCandidateList)[] = [ - `id`, - `poll_candidate_ids`, - `meeting_id`, - `option_id` - ]; -} -export interface PollCandidateList extends HasMeetingId {} diff --git a/client/src/app/domain/models/poll-candidate-lists/poll-candidate.ts b/client/src/app/domain/models/poll-candidate-lists/poll-candidate.ts deleted file mode 100644 index 5b879d2774..0000000000 --- a/client/src/app/domain/models/poll-candidate-lists/poll-candidate.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Id } from '../../definitions/key-types'; -import { HasMeetingId } from '../../interfaces'; -import { BaseModel } from '../base/base-model'; - -export class PollCandidate extends BaseModel { - public static COLLECTION = `poll_candidate`; - - public weight!: number; - - public poll_candidate_list_id!: Id; // poll_candidate_list/poll_candidate_ids; - public user_id!: Id; // user/poll_candidate_ids; - - public constructor(input?: any) { - super(PollCandidate.COLLECTION, input); - } - - public static readonly REQUESTABLE_FIELDS: (keyof PollCandidate)[] = [ - `id`, - `poll_candidate_list_id`, - `user_id`, - `weight`, - `meeting_id` - ]; -} -export interface PollCandidate extends HasMeetingId {} diff --git a/client/src/app/domain/models/poll/base-poll-config.ts b/client/src/app/domain/models/poll/base-poll-config.ts new file mode 100644 index 0000000000..0b4fa7c023 --- /dev/null +++ b/client/src/app/domain/models/poll/base-poll-config.ts @@ -0,0 +1,6 @@ +import { Id } from '../../definitions/key-types'; +import { BaseModel } from '../base/base-model'; + +export abstract class BasePollConfigModel extends BaseModel { + public poll_id!: Id; +} diff --git a/client/src/app/domain/models/poll/generic-poll.ts b/client/src/app/domain/models/poll/generic-poll.ts index b35cdefc33..55cb09439a 100644 --- a/client/src/app/domain/models/poll/generic-poll.ts +++ b/client/src/app/domain/models/poll/generic-poll.ts @@ -1,11 +1,7 @@ -import { Observable } from 'rxjs'; import { ViewTopic } from 'src/app/site/pages/meetings/pages/agenda'; import { ViewAssignment } from 'src/app/site/pages/meetings/pages/assignments'; import { ViewMotion } from 'src/app/site/pages/meetings/pages/motions'; -import { ViewPollCandidateList } from 'src/app/site/pages/meetings/pages/polls/view-models/view-poll-candidate-list'; -import { ViewUser } from 'src/app/site/pages/meetings/view-models/view-user'; - -import { EntitledUsersEntry, PollClassType, PollMethod, PollPercentBase, PollState, PollType } from './poll-constants'; +import { ViewMeetingUser } from 'src/app/site/pages/meetings/view-models/view-meeting-user'; export type PollContentObject = ViewAssignment | ViewMotion | ViewTopic; @@ -14,27 +10,6 @@ export type PollContentObject = ViewAssignment | ViewMotion | ViewTopic; * This is a unification of the data received in the projector and ViewPoll; both * use this interface, so the poll services can work on this shared view on the data. */ -export interface PollData { - pollClassType?: PollClassType; - pollmethod: PollMethod; - state: PollState; - onehundred_percent_base: PollPercentBase; - votesvalid: number; - votesinvalid: number; - votescast: number; - type: PollType; - entitled_users_at_stop: EntitledUsersEntry[]; - options: OptionData[]; - options$: Observable; - global_option: OptionData; - global_yes?: boolean; - global_no?: boolean; - global_abstain?: boolean; - content_object?: PollContentObject; - getContentObjectTitle: () => string | null; -} - -export type PollDataKey = keyof PollData; export interface OptionTitle { title: string; @@ -53,7 +28,8 @@ export interface OptionData { amount_global_yes?: number; amount_global_no?: number; amount_global_abstain?: number; - content_object?: ViewUser | ViewMotion | ViewPollCandidateList; + meeting_user?: ViewMeetingUser; + text?: string; entries_amount?: number; } diff --git a/client/src/app/domain/models/poll/index.ts b/client/src/app/domain/models/poll/index.ts index 316a36a5fe..0ce0695181 100644 --- a/client/src/app/domain/models/poll/index.ts +++ b/client/src/app/domain/models/poll/index.ts @@ -1,6 +1,5 @@ export * from './generic-poll'; -export * from './option'; export * from './poll'; +export * from './poll-ballot'; export * from './poll-constants'; -export * from './vote'; export * from './vote-constants'; diff --git a/client/src/app/domain/models/poll/option.ts b/client/src/app/domain/models/poll/option.ts deleted file mode 100644 index afd8cd32dc..0000000000 --- a/client/src/app/domain/models/poll/option.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Fqid, Id, Ids } from '../../definitions/key-types'; -import { BaseDecimalModel } from '../base/base-decimal-model'; - -export class Option extends BaseDecimalModel