import { Injectable } from "@angular/core" ; import { EntityMapperService } from "../../../core/entity/entity-mapper.service" ; import { Note } from "../model/note" ; import { User } from "../../../core/user/user" ; import { AlertService } from "../../../core/alerts/alert.service" ; import { Alert } from "../../../core/alerts/alert" ; import { AlertDisplay } from "../../../core/alerts/alert-display" ; import { RecurringActivity } from "../../attendance/model/recurring-activity" ; @ Injectable ( { providedIn : "root" , } ) export class NotesMigrationService { allUsers : Map < string , User > ; constructor ( private entityMapperService , private alertService ) { } /**
     * migrates all notes in the database to the new format.
     * <br>This format will include users as an array of string-id's
     * instead of a single field describing the author(s) of the note
     */ async migrateToMultiUser ( ) { console . log ( "Starting to migrate all Notes' authors" ) ; this . allUsers = new Map < string , User > ( ( await this . entityMapperService . loadType ( User ) ) . map ( ( u ) => [ u . name . toLowerCase ( ) , u , ] ) ) ; const allNotes = await this . entityMapperService . loadType ( Note ) ; let amountOfMigratedNotes = 0 ; for ( const note of allNotes ) { amountOfMigratedNotes += this . migrateSingleNote ( note ) ; await this . entityMapperService . save ( note ) ; } this . alertService . addAlert ( new Alert ( `Migrated ${ amountOfMigratedNotes } note(s) ` , Alert . INFO , AlertDisplay . TEMPORARY ) ) ; console . log ( `Completed to migrate all Notes' authors (${ amountOfMigratedNotes } note(s) total)` ) ; this . migrateToMultiAssignedActivities ( ) ; } async migrateToMultiAssignedActivities ( ) { const allActivities = await this . entityMapperService . loadType ( RecurringActivity ) ; for ( const act of allActivities ) { act . assignedTo = [ ] ; await this . entityMapperService . save ( act ) ; } } param note public migrateSingleNote ( note ) { const userStr = note [ "author" ] ; if ( userStr === undefined || userStr === null ) { return 0 ; } const newUsers = this . findUsers ( userStr ) ; note . authors = newUsers . detectedUsers . map ( ( u ) => u . getId ( ) ) ; delete note [ "author" ] ; if ( newUsers . additional . length > 0 ) { console . log ( "could not match all users" , note ) ; this . updateNoteText ( note , newUsers . additional ) ; } return 1 ; } private updateNoteText ( note , additionalUsers ) { const additionalText = "Also authored by " + additionalUsers . join ( ", " ) ; if ( note . text . length === 0 ) { note . text = additionalText ; } else { note . text += "\n" + additionalText ; } } param str public findUsers ( str ) { const detectedUsers = [ ] ; const additional = [ ] ; const searchStrings = str . trim ( ) . replace ( /&/g , "," ) . replace ( /and/g , "," ) . split ( "," ) . map ( ( s ) => s . replace ( /[^a-zA-Z\s]/ , "" ) . trim ( ) ) ; for ( const searchString of searchStrings ) { const user = this . findSingleUser ( searchString ) ; if ( user ) { detectedUsers . push ( user ) ; } else if ( searchString . trim ( ) . length > 0 ) { additional . push ( searchString . trim ( ) ) ; } } return { detectedUsers : detectedUsers , additional : additional } ; } param str private findSingleUser ( str ) { const lowerCaseSearch = str . toLowerCase ( ) ; if ( lowerCaseSearch . match ( /\s/ ) ) { return ( this . allUsers . get ( lowerCaseSearch ) || lowerCaseSearch . split ( /\s/ ) . map ( ( s ) => this . allUsers . get ( s ) ) . filter ( ( u ) => ! ! u ) . pop ( ) ) ; } else { return this . allUsers . get ( lowerCaseSearch ) ; } } }