diff --git a/client/src/app/domain/fieldsets/user.ts b/client/src/app/domain/fieldsets/user.ts index 86a1f229fc..d318b577dc 100644 --- a/client/src/app/domain/fieldsets/user.ts +++ b/client/src/app/domain/fieldsets/user.ts @@ -15,3 +15,9 @@ export class UserFieldsets { ] }; } + +export class MeetingUserFieldsets { + public static readonly FullNameSubscription: BaseSimplifiedModelRequest = { + fieldset: [`group_ids`, `meeting_id`, `user_id`, `structure_level`, `number`] + }; +} diff --git a/client/src/app/domain/models/users/user.ts b/client/src/app/domain/models/users/user.ts index 7380202f12..1eb9d59637 100644 --- a/client/src/app/domain/models/users/user.ts +++ b/client/src/app/domain/models/users/user.ts @@ -12,6 +12,7 @@ export type UserSortProperty = 'first_name' | 'last_name' | 'number'; * Iterable pre selection of genders */ export const GENDERS = [_(`female`), _(`male`), _(`diverse`), _(`non-binary`)]; +export const GENDER_FITLERABLE = [`female`, `male`, `diverse`, `non-binary`]; /** * Representation of a user in contrast to the operator. diff --git a/client/src/app/gateways/export/csv-export.service/csv-export-for-backend.service.ts b/client/src/app/gateways/export/csv-export.service/csv-export-for-backend.service.ts index 479d2010ae..a85ec745d0 100644 --- a/client/src/app/gateways/export/csv-export.service/csv-export-for-backend.service.ts +++ b/client/src/app/gateways/export/csv-export.service/csv-export-for-backend.service.ts @@ -4,7 +4,7 @@ import { BaseViewModel } from 'src/app/site/base/base-view-model'; import { ExportServiceModule } from '../export-service.module'; import { FileExportService } from '../file-export.service'; import { - CsvColumnsDefinition, + BackendCsvColumnsDefinition, DEFAULT_COLUMN_SEPARATOR, DEFAULT_ENCODING, DEFAULT_LINE_SEPARATOR, @@ -30,7 +30,7 @@ export class CsvExportForBackendService { */ public export( models: T[], - columns: CsvColumnsDefinition, + columns: BackendCsvColumnsDefinition, filename: string, { lineSeparator = DEFAULT_LINE_SEPARATOR, @@ -54,7 +54,7 @@ export class CsvExportForBackendService { const header = columns.map(column => { let label = ``; if (isPropertyDefinition(column)) { - label = column.label ? column.label : (column.property as string); + label = column.property as string; } else if (isMapDefinition(column)) { label = column.label; } diff --git a/client/src/app/gateways/export/csv-export.service/csv-export-utils.ts b/client/src/app/gateways/export/csv-export.service/csv-export-utils.ts index 8048796dca..fee0e09cae 100644 --- a/client/src/app/gateways/export/csv-export.service/csv-export-utils.ts +++ b/client/src/app/gateways/export/csv-export.service/csv-export-utils.ts @@ -1,3 +1,11 @@ +/** + * Defines a csv column with a property of the model and an optional label. If this is not given, the + * translated and capitalized property name is used. + */ +export interface BackendCsvColumnDefinitionProperty { + property: keyof T; +} + /** * Defines a csv column with a property of the model and an optional label. If this is not given, the * translated and capitalized property name is used. @@ -44,6 +52,12 @@ export function isMapDefinition(obj: any): obj is CsvColumnDefinitionMap { */ export type CsvColumnsDefinition = (CsvColumnDefinitionProperty | CsvColumnDefinitionMap)[]; +/** + * The definition of columns in the export. Either use a property for every model or do a custom mapping to + * a string to be put into the csv. + */ +export type BackendCsvColumnsDefinition = (BackendCsvColumnDefinitionProperty | CsvColumnDefinitionMap)[]; + export const ISO_8859_15_ENCODING = `iso-8859-15`; export const DEFAULT_LINE_SEPARATOR = `\r\n`; export const DEFAULT_COLUMN_SEPARATOR = `,`; diff --git a/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts b/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts index aa9eb0a820..216e90e2a5 100644 --- a/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts +++ b/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts @@ -27,10 +27,10 @@ export class MeetingUserRepositoryService extends BaseMeetingRelatedRepository = [`about_me`, `user_id`, `meeting_id`]; diff --git a/client/src/app/gateways/repositories/users/user-action.ts b/client/src/app/gateways/repositories/users/user-action.ts index 556516417e..750f45c89a 100644 --- a/client/src/app/gateways/repositories/users/user-action.ts +++ b/client/src/app/gateways/repositories/users/user-action.ts @@ -14,4 +14,6 @@ export class UserAction { public static readonly FORGET_PASSWORD_CONFIRM = `user.forget_password_confirm`; public static readonly ASSIGN_MEETINGS = `user.assign_meetings`; public static readonly MERGE_TOGETHER = `user.merge_together`; + public static readonly ACCOUNT_JSON_UPLOAD = `account.json_upload`; + public static readonly ACCOUNT_IMPORT = `account.import`; } diff --git a/client/src/app/gateways/repositories/users/user-repository.service.ts b/client/src/app/gateways/repositories/users/user-repository.service.ts index fa5014b82c..748a7e1132 100644 --- a/client/src/app/gateways/repositories/users/user-repository.service.ts +++ b/client/src/app/gateways/repositories/users/user-repository.service.ts @@ -5,6 +5,7 @@ import { BaseRepository } from 'src/app/gateways/repositories/base-repository'; import { UserAction } from 'src/app/gateways/repositories/users/user-action'; import { ActiveMeetingIdService } from 'src/app/site/pages/meetings/services/active-meeting-id.service'; import { ViewMeetingUser } from 'src/app/site/pages/meetings/view-models/view-meeting-user'; +import { BackendImportRawPreview } from 'src/app/ui/modules/import-list/definitions/backend-import-preview'; import { Id } from '../../../domain/definitions/key-types'; import { Displayable } from '../../../domain/interfaces/displayable'; @@ -497,6 +498,14 @@ export class UserRepositoryService extends BaseRepository { return this.createAction(UserAction.SET_PRESENT, payload); } + public accountJsonUpload(payload: { [key: string]: any }): Action { + return this.createAction(UserAction.ACCOUNT_JSON_UPLOAD, payload); + } + + public accountImport(payload: { id: number; import: boolean }[]): Action { + return this.createAction(UserAction.ACCOUNT_IMPORT, payload); + } + private sanitizePayload(payload: any): any { const temp = { ...payload }; for (const key of Object.keys(temp).filter(field => !this.isFieldAllowedToBeEmpty(field))) { diff --git a/client/src/app/site/base/base-import.service/base-backend-import.service.ts b/client/src/app/site/base/base-import.service/base-backend-import.service.ts index d1ebe5d206..6d68324a19 100644 --- a/client/src/app/site/base/base-import.service/base-backend-import.service.ts +++ b/client/src/app/site/base/base-import.service/base-backend-import.service.ts @@ -282,15 +282,24 @@ export abstract class BaseBackendImportService implements BackendImportService { isBackendImportRawPreview(result) ) as BackendImportRawPreview[]; this.processRawPreviews(updatedPreviews); - if (this.previewHasRowErrors) { + const statesSet = new Set(updatedPreviews.map(preview => preview.state)); + if (statesSet.has(BackendImportState.Error)) { this._currentImportPhaseSubject.next(BackendImportPhase.ERROR); + } else if (statesSet.has(BackendImportState.Warning)) { + this.processRawPreviews( + updatedPreviews + .filter(preview => preview.state === BackendImportState.Warning) + .map(preview => ({ + ...preview, + rows: preview.rows.filter(row => row.messages && row.messages.length) + })) + ); + this._currentImportPhaseSubject.next(BackendImportPhase.FINISHED_WITH_WARNING); } else { - this._currentImportPhaseSubject.next(BackendImportPhase.TRY_AGAIN); + this._currentImportPhaseSubject.next(BackendImportPhase.FINISHED); + this._csvLines = []; + return true; } - } else { - this._currentImportPhaseSubject.next(BackendImportPhase.FINISHED); - this._csvLines = []; - return true; } return false; } diff --git a/client/src/app/site/base/base-via-backend-import-list.component.ts b/client/src/app/site/base/base-via-backend-import-list.component.ts index b9ba3eb7f0..b11d1c39f4 100644 --- a/client/src/app/site/base/base-via-backend-import-list.component.ts +++ b/client/src/app/site/base/base-via-backend-import-list.component.ts @@ -29,7 +29,7 @@ export abstract class BaseViaBackendImportListComponent extends BaseComponent im * True if the import is in a state in which an import can be conducted */ public get canImport(): boolean { - return this._state === BackendImportPhase.AWAITING_CONFIRM || this.tryAgain; + return this._state === BackendImportPhase.AWAITING_CONFIRM; } /** @@ -42,8 +42,8 @@ export abstract class BaseViaBackendImportListComponent extends BaseComponent im /** * True if, after an attempted import failed, the view is waiting for the user to confirm the import on the new preview. */ - public get tryAgain(): boolean { - return this._state === BackendImportPhase.TRY_AGAIN; + public get finishedWithWarnings(): boolean { + return this._state === BackendImportPhase.FINISHED_WITH_WARNING; } /** diff --git a/client/src/app/site/modules/global-headbar/components/account-button/account-button.component.ts b/client/src/app/site/modules/global-headbar/components/account-button/account-button.component.ts index 3ae5da4c3d..52a03eb124 100644 --- a/client/src/app/site/modules/global-headbar/components/account-button/account-button.component.ts +++ b/client/src/app/site/modules/global-headbar/components/account-button/account-button.component.ts @@ -1,5 +1,8 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; +import { + MatLegacyDialog as MatDialog, + MatLegacyDialogConfig as MatDialogConfig +} from '@angular/material/legacy-dialog'; import { MatLegacyMenuTrigger as MatMenuTrigger } from '@angular/material/legacy-menu'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; @@ -18,6 +21,7 @@ import { ThemeService } from 'src/app/site/services/theme.service'; import { UserControllerService } from 'src/app/site/services/user-controller.service'; import { BaseUiComponent } from 'src/app/ui/base/base-ui-component'; import { ChessDialogComponent } from 'src/app/ui/modules/sidenav/modules/easter-egg/modules/chess-dialog/components/chess-dialog/chess-dialog.component'; +import { ChessChallengeService } from 'src/app/ui/modules/sidenav/modules/easter-egg/modules/chess-dialog/services/chess-challenge.service'; import { AccountDialogComponent } from '../account-dialog/account-dialog.component'; @@ -81,9 +85,11 @@ export class AccountButtonComponent extends BaseUiComponent implements OnInit { private theme: ThemeService, private meetingSettingsService: MeetingSettingsService, private activeMeetingIdService: ActiveMeetingIdService, - private controller: UserControllerService + private controller: UserControllerService, + chessChallengeService: ChessChallengeService ) { super(); + chessChallengeService.startListening(); } public ngOnInit(): void { @@ -159,7 +165,12 @@ export class AccountButtonComponent extends BaseUiComponent implements OnInit { if (this.clickCounter === 4) { this.clickCounter = 0; - this.dialog.open(ChessDialogComponent, { ...mediumDialogSettings }); + const config: MatDialogConfig = mediumDialogSettings; + const match = this.router.url.match(/.*\/participants\/(\d+)\/?$/); + if (match) { + config.data = { userId: +match[1] }; + } + this.dialog.open(ChessDialogComponent, config); } else { this.clickTimeout = setTimeout(() => { this.clickCounter = 0; diff --git a/client/src/app/site/modules/global-headbar/global-headbar.module.ts b/client/src/app/site/modules/global-headbar/global-headbar.module.ts index 1e0b993ce5..d3a0ed0362 100644 --- a/client/src/app/site/modules/global-headbar/global-headbar.module.ts +++ b/client/src/app/site/modules/global-headbar/global-headbar.module.ts @@ -19,6 +19,7 @@ import { RouterModule } from '@angular/router'; import { DirectivesModule } from 'src/app/ui/directives'; import { CommaSeparatedListingModule } from 'src/app/ui/modules/comma-separated-listing'; import { InputModule } from 'src/app/ui/modules/input'; +import { ChessDialogModule } from 'src/app/ui/modules/sidenav/modules/easter-egg/modules/chess-dialog'; import { OpenSlidesTranslationModule } from '../translations'; import { UserComponentsModule } from '../user-components'; @@ -58,6 +59,7 @@ const DECLARATIONS = [GlobalHeadbarComponent]; ScrollingModule, FormsModule, ReactiveFormsModule, + ChessDialogModule, ...MODULES ] }) diff --git a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts index 369b49280b..22d7ca09c8 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts @@ -1,6 +1,6 @@ import { Id } from 'src/app/domain/definitions/key-types'; import { FULL_FIELDSET, MEETING_ROUTING_FIELDS } from 'src/app/domain/fieldsets/misc'; -import { UserFieldsets } from 'src/app/domain/fieldsets/user'; +import { MeetingUserFieldsets, UserFieldsets } from 'src/app/domain/fieldsets/user'; import { SubscriptionConfigGenerator } from 'src/app/domain/interfaces/subscription-config'; import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting'; import { FollowList } from 'src/app/site/services/model-request-builder'; @@ -21,13 +21,13 @@ export const agendaItemFollow: FollowList = [ follow: [ { idField: `meeting_user_id`, - fieldset: [], follow: [ { idField: `user_id`, - ...UserFieldsets.FullNameSubscription + fieldset: [...UserFieldsets.FullNameSubscription.fieldset, `meeting_user_ids`] } - ] + ], + ...MeetingUserFieldsets.FullNameSubscription }, { idField: `point_of_order_category_id`, diff --git a/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-import/components/topic-import/topic-import.component.html b/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-import/components/topic-import/topic-import.component.html index 5e9b79a31b..a2093e0426 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-import/components/topic-import/topic-import.component.html +++ b/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-import/components/topic-import/topic-import.component.html @@ -6,10 +6,16 @@

{{ 'Import topics' | translate }}