diff --git a/src/app/components/shared/_dialogs/room-create/room-create.component.html b/src/app/components/shared/_dialogs/room-create/room-create.component.html index b3cf9be54c25c6b00c4428cb3b010953a4199baf..a8bf7a84d4de7ae5b151fae63761f830c51efa2d 100644 --- a/src/app/components/shared/_dialogs/room-create/room-create.component.html +++ b/src/app/components/shared/_dialogs/room-create/room-create.component.html @@ -54,6 +54,7 @@ <app-dialog-action-buttons buttonsLabelSection="room-create" confirmButtonLabel="create-room" + [showLoadingCycle]="isLoading" [cancelButtonClickAction]="buildCloseDialogActionCallback()" [confirmButtonClickAction]="buildRoomCreateActionCallback(roomName)" ></app-dialog-action-buttons> diff --git a/src/app/components/shared/_dialogs/room-create/room-create.component.ts b/src/app/components/shared/_dialogs/room-create/room-create.component.ts index bd3ef6432bb3d2726e544c2c8c3ad449bd2b0245..00b0929a88dd1ea59664343a38e794c8b64af190 100644 --- a/src/app/components/shared/_dialogs/room-create/room-create.component.ts +++ b/src/app/components/shared/_dialogs/room-create/room-create.component.ts @@ -24,6 +24,7 @@ export class RoomCreateComponent implements OnInit { roomId: string; user: User; hasCustomShortId = false; + isLoading = false; constructor( private roomService: RoomService, @@ -52,6 +53,10 @@ export class RoomCreateComponent implements OnInit { } checkLogin(longRoomName: string) { + if (this.isLoading) { + return; + } + this.isLoading = true; if (!this.user) { this.authenticationService.guestLogin(UserRole.CREATOR).subscribe(() => { this.addRoom(longRoomName); @@ -88,12 +93,13 @@ export class RoomCreateComponent implements OnInit { } this.roomService.addRoom(newRoom, () => { this.shortIdAlreadyUsed = true; + this.isLoading = false; }).subscribe(room => { const encoded = encodeURIComponent(room.shortId) - .replace('\~', '%7E') - .replace('\.', '%2E') - .replace('\_', '%5F') - .replace('\-', '%2D'); + .replace('\~', '%7E') + .replace('\.', '%2E') + .replace('\_', '%5F') + .replace('\-', '%2D'); this.room = room; let msg1: string; let msg2: string; @@ -102,7 +108,7 @@ export class RoomCreateComponent implements OnInit { this.notification.show(msg1 + longRoomName + msg2); this.authenticationService.setAccess(encoded, UserRole.CREATOR); this.authenticationService.assignRole(UserRole.CREATOR); - this.router.navigate(['/creator/room/' + encoded ]); + this.router.navigate(['/creator/room/' + encoded]); this.closeDialog(); }); } diff --git a/src/app/components/shared/tag-cloud/tag-cloud.component.ts b/src/app/components/shared/tag-cloud/tag-cloud.component.ts index 91c28a70749dd4f4c8487c91515220f44c12f3c3..a8d3120eb4b1c0aed75cd6af017efe324d968e8d 100644 --- a/src/app/components/shared/tag-cloud/tag-cloud.component.ts +++ b/src/app/components/shared/tag-cloud/tag-cloud.component.ts @@ -1,4 +1,4 @@ -import { AfterContentInit, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { AfterContentInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { CloudData, @@ -23,7 +23,7 @@ import { ThemeService } from '../../../../theme/theme.service'; import { TopicCloudAdministrationComponent } from '../_dialogs/topic-cloud-administration/topic-cloud-administration.component'; import { WsCommentService } from '../../../services/websockets/ws-comment.service'; import { CreateCommentWrapper } from '../../../utils/create-comment-wrapper'; -import { regexMaskKeyword, TopicCloudAdminService } from '../../../services/util/topic-cloud-admin.service'; +import { maskKeyword, TopicCloudAdminService } from '../../../services/util/topic-cloud-admin.service'; import { TagCloudPopUpComponent } from './tag-cloud-pop-up/tag-cloud-pop-up.component'; import { TagCloudDataService, TagCloudDataTagEntry } from '../../../services/util/tag-cloud-data.service'; import { WsRoomService } from '../../../services/websockets/ws-room.service'; @@ -69,10 +69,6 @@ class TagComment implements CloudData { const transformationScaleKiller = /scale\([^)]*\)/; const transformationRotationKiller = /rotate\(([^)]*)\)/; -const maskedCharRegex = /[“â€â€˜â€™â€žâ€šÂ«Â»â€¹â€ºã€Žã€ï¹ƒï¹„「ã€ï¹ï¹‚",《》〈〉'`#&]|(\s(lu|li’u)(?=\s))|(^lu\s)|(\sli’u$)/; -const httpRegex = /(https?:[^\s](\s|$))/; -const hidelist = new RegExp(maskedCharRegex.source + '|' + httpRegex.source, 'gmi'); - const CONDITION_ROOM = 0; const CONDITION_BUILT = 1; @@ -320,8 +316,7 @@ export class TagCloudComponent implements OnInit, OnDestroy, AfterContentInit { if (rotation === null || this._currentSettings.randomAngles) { rotation = Math.floor(Math.random() * 30 - 15); } - const filteredTag = tag.replace(hidelist, '') - .replace(regexMaskKeyword, '').replace(/ +/, ' ').trim(); + const filteredTag = maskKeyword(tag); newElements.push(new TagComment(filteredTag, tag, rotation, tagData.weight, tagData, newElements.length)); } } diff --git a/src/app/models/export.ts b/src/app/models/export.ts index 0620469a96105e600f111fcc5ab0fec14ad7ebda..88b6c5ab615ec6a9c6d21495c6278269b20a5408 100644 --- a/src/app/models/export.ts +++ b/src/app/models/export.ts @@ -6,7 +6,6 @@ import { BonusToken } from './bonus-token'; import { TranslateService } from '@ngx-translate/core'; import { User } from './user'; import { NotificationService } from '../services/util/notification.service'; -import { ViewCommentDataComponent } from '../components/shared/view-comment-data/view-comment-data.component'; import { forkJoin, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Comment } from './comment'; @@ -140,7 +139,7 @@ export class Export { private user: User ) { this.mapper = new ExportMapper<CommentBonusTokenMixin>(); - this.bonusTokenMask = this.user && this.user.role >= UserRole.PARTICIPANT; + this.bonusTokenMask = this.user && this.user.role > UserRole.PARTICIPANT; } public exportAsCsv() { diff --git a/src/app/services/util/profanity-filter.service.ts b/src/app/services/util/profanity-filter.service.ts index 0e1237e348979f6a7ef645127c2320529d40aa60..1cf15c8c8d07cc50e2df223013c7ed7cef272d40 100644 --- a/src/app/services/util/profanity-filter.service.ts +++ b/src/app/services/util/profanity-filter.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; import * as BadWords from 'naughty-words'; +import { escapeForRegex } from '../../utils/regex-escape'; @Injectable({ providedIn: 'root' @@ -80,9 +81,7 @@ export class ProfanityFilterService { if (list.length < 1 || !str) { return [str, false]; } - const escapeRegex = /[.*+\-?^${}()|\[\]\\]/g; - const censoredWords = list - .reduce((acc, elem) => acc + (acc.length > 1 ? '|' : '') + elem.replace(escapeRegex, '\\$&'), '(') + ')'; + const censoredWords = list.reduce((acc, elem) => acc + (acc.length > 1 ? '|' : '') + escapeForRegex(elem), '(') + ')'; const regex = new RegExp(censorPartialWordsCheck ? censoredWords : '\\b' + censoredWords + '\\b', 'gmi'); let result = ''; let censored = false; diff --git a/src/app/services/util/topic-cloud-admin.service.ts b/src/app/services/util/topic-cloud-admin.service.ts index 2204aa832d47cd4540ab336b474baa1f5a900e77..42836978f9495edea228a5ce5f4387fc2da605c7 100644 --- a/src/app/services/util/topic-cloud-admin.service.ts +++ b/src/app/services/util/topic-cloud-admin.service.ts @@ -16,12 +16,16 @@ import { Comment } from '../../models/comment'; import { UserRole } from '../../models/user-roles.enum'; import { CloudParameters } from '../../utils/cloud-parameters'; import { RoomDataService } from './room-data.service'; +import { stopWords, superfluousSpecialCharacters } from '../../utils/stopwords'; +import { escapeForRegex } from '../../utils/regex-escape'; -const words = [ - 'frage', 'antwort', 'aufgabe', 'hallo', 'test', 'bzw', 'bzw.', 'muss', 'more to come', 'mal', 'zb', 'zb\\.', - 'z\\.\\s*b\\.', 'zum beispiel', 'beispiel', 'jeder?', 'jede/r', 'bisschen', 'bißchen', 'okay', 'ok', 'o.k.' -]; -export const regexMaskKeyword = new RegExp('\\b(' + words.join('|') + ')\\b|…|\\\\|\\/', 'gmi'); +const words = stopWords.map(word => escapeForRegex(word).replace(/\s+/, '\\s*')); +const httpRegex = /(https?:[^\s]+(\s|$))/; +const specialCharacters = '[' + escapeForRegex(superfluousSpecialCharacters) + ']+'; +const regexMaskKeyword = new RegExp('\\b(' + words.join('|') + ')\\b|' + + httpRegex.source + '|' + specialCharacters, 'gmi'); +export const maskKeyword = (keyword: string): string => + keyword.replace(regexMaskKeyword, '').replace(/\s+/, ' ').trim(); @Injectable({ providedIn: 'root', @@ -85,7 +89,7 @@ export class TopicCloudAdminService { const wantedLabels = config.wantedLabels[comment.language.toLowerCase()]; for (let i = 0; i < source.length; i++) { const keyword = source[i]; - if (keyword.text.replace(regexMaskKeyword, '').replace(/ +/, ' ').trim().length < 3) { + if (maskKeyword(keyword.text).length < 3) { continue; } if (censored[i]) { diff --git a/src/app/utils/regex-escape.ts b/src/app/utils/regex-escape.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0efb140466bee2adaf58f9c326d2ac2ef39f9fc --- /dev/null +++ b/src/app/utils/regex-escape.ts @@ -0,0 +1 @@ +export const escapeForRegex = (str: string): string => str.replace(/[.*+\-?^${}()|\[\]\\]/g, '\\$&'); diff --git a/src/app/utils/stopwords.ts b/src/app/utils/stopwords.ts new file mode 100644 index 0000000000000000000000000000000000000000..0401a7dfd5326226f045bb77dd5fdd709e6f1d42 --- /dev/null +++ b/src/app/utils/stopwords.ts @@ -0,0 +1,28 @@ +// all spaces gets replaced with \s* (multiple or none whitespaces) +// all words are case insensitive +export const stopWords = [ + 'Frage', + 'Antwort', + 'Aufgabe', + 'Hallo', + 'Test', + 'bzw', + 'bzw.', + 'muss', + 'more to come', + 'mal', + 'zb.', + 'zb', + 'z. b.', + 'Zum Beispiel', + 'Beispiel', + 'jede', + 'jeder', + 'jede/r', + 'bisschen', + 'bißchen', + 'okay', + 'ok', + 'o.k.' +]; +export const superfluousSpecialCharacters = '“â€â€˜â€™â€žâ€šÂ«Â»â€¹â€ºã€Žã€ï¹ƒï¹„「ã€ï¹ï¹‚",《》〈〉\'`#&…\\/';