Skip to content

Commit

Permalink
Added handling of moderation events to ban a user.
Browse files Browse the repository at this point in the history
Co-authored-by: Patrick Schmidt (Clon1998)
  • Loading branch information
devopvoid committed Feb 7, 2024
1 parent 672b4c1 commit 6e3efba
Show file tree
Hide file tree
Showing 15 changed files with 189 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/component/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './controls/documents-button';
export * from './controls/document-navigation';
export * from './controls/settings-button';
export * from './loading/player-loading';
export * from './no-access/no-access';
export * from './offline/player-offline';
export * from './feature-view/feature-view';
export * from './chat-box/chat-box';
Expand All @@ -26,4 +27,4 @@ export * from './theme-settings/theme-settings';
export * from './media-settings/camera-settings';
export * from './media-settings/sound-settings';

export * from './shoelace';
export * from './shoelace';
48 changes: 48 additions & 0 deletions src/component/no-access/no-access.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
:host {
display: flex;
flex-direction: column;
align-items: center;
height: inherit;
color: var(--sl-color-neutral-700);
}
:host > div {
display: flex;
flex-direction: column;
flex: 0 0 auto;
width: 50%;
padding-top: 3rem;
}
:host > div > h1 {
padding: 0.5rem 0;
align-self: center;
}
:host > div > p {
align-self: center;
}
:host > div > sl-icon {
fill: var(--sl-color-primary-600);
font-size: 6rem;
align-self: center;
padding-bottom: 0.5rem;
}

:host > div > sl-button {
margin: var(--sl-spacing-medium);
align-self: center;
}

:host p {
margin-top: 0;
margin-bottom: 1rem;
}

@media (max-width: 1000px) {
:host > div {
width: 60%;
}
}
@media (max-width: 800px) {
:host > div {
width: 80%;
}
}
32 changes: 32 additions & 0 deletions src/component/no-access/no-access.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {CSSResultGroup, html} from 'lit';
import {customElement} from 'lit/decorators.js';
import {I18nLitElement} from '../i18n-mixin';
import {Component} from '../component';
import style from './player-no-access.css';
import {t} from "i18next";

@customElement('player-no-access')
export class PlayerNoAccess extends Component {

static override styles = <CSSResultGroup>[
I18nLitElement.styles,
style,
];


private home() {
// Use location to navigate to the home page.
location.assign("/")
}

protected override render() {
return html`
<div>
<sl-icon name="shield-x"></sl-icon>
<h1>${t("course.no_access.title")}</h1>
<p>${t("course.no_access.description")}</p>
<sl-button @click="${this.home}" variant="default">${t("course.overview")}</sl-button>
</div>
`;
}
}
42 changes: 39 additions & 3 deletions src/component/player/player.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { EventEmitter } from '../../utils/event-emitter';
import { RootController } from '../controller/root.controller';
import { Controller } from '../controller/controller';
import { streamStatsStore } from '../../store/stream-stats.store';
import { LpChatResponseEvent, LpChatStateEvent, LpEventServiceStateEvent, LpMediaStateEvent, LpParticipantPresenceEvent, LpQuizStateEvent, LpRecordingStateEvent, LpStreamStateEvent } from '../../event';
import { LpChatResponseEvent, LpChatStateEvent, LpEventServiceStateEvent, LpMediaStateEvent, LpParticipantPresenceEvent, LpParticipantModerationEvent, LpQuizStateEvent, LpRecordingStateEvent, LpStreamStateEvent } from '../../event';
import { Toaster } from '../../utils/toaster';
import { t } from 'i18next';

Expand Down Expand Up @@ -79,6 +79,7 @@ export class PlayerController extends Controller implements ReactiveController {
this.eventEmitter.addEventListener("lp-media-state", this.onMediaState.bind(this));
this.eventEmitter.addEventListener("lp-participant-presence", this.onParticipantPresence.bind(this));
this.eventEmitter.addEventListener("lp-stream-connection-state", this.onStreamConnectionState.bind(this));
this.eventEmitter.addEventListener("lp-participant-moderation", this.onParticipantModeration.bind(this));

if (this.host.courseId) {
this.eventService.connect();
Expand Down Expand Up @@ -519,12 +520,43 @@ export class PlayerController extends Controller implements ReactiveController {
this.updateConnectionState();
}

private onParticipantModeration(event: LpParticipantModerationEvent) {
const moderation = event.detail;

if (moderation.userId !== userStore.userId) {
console.log("User moderation event for user, but not me.")
return;
}

if (moderation.moderationType === "PERMANENT_BAN") {
console.log("User banned.")
this.modalController.closeAllModals();

uiStateStore.setStreamState(State.NO_ACCESS);
uiStateStore.setDocumentState(State.NO_ACCESS);
this.streamController.disconnect();
this.eventService.close();
this.updateConnectionState();

Toaster.showWarning(t("course.moderation.toast.permanent_banned.title"),
t("course.moderation.toast.permanent_banned.description"), Infinity);
}
}

private updateConnectionState() {
const state = uiStateStore.state;
const streamState = uiStateStore.streamState;
const documentState = uiStateStore.documentState;

console.log("** update state:", State[state], ", streamState", State[streamState], ", documentState", State[documentState], ", has features", featureStore.hasFeatures());
console.log("** update state:", State[state],
", streamState", State[streamState],
", documentState", State[documentState],
", has features", featureStore.hasFeatures());

if (streamState == State.NO_ACCESS || documentState == State.NO_ACCESS) {
this.setConnectionState(State.NO_ACCESS);
return;
}

if (this.hasStream() && !courseStore.isClassroom) {
if (streamState === State.CONNECTED && documentState === State.CONNECTED) {
Expand Down Expand Up @@ -557,6 +589,10 @@ export class PlayerController extends Controller implements ReactiveController {
if (uiStateStore.state === state) {
return;
}
if (uiStateStore.state == State.NO_ACCESS) {
console.log("no access, skip state change");
return;
}

console.log("new state", State[state])

Expand All @@ -577,4 +613,4 @@ export class PlayerController extends Controller implements ReactiveController {
break;
}
}
}
}
2 changes: 2 additions & 0 deletions src/component/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export class LecturePlayer extends Component {
return html`<player-feature-view .chatService="${this.controller.chatService}"></player-feature-view>`;
case State.DISCONNECTED:
return html`<player-offline></player-offline>`;
case State.NO_ACCESS:
return html`<player-no-access></player-no-access>`;
}
}
}
3 changes: 2 additions & 1 deletion src/event/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from "./lp-participant-destroyed.event";
export * from "./lp-participant-error.event";
export * from "./lp-participant-joined.event";
export * from "./lp-participant-left.event";
export * from "./lp-participant-moderation.event";
export * from "./lp-participant-presence.event";
export * from "./lp-participant-state.event";
export * from './lp-quiz-state.event';
Expand All @@ -21,4 +22,4 @@ export * from './lp-speech-state.event';
export * from "./lp-stream-capture-stats.event";
export * from "./lp-stream-connection-state.event";
export * from './lp-stream-state.event';
export * from './lp-void.event';
export * from './lp-void.event';
4 changes: 3 additions & 1 deletion src/event/lp-participant-joined.event.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {VideoRoomParticipant} from "janus-gateway";

export type LpParticipantJoinedEvent = CustomEvent<VideoRoomParticipant>;

declare global {
interface GlobalEventHandlersEventMap {
"lp-participant-joined": LpParticipantJoinedEvent;
}
}
}
9 changes: 9 additions & 0 deletions src/event/lp-participant-moderation.event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {CourseParticipantModeration} from "../model/moderation";

export type LpParticipantModerationEvent = CustomEvent<CourseParticipantModeration>;

declare global {
interface GlobalEventHandlersEventMap {
"lp-participant-moderation": LpParticipantModerationEvent;
}
}
4 changes: 4 additions & 0 deletions src/icons/shield-x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion src/locales/de/main.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"course.overview": "Kurs Übersicht",
"course.loading": "Lade Kurs...",
"course.unavailable": "Der Stream hat noch nicht begonnen. Bitte versuchen Sie es kurz vor Beginn der Veranstaltung erneut.",
"settings.title": "Einstellungen",
Expand Down Expand Up @@ -115,6 +116,10 @@
"course.recorded.modal.title": "Dieser Kurs wird aufgezeichnet",
"course.recorded.modal.message": "Die Aufzeichnung kann nachträglich veröffentlicht werden. Dies betrifft als digitale Veranstaltung Ihre Beiträge bei aktiven Wortmeldungen.",
"course.recorded.modal.accept": "Verstanden",
"course.no_access.title": "Sie haben keinen Zugriff auf diesen Kurs.",
"course.no_access.description": "Der Zugriff auf diesen Kurs ist Ihnen nicht gestattet. Bitte setzen Sie sich mit den Organisatoren:innen in Verbindung.",
"course.moderation.toast.permanent_banned.title": "Sie wurden vom Kurs ausgeschlossen",
"course.moderation.toast.permanent_banned.description": "Bei Fragen wenden Sie sich an die Organisator:innen.",
"documents.open.document": "PDF-Dokument öffnen",
"documents.open.whiteboard": "Whiteboard öffnen",
"entry.modal.title": "Medienwiedergabe Starten",
Expand Down Expand Up @@ -173,4 +178,4 @@
"vpn.required.description.vpn": "Sichere Verbindung ins TU-Netz und Zugang zu Services außerhalb des TU Datennetzes.",
"vpn.required.description.wlan": "Nahezu flächendeckender Internetzugang am Campus und im Kongresszentrum \u201Cdarmstadtium\u201D.",
"vpn.required.reconnect": "Bitte die Seite neu laden, nachdem die Verbindung erfolgreich aufgebaut worden ist."
}
}
7 changes: 6 additions & 1 deletion src/locales/en/main.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"course.overview": "Course Overview",
"course.loading": "Loading Course...",
"course.unavailable": "The stream has not started yet. Please try again closer to the event start time.",
"settings.title": "Device settings",
Expand Down Expand Up @@ -115,6 +116,10 @@
"course.recorded.modal.title": "This course is being recorded",
"course.recorded.modal.message": "The recording can be published later. As a digital event, this affects your contributions during active requests to speak.",
"course.recorded.modal.accept": "Got it",
"course.no_access.title": "You are not allowed to access this course.",
"course.no_access.description": "You do not have access to this course. Please contact the organizers.",
"course.moderation.toast.permanent_banned.title": "You have been permanently banned from the course",
"course.moderation.toast.permanent_banned.description": "If you have any questions, please contact the organizers.",
"documents.open.document": "Open PDF Document",
"documents.open.whiteboard": "Open Whiteboard",
"entry.modal.title": "Start media playback",
Expand Down Expand Up @@ -168,4 +173,4 @@
"vpn.required.description.vpn": "Secure connection into the TU network and access to services outside of the TU data network.",
"vpn.required.description.wlan": "Nearly full-coverage Internet access on campus and in the \u201Cdarmstadtium\u201D congress center.",
"vpn.required.reconnect": "Please reload the page after the connection has been successfully established."
}
}
12 changes: 12 additions & 0 deletions src/model/moderation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ModerationType = "PERMANENT_BAN";

export interface CourseParticipantModeration {

readonly userId: string;

readonly firstName: string;

readonly familyName: string;

readonly moderationType: ModerationType;
}
11 changes: 10 additions & 1 deletion src/service/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export class EventService extends EventTarget {

private readonly subServices: EventSubService[];

private client: Client | undefined;


constructor(courseId: number, eventEmitter: EventEmitter) {
super();
Expand Down Expand Up @@ -85,10 +87,17 @@ export class EventService extends EventTarget {
client.deactivate();
});

this.client = client;

return client;
}

close() {
console.log("** EventService closes, disconnecting STOMP");
this.client?.deactivate()
}

private handleEvent(eventName: string, body: string) {
this.eventEmitter.dispatchEvent(Utils.createEvent(eventName, JSON.parse(body)));
}
}
}
5 changes: 3 additions & 2 deletions src/utils/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum State {
CONNECTED,
CONNECTED_FEATURES,
DISCONNECTED,
RECONNECTING
RECONNECTING,
NO_ACCESS,

}
}
22 changes: 11 additions & 11 deletions src/utils/toaster.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
export class Toaster {

public static show(title: string, message?: string): void {
this.showNotification(title, message, "neutral", "info-circle");
public static show(title: string, message?: string, duration = 3000): void {
this.showNotification(title, message, "neutral", "info-circle", duration);
}

public static showInfo(title: string, message?: string): void {
this.showNotification(title, message, "primary", "info-circle");
public static showInfo(title: string, message?: string, duration = 3000): void {
this.showNotification(title, message, "primary", "info-circle", duration);
}

public static showSuccess(title: string, message?: string): void {
this.showNotification(title, message, "success", "check2-circle");
public static showSuccess(title: string, message?: string, duration = 3000): void {
this.showNotification(title, message, "success", "check2-circle", duration);
}

public static showWarning(title: string, message?: string): void {
this.showNotification(title, message, "warning", "exclamation-triangle");
public static showWarning(title: string, message?: string, duration = 3000): void {
this.showNotification(title, message, "warning", "exclamation-triangle", duration);
}

public static showError(title: string, message?: string): void {
this.showNotification(title, message, "danger", "exclamation-octagon");
public static showError(title: string, message?: string, duration = 3000): void {
this.showNotification(title, message, "danger", "exclamation-octagon", duration);
}

public static showNotification(title: string, message: string | undefined, variant: string, icon: string, duration = 3000): Promise<void> {
Expand Down Expand Up @@ -53,4 +53,4 @@ export class Toaster {

return div.innerHTML;
}
}
}

0 comments on commit 6e3efba

Please sign in to comment.