diff --git a/client/src/app/base.component.ts b/client/src/app/base.component.ts index 61cb9c853..6288dbda5 100644 --- a/client/src/app/base.component.ts +++ b/client/src/app/base.component.ts @@ -58,7 +58,6 @@ export abstract class BaseComponent { /** * Set the title in web browser using angulars TitleService * @param prefix The title prefix. Should be translated here. - * TODO Might translate the prefix here? */ public setTitle(prefix: string): void { const translatedPrefix = this.translate.instant(prefix); diff --git a/client/src/app/core/core-services/storage.service.ts b/client/src/app/core/core-services/storage.service.ts index 39611324f..bba7830c9 100644 --- a/client/src/app/core/core-services/storage.service.ts +++ b/client/src/app/core/core-services/storage.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { LocalStorage } from '@ngx-pwa/local-storage'; +import { Observable } from 'rxjs'; import { OpenSlidesStatusService } from './openslides-status.service'; import { StoragelockService } from '../local-storage/storagelock.service'; @@ -31,7 +32,7 @@ export class StorageService { public async set(key: string, item: any): Promise { await this.lock.promise; - this.assertNotHistroyMode(); + this.assertNotHistoryMode(); if (item === null || item === undefined) { await this.remove(key); // You cannot do a setItem with null or undefined... } else { @@ -44,16 +45,13 @@ export class StorageService { /** * get a value from the store. You need to subscribe to the request to retrieve the value. * - * TODO: This needs adjustment to ensure safe access. - * Since angular 7 `LocalStorrage.getItem` will return "unknown" instead of any. - * https://github.com/cyrilletuzi/angular-async-local-storage/blob/master/docs/MIGRATION_TO_V7.md * @param key The key to get the value from * @returns The requested value to the key */ public async get(key: string): Promise { await this.lock.promise; - return await this.localStorage.getUnsafeItem(key).toPromise(); + return ((await this.localStorage.getItem(key)) as Observable).toPromise(); } /** @@ -63,7 +61,7 @@ export class StorageService { public async remove(key: string): Promise { await this.lock.promise; - this.assertNotHistroyMode(); + this.assertNotHistoryMode(); if (!(await this.localStorage.removeItem(key).toPromise())) { throw new Error('Could not delete the item.'); } @@ -75,7 +73,7 @@ export class StorageService { public async clear(): Promise { await this.lock.promise; - this.assertNotHistroyMode(); + this.assertNotHistoryMode(); if (!(await this.localStorage.clear().toPromise())) { throw new Error('Could not clear the storage.'); } @@ -84,7 +82,7 @@ export class StorageService { /** * Throws an error, if we are in history mode. */ - private assertNotHistroyMode(): void { + private assertNotHistoryMode(): void { if (this.OSStatus.isInHistoryMode) { throw new Error('You cannot use the storageService in histroy mode.'); } diff --git a/client/src/app/core/repositories/motions/motion-block-repository.service.ts b/client/src/app/core/repositories/motions/motion-block-repository.service.ts index 028e035a8..c8085bddf 100644 --- a/client/src/app/core/repositories/motions/motion-block-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-block-repository.service.ts @@ -109,12 +109,13 @@ export class MotionBlockRepositoryService extends BaseAgendaContentObjectReposit } /** - * Retrieves motion block(s) by name - * TODO: check if a title is unique for a motionBlock - * @param title Strign to check for + * Retrieves motion blocks by name + * + * @param title String to check for + * @returns the motion blocks found */ - public getMotionBlockByTitle(title: string): MotionBlock { - return this.DS.find(MotionBlock, block => block.title === title); + public getMotionBlocksByTitle(title: string): MotionBlock[] { + return this.DS.filter(MotionBlock, block => block.title === title); } /** diff --git a/client/src/app/core/repositories/users/user-repository.service.ts b/client/src/app/core/repositories/users/user-repository.service.ts index 6d2423dbe..998aacbc1 100644 --- a/client/src/app/core/repositories/users/user-repository.service.ts +++ b/client/src/app/core/repositories/users/user-repository.service.ts @@ -265,14 +265,18 @@ export class UserRepositoryService extends BaseRepository { } /** - * Tries to convert a user string into an user. If it is two words, expect - * a first and a last name, if one word only, expect a first name only. - * If more than two words, they will all be put as the first name - * TODO: More advanced logic to fit names + * Tries to convert a user string into an user. Names that don't fit the scheme given + * will be entered into the first_name field + * + * Naming schemes are: + * - firstSpaceLast: One or two space-separated words are assumed, matching + * given name and surname + * - lastCommaFirst: A comma is supposed to separate last name(s) from given name(s). + * TODO: More advanced logic(s) to fit names * * @param inputUser A raw user string - * @param schema optional hint on how to handle the strings. TODO: Not fully implemented. - * @returns A User object (not uploaded to the server) + * @param schema optional hint on how to handle the strings. + * @returns A User object (note: is only a local object, not uploaded to the server) */ public parseUserString(inputUser: string, schema?: StringNamingSchema): User { const newUser: Partial = {}; diff --git a/client/src/app/core/ui-services/base-filter-list.service.ts b/client/src/app/core/ui-services/base-filter-list.service.ts index 0f3d67d73..26c2fc122 100644 --- a/client/src/app/core/ui-services/base-filter-list.service.ts +++ b/client/src/app/core/ui-services/base-filter-list.service.ts @@ -1,10 +1,10 @@ import { auditTime } from 'rxjs/operators'; import { BehaviorSubject, Observable } from 'rxjs'; +import { BaseRepository } from 'app/core/repositories/base-repository'; import { BaseModel } from '../../shared/models/base/base-model'; import { BaseViewModel } from '../../site/base/base-view-model'; import { StorageService } from '../core-services/storage.service'; -import { BaseRepository } from '../repositories/base-repository'; /** * Describes the available filters for a listView. @@ -46,7 +46,7 @@ export interface OsFilterOption { * and will receive their filtered data as observable */ -export abstract class BaseFilterListService { +export abstract class BaseFilterListService { /** * stores the currently used raw data to be used for the filter */ @@ -110,7 +110,7 @@ export abstract class BaseFilterListService) {} + public constructor(private store: StorageService, private repo: BaseRepository) {} /** * Initializes the filterService. Returns the filtered data as Observable diff --git a/client/src/app/core/ui-services/base-import.service.ts b/client/src/app/core/ui-services/base-import.service.ts index 9b06faf72..ad8b2bd27 100644 --- a/client/src/app/core/ui-services/base-import.service.ts +++ b/client/src/app/core/ui-services/base-import.service.ts @@ -8,13 +8,16 @@ import { BaseViewModel } from 'app/site/base/base-view-model'; /** * Interface for value- Label combinations. - * Map objects didn't work, TODO: Use map objects (needs iterating through all objects of a map) */ export interface ValueLabelCombination { value: string; label: string; } +interface FileReaderProgressEvent extends ProgressEvent { + readonly target: FileReader | null; +} + /** * Interface matching a newly created entry with their duplicates and an import status */ @@ -168,10 +171,8 @@ export abstract class BaseImportService { * @param matSnackBar snackBar to display import errors */ public constructor(protected translate: TranslateService, private papa: Papa, protected matSnackbar: MatSnackBar) { - this.reader.onload = (event: any) => { - // TODO type: event is a progressEvent, - // but has a property target.result, which typescript doesn't recognize - this.parseInput(event.target.result); + this.reader.onload = (event: FileReaderProgressEvent) => { + this.parseInput(event.target.result as string); }; } diff --git a/client/src/app/shared/components/os-sort-filter-bar/filter-menu/filter-menu.component.ts b/client/src/app/shared/components/os-sort-filter-bar/filter-menu/filter-menu.component.ts index d448c7836..49de3d602 100644 --- a/client/src/app/shared/components/os-sort-filter-bar/filter-menu/filter-menu.component.ts +++ b/client/src/app/shared/components/os-sort-filter-bar/filter-menu/filter-menu.component.ts @@ -1,6 +1,7 @@ import { Output, Component, OnInit, EventEmitter, Input } from '@angular/core'; import { BaseFilterListService, OsFilterOption } from 'app/core/ui-services/base-filter-list.service'; +import { BaseViewModel } from 'app/site/base/base-view-model'; /** * Component for selecting the filters in a filter menu. @@ -31,7 +32,7 @@ export class FilterMenuComponent implements OnInit { * the FilterListService; unsure about how to get them in any other way. */ @Input() - public service: BaseFilterListService; // TODO (M, V) + public service: BaseFilterListService; /** * Constructor. Does nothing. diff --git a/client/src/app/shared/components/os-sort-filter-bar/os-sort-filter-bar.component.ts b/client/src/app/shared/components/os-sort-filter-bar/os-sort-filter-bar.component.ts index 695c27490..7e5c955b7 100644 --- a/client/src/app/shared/components/os-sort-filter-bar/os-sort-filter-bar.component.ts +++ b/client/src/app/shared/components/os-sort-filter-bar/os-sort-filter-bar.component.ts @@ -9,6 +9,7 @@ import { FilterMenuComponent } from './filter-menu/filter-menu.component'; import { OsSortingItem } from 'app/core/ui-services/base-sort-list.service'; import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service'; import { ViewportService } from 'app/core/ui-services/viewport.service'; +import { BaseFilterListService } from 'app/core/ui-services/base-filter-list.service'; /** * Reusable bar for list views, offering sorting and filter options. @@ -47,7 +48,7 @@ export class OsSortFilterBarComponent { * be a FilterListService extendingFilterListService. */ @Input() - public filterService: any; // TODO a FilterListService extending FilterListService + public filterService: BaseFilterListService; /** * optional additional string to show after the item count. This string will not be translated here @@ -80,7 +81,7 @@ export class OsSortFilterBarComponent { */ public get displayedCount(): number { if (this.filterCount === undefined || this.filterCount === null) { - return this.filterService.filterCount; + return this.filterService.filteredCount; } else { return this.filterCount; } diff --git a/client/src/app/site/agenda/agenda-import.service.ts b/client/src/app/site/agenda/agenda-import.service.ts index 027956820..93057f439 100644 --- a/client/src/app/site/agenda/agenda-import.service.ts +++ b/client/src/app/site/agenda/agenda-import.service.ts @@ -205,7 +205,8 @@ export class AgendaImportService extends BaseImportService { }; const duplicates = this.repo.getTopicDuplicates(newTopic); if (duplicates.length) { - // TODO this is a dishonest casting. duplicates should not be required to be View + // TODO duplicates are not really ViewCreateTopics, but ViewTopics. + // TODO this should be fine as the duplicates will not be created newEntry.duplicates = duplicates as ViewCreateTopic[]; this.setError(newEntry, 'Duplicates'); } diff --git a/client/src/app/site/agenda/services/agenda-filter-list.service.ts b/client/src/app/site/agenda/services/agenda-filter-list.service.ts index db170c5ed..992453a49 100644 --- a/client/src/app/site/agenda/services/agenda-filter-list.service.ts +++ b/client/src/app/site/agenda/services/agenda-filter-list.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { BaseFilterListService, OsFilter, OsFilterOption } from 'app/core/ui-services/base-filter-list.service'; -import { Item, itemVisibilityChoices } from 'app/shared/models/agenda/item'; +import { itemVisibilityChoices } from 'app/shared/models/agenda/item'; import { ViewItem } from '../models/view-item'; import { StorageService } from 'app/core/core-services/storage.service'; import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service'; @@ -10,7 +10,7 @@ import { TranslateService } from '@ngx-translate/core'; @Injectable({ providedIn: 'root' }) -export class AgendaFilterListService extends BaseFilterListService { +export class AgendaFilterListService extends BaseFilterListService { protected name = 'Agenda'; public filterOptions: OsFilter[] = []; diff --git a/client/src/app/site/agenda/services/agenda-pdf.service.ts b/client/src/app/site/agenda/services/agenda-pdf.service.ts index 8fc6e0458..be9945e98 100644 --- a/client/src/app/site/agenda/services/agenda-pdf.service.ts +++ b/client/src/app/site/agenda/services/agenda-pdf.service.ts @@ -65,7 +65,7 @@ export class AgendaPdfService { /** * Parses an entry line and triggers parsing of any children - * (TODO: Check assumption: items with 'is_hidden' are not to be exported) + * Items with 'is_hidden' and their subitems are not exported * * @param nodeItem the item for the head line * @param level: The hierarchy index (beginning at 0 for top level agenda topics) diff --git a/client/src/app/site/assignments/components/assignment-list/assignment-list.component.ts b/client/src/app/site/assignments/components/assignment-list/assignment-list.component.ts index dbc051e14..a3b618cf9 100644 --- a/client/src/app/site/assignments/components/assignment-list/assignment-list.component.ts +++ b/client/src/app/site/assignments/components/assignment-list/assignment-list.component.ts @@ -67,7 +67,7 @@ export class AssignmentListComponent extends ListViewBaseComponent { +export class AssignmentFilterListService extends BaseFilterListService { protected name = 'Assignment'; /** diff --git a/client/src/app/site/base/list-view-base.ts b/client/src/app/site/base/list-view-base.ts index d3a92ef92..ded8fbac1 100644 --- a/client/src/app/site/base/list-view-base.ts +++ b/client/src/app/site/base/list-view-base.ts @@ -89,7 +89,7 @@ export abstract class ListViewBaseComponent, + public filterService?: BaseFilterListService, public sortService?: BaseSortListService ) { super(titleService, translate, matSnackBar); diff --git a/client/src/app/site/config/components/config-field/config-field.component.ts b/client/src/app/site/config/components/config-field/config-field.component.ts index bbed3b4c6..da8d005da 100644 --- a/client/src/app/site/config/components/config-field/config-field.component.ts +++ b/client/src/app/site/config/components/config-field/config-field.component.ts @@ -12,9 +12,13 @@ import { ViewConfig } from '../../models/view-config'; import { ConfigRepositoryService } from 'app/core/repositories/config/config-repository.service'; /** - * List view for the categories. + * Component for a config field, used by the {@link ConfigListComponent}. Handles + * all inpu types defined by the server, as well as updating the configs * - * TODO: Creation of new Categories + * @example + * ```ts + * + * ``` */ @Component({ selector: 'os-config-field', @@ -58,7 +62,8 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit { public rawDate: Date; /** - * The config item for this component. Just accept components with already populated constants-info. + * The config item for this component. Just accepts components with already + * populated constants-info. */ @Input() public set item(value: ViewConfig) { diff --git a/client/src/app/site/mediafiles/services/mediafile-filter.service.ts b/client/src/app/site/mediafiles/services/mediafile-filter.service.ts index 94cc9aa1a..701a65c14 100644 --- a/client/src/app/site/mediafiles/services/mediafile-filter.service.ts +++ b/client/src/app/site/mediafiles/services/mediafile-filter.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; import { BaseFilterListService, OsFilter } from 'app/core/ui-services/base-filter-list.service'; -import { Mediafile } from 'app/shared/models/mediafiles/mediafile'; import { ViewMediafile } from '../models/view-mediafile'; import { StorageService } from 'app/core/core-services/storage.service'; import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service'; @@ -11,7 +10,7 @@ import { TranslateService } from '@ngx-translate/core'; @Injectable({ providedIn: 'root' }) -export class MediafileFilterListService extends BaseFilterListService { +export class MediafileFilterListService extends BaseFilterListService { protected name = 'Mediafile'; /** diff --git a/client/src/app/site/motions/services/motion-filter-list.service.ts b/client/src/app/site/motions/services/motion-filter-list.service.ts index bd205b058..44f5513ad 100644 --- a/client/src/app/site/motions/services/motion-filter-list.service.ts +++ b/client/src/app/site/motions/services/motion-filter-list.service.ts @@ -3,7 +3,6 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { BaseFilterListService, OsFilter, OsFilterOptions } from 'app/core/ui-services/base-filter-list.service'; -import { Motion } from 'app/shared/models/motions/motion'; import { ViewMotion } from '../models/view-motion'; import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service'; import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service'; @@ -19,7 +18,7 @@ import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository. @Injectable({ providedIn: 'root' }) -export class MotionFilterListService extends BaseFilterListService { +export class MotionFilterListService extends BaseFilterListService { protected name = 'Motion'; /** diff --git a/client/src/app/site/motions/services/motion-import.service.ts b/client/src/app/site/motions/services/motion-import.service.ts index 7c997af55..e630bfc2d 100644 --- a/client/src/app/site/motions/services/motion-import.service.ts +++ b/client/src/app/site/motions/services/motion-import.service.ts @@ -271,12 +271,12 @@ export class MotionImportService extends BaseImportService { return null; } blockString = blockString.trim(); - let existingBlock = this.motionBlockRepo.getMotionBlockByTitle(blockString); - if (!existingBlock) { - existingBlock = this.motionBlockRepo.getMotionBlockByTitle(this.translate.instant(blockString)); + let existingBlock = this.motionBlockRepo.getMotionBlocksByTitle(blockString); + if (!existingBlock.length) { + existingBlock = this.motionBlockRepo.getMotionBlocksByTitle(this.translate.instant(blockString)); } - if (existingBlock) { - return { id: existingBlock.id, name: existingBlock.title }; + if (existingBlock.length) { + return { id: existingBlock[0].id, name: existingBlock[0].title }; } else { if (!this.newMotionBlocks.find(newBlock => newBlock.name === blockString)) { this.newMotionBlocks.push({ name: blockString }); diff --git a/client/src/app/site/users/components/user-list/user-list.component.ts b/client/src/app/site/users/components/user-list/user-list.component.ts index 0cd9d8a77..731342c50 100644 --- a/client/src/app/site/users/components/user-list/user-list.component.ts +++ b/client/src/app/site/users/components/user-list/user-list.component.ts @@ -95,11 +95,10 @@ export class UserListComponent extends ListViewBaseComponent imp private _presenceViewConfigured = false; /** - * TODO: Does not check for user manage rights itself * @returns true if the presence view is available to administrators */ public get presenceViewConfigured(): boolean { - return this._presenceViewConfigured; + return this._presenceViewConfigured && this.operator.hasPerms('users.can_manage'); } /** @@ -164,7 +163,7 @@ export class UserListComponent extends ListViewBaseComponent imp * to filter/sort services */ public ngOnInit(): void { - super.setTitle(this.translate.instant('Participants')); + super.setTitle('Participants'); this.initTable(); this.setFulltextFilter(); diff --git a/client/src/app/site/users/models/view-user.ts b/client/src/app/site/users/models/view-user.ts index 473fe2f0b..338a04166 100644 --- a/client/src/app/site/users/models/view-user.ts +++ b/client/src/app/site/users/models/view-user.ts @@ -97,7 +97,6 @@ export class ViewUser extends BaseProjectableViewModel implements Searchable { return this.user && !!this.user.last_email_send; } - // TODO read config values for "users_sort_by" /** * Getter for the short name (Title, given name, surname) * @@ -111,16 +110,6 @@ export class ViewUser extends BaseProjectableViewModel implements Searchable { const title = this.title ? this.title.trim() : ''; const firstName = this.first_name ? this.first_name.trim() : ''; const lastName = this.last_name ? this.last_name.trim() : ''; - - // TODO need DS adjustment first first - // if (this.DS.getConfig('users_sort_by').value === 'last_name') { - // if (lastName && firstName) { - // shortName += `${lastName}, ${firstName}`; - // } else { - // shortName += lastName || firstName; - // } - // } - let shortName = `${firstName} ${lastName}`; if (shortName.length <= 1) { diff --git a/client/src/app/site/users/services/user-filter-list.service.ts b/client/src/app/site/users/services/user-filter-list.service.ts index f56a4fd93..99da73677 100644 --- a/client/src/app/site/users/services/user-filter-list.service.ts +++ b/client/src/app/site/users/services/user-filter-list.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'; import { BaseFilterListService, OsFilter } from 'app/core/ui-services/base-filter-list.service'; import { StorageService } from 'app/core/core-services/storage.service'; -import { User } from 'app/shared/models/users/user'; import { ViewUser } from '../models/view-user'; import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; @@ -11,7 +10,7 @@ import { TranslateService } from '@ngx-translate/core'; @Injectable({ providedIn: 'root' }) -export class UserFilterListService extends BaseFilterListService { +export class UserFilterListService extends BaseFilterListService { protected name = 'User'; private userGroupFilterOptions = { diff --git a/client/src/app/site/users/services/user-sort-list.service.ts b/client/src/app/site/users/services/user-sort-list.service.ts index 33b759340..ce9da94db 100644 --- a/client/src/app/site/users/services/user-sort-list.service.ts +++ b/client/src/app/site/users/services/user-sort-list.service.ts @@ -22,7 +22,6 @@ export class UserSortListService extends BaseSortListService { { property: 'number', label: 'Participant number' }, { property: 'structure_level', label: 'Structure level' }, { property: 'comment' } - // TODO email send? ] }; protected name = 'User';