Skip to content
Snippets Groups Projects
Commit b33540e1 authored by Sebastian Wittek's avatar Sebastian Wittek
Browse files

Merge branch 'remove-subject' into 'master'

Comment Microservice Binding

See merge request swtp-2019/arsnova-lite!20
parents 0e25a400 73a2b992
No related merge requests found
Showing
with 199 additions and 69 deletions
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
"rxjs": "^6.3.3", "rxjs": "^6.3.3",
"rxjs-compat": "^6.2.2", "rxjs-compat": "^6.2.2",
"tslint-eslint-rules": "^5.3.1", "tslint-eslint-rules": "^5.3.1",
"typescript-map": "0.0.7",
"zone.js": "^0.8.26" "zone.js": "^0.8.26"
}, },
"devDependencies": { "devDependencies": {
......
{ {
"/api/comment": {
"target": "http://localhost:8088",
"secure": false,
"pathRewrite": {
"^/api": ""
},
"logLevel": "debug"
},
"/api": { "/api": {
"target": "http://localhost:8080", "target": "http://localhost:8080",
"secure": false, "secure": false,
......
<div fxLayout="column" fxLayoutAlign="center" fxLayoutGap="20px"> <div fxLayout="column" fxLayoutAlign="center" fxLayoutGap="20px">
<div fxLayout="row" fxLayoutAlign="center"> <div fxLayout="row" fxLayoutAlign="center">
<form> <form>
<mat-form-field class="input-block">
<input matInput #commentSubject type="text" maxlength="25"
placeholder="{{ 'comment-page.enter-title' | translate}}" onkeypress="return event.keyCode !=13;"
[formControl]="subjectForm">
<mat-hint align="end">{{commentSubject.value.length}} / 25</mat-hint>
</mat-form-field>
<mat-form-field class="input-block"> <mat-form-field class="input-block">
<textarea matInput #commentBody placeholder="{{ 'comment-page.enter-comment' | translate}}" <textarea matInput #commentBody placeholder="{{ 'comment-page.enter-comment' | translate}}"
matAutosizeMinRows=2 matAutosizeMaxRows=5 maxlength="255" [formControl]="bodyForm"></textarea> matAutosizeMinRows=2 matAutosizeMaxRows=5 maxlength="255" [formControl]="bodyForm"></textarea>
...@@ -15,7 +9,7 @@ ...@@ -15,7 +9,7 @@
<button mat-raised-button color="warn" <button mat-raised-button color="warn"
(click)="onNoClick()">{{ 'comment-page.abort' | translate}}</button> (click)="onNoClick()">{{ 'comment-page.abort' | translate}}</button>
<button mat-raised-button color="accent" <button mat-raised-button color="accent"
(click)="closeDialog(commentSubject.value, commentBody.value)">{{ 'comment-page.send' | translate}}</button> (click)="closeDialog(commentBody.value)">{{ 'comment-page.send' | translate}}</button>
</form> </form>
</div> </div>
</div> </div>
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, OnInit } from '@angular/core';
import { Comment } from '../../../../models/comment'; import { Comment } from '../../../../models/comment';
import { ActivatedRoute } from '@angular/router';
import { NotificationService } from '../../../../services/util/notification.service'; import { NotificationService } from '../../../../services/util/notification.service';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CommentPageComponent } from '../../comment-page/comment-page.component'; import { CommentPageComponent } from '../../comment-page/comment-page.component';
import { AuthenticationService } from '../../../../services/http/authentication.service';
import { FormControl, Validators } from '@angular/forms'; import { FormControl, Validators } from '@angular/forms';
import { User } from '../../../../models/user'; import { User } from '../../../../models/user';
...@@ -20,16 +18,16 @@ export class SubmitCommentComponent implements OnInit { ...@@ -20,16 +18,16 @@ export class SubmitCommentComponent implements OnInit {
comment: Comment; comment: Comment;
user: User; user: User;
roomId: string;
subjectForm = new FormControl('', [Validators.required]); subjectForm = new FormControl('', [Validators.required]);
bodyForm = new FormControl('', [Validators.required]); bodyForm = new FormControl('', [Validators.required]);
private date = new Date(Date.now()); private date = new Date(Date.now());
constructor(private route: ActivatedRoute, constructor(
private notification: NotificationService, private notification: NotificationService,
public dialogRef: MatDialogRef<CommentPageComponent>, public dialogRef: MatDialogRef<CommentPageComponent>,
private translateService: TranslateService, private translateService: TranslateService,
protected authenticationService: AuthenticationService,
public dialog: MatDialog, public dialog: MatDialog,
private translationService: TranslateService, private translationService: TranslateService,
@Inject(MAT_DIALOG_DATA) public data: any) { @Inject(MAT_DIALOG_DATA) public data: any) {
...@@ -37,28 +35,14 @@ export class SubmitCommentComponent implements OnInit { ...@@ -37,28 +35,14 @@ export class SubmitCommentComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.translateService.use(localStorage.getItem('currentLang')); this.translateService.use(localStorage.getItem('currentLang'));
this.user = this.authenticationService.getUser();
} }
onNoClick(): void { onNoClick(): void {
this.dialogRef.close(); this.dialogRef.close();
} }
checkInputData(subject: string, body: string): boolean { checkInputData(body: string): boolean {
subject = subject.trim();
body = body.trim(); body = body.trim();
if (!subject && !body) {
this.translationService.get('comment-page.error-both-fields').subscribe(message => {
this.notification.show(message);
});
return false;
}
if (!subject) {
this.translationService.get('comment-page.error-title').subscribe(message => {
this.notification.show(message);
});
return false;
}
if (!body) { if (!body) {
this.translationService.get('comment-page.error-comment').subscribe(message => { this.translationService.get('comment-page.error-comment').subscribe(message => {
this.notification.show(message); this.notification.show(message);
...@@ -68,11 +52,10 @@ export class SubmitCommentComponent implements OnInit { ...@@ -68,11 +52,10 @@ export class SubmitCommentComponent implements OnInit {
return true; return true;
} }
closeDialog(subject: string, body: string) { closeDialog(body: string) {
if (this.checkInputData(subject, body) === true) { if (this.checkInputData(body) === true) {
const comment = new Comment(); const comment = new Comment();
comment.roomId = localStorage.getItem(`roomId`); comment.roomId = localStorage.getItem(`roomId`);
comment.subject = subject;
comment.body = body; comment.body = body;
comment.userId = this.user.id; comment.userId = this.user.id;
this.dialogRef.close(comment); this.dialogRef.close(comment);
......
...@@ -3,6 +3,8 @@ import { Comment } from '../../../models/comment'; ...@@ -3,6 +3,8 @@ import { Comment } from '../../../models/comment';
import { CommentService } from '../../../services/http/comment.service'; import { CommentService } from '../../../services/http/comment.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { LanguageService } from '../../../services/util/language.service'; import { LanguageService } from '../../../services/util/language.service';
import { RxStompService } from '@stomp/ng2-stompjs';
import { Message } from '@stomp/stompjs';
@Component({ @Component({
selector: 'app-comment-list', selector: 'app-comment-list',
...@@ -18,13 +20,18 @@ export class CommentListComponent implements OnInit { ...@@ -18,13 +20,18 @@ export class CommentListComponent implements OnInit {
constructor(private commentService: CommentService, constructor(private commentService: CommentService,
private translateService: TranslateService, private translateService: TranslateService,
protected langService: LanguageService) { protected langService: LanguageService,
private rxStompService: RxStompService) {
langService.langEmitter.subscribe(lang => translateService.use(lang)); langService.langEmitter.subscribe(lang => translateService.use(lang));
} }
ngOnInit() { ngOnInit() {
this.roomId = localStorage.getItem(`roomId`); this.roomId = localStorage.getItem(`roomId`);
this.comments = [];
this.hideCommentsList = false; this.hideCommentsList = false;
this.rxStompService.watch(`/topic/${this.roomId}.comment.stream`).subscribe((message: Message) => {
this.parseIncomingMessage(message);
});
this.getComments(); this.getComments();
this.translateService.use(localStorage.getItem('currentLang')); this.translateService.use(localStorage.getItem('currentLang'));
} }
...@@ -40,4 +47,39 @@ export class CommentListComponent implements OnInit { ...@@ -40,4 +47,39 @@ export class CommentListComponent implements OnInit {
searchComments(term: string): void { searchComments(term: string): void {
this.filteredComments = this.comments.filter(c => c.body.toLowerCase().includes(term)); this.filteredComments = this.comments.filter(c => c.body.toLowerCase().includes(term));
} }
parseIncomingMessage(message: Message) {
const msg = JSON.parse(message.body);
const payload = msg.payload;
if (msg.type === 'CommentCreated') {
const c = new Comment();
c.roomId = this.roomId;
c.body = payload.body;
c.id = payload.id;
c.creationTimestamp = payload.timestamp;
this.comments = this.comments.concat(c);
} else if (msg.type === 'CommentPatched') {
const c = this.comments.find((comment: Comment) => comment.id === payload.id);
if (c) {
const index = this.comments.indexOf(c);
console.log(index);
const newList = this.comments.slice(0);
const changes = payload.changes;
// ToDo: there must be a better way to update the model
for (const change of changes) {
console.log(change);
if (change.read) {
c.read = change.read;
} else if (change.favorite) {
c.favorite = change.favorite;
} else if (change.correct) {
c.correct = change.correct;
}
}
newList[index] = c;
this.comments = newList;
}
}
}
} }
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Comment } from '../../../models/comment'; import { Comment } from '../../../models/comment';
import { CommentService } from '../../../services/http/comment.service'; import { User } from '../../../models/user';
import { NotificationService } from '../../../services/util/notification.service'; import { NotificationService } from '../../../services/util/notification.service';
import { CommentListComponent } from '../comment-list/comment-list.component'; import { AuthenticationService } from '../../../services/http/authentication.service';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { SubmitCommentComponent } from '../_dialogs/submit-comment/submit-comment.component'; import { SubmitCommentComponent } from '../_dialogs/submit-comment/submit-comment.component';
import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service';
@Component({ @Component({
selector: 'app-comment-page', selector: 'app-comment-page',
...@@ -13,20 +14,26 @@ import { SubmitCommentComponent } from '../_dialogs/submit-comment/submit-commen ...@@ -13,20 +14,26 @@ import { SubmitCommentComponent } from '../_dialogs/submit-comment/submit-commen
styleUrls: ['./comment-page.component.scss'] styleUrls: ['./comment-page.component.scss']
}) })
export class CommentPageComponent implements OnInit { export class CommentPageComponent implements OnInit {
@ViewChild(CommentListComponent) child: CommentListComponent; roomId: string;
user: User;
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private commentService: CommentService,
private notification: NotificationService, private notification: NotificationService,
public dialog: MatDialog) { } public dialog: MatDialog,
private authenticationService: AuthenticationService,
private wsCommentService: WsCommentServiceService) { }
ngOnInit(): void { ngOnInit(): void {
this.roomId = localStorage.getItem('roomId');
this.user = this.authenticationService.getUser();
} }
openSubmitDialog(): void { openSubmitDialog(): void {
const dialogRef = this.dialog.open(SubmitCommentComponent, { const dialogRef = this.dialog.open(SubmitCommentComponent, {
width: '400px' width: '400px'
}); });
dialogRef.componentInstance.user = this.user;
dialogRef.componentInstance.roomId = this.roomId;
dialogRef.afterClosed() dialogRef.afterClosed()
.subscribe(result => { .subscribe(result => {
if (result) { if (result) {
...@@ -38,19 +45,6 @@ export class CommentPageComponent implements OnInit { ...@@ -38,19 +45,6 @@ export class CommentPageComponent implements OnInit {
} }
send(comment: Comment): void { send(comment: Comment): void {
this.commentService.addComment({ this.wsCommentService.add(comment);
id: '',
roomId: comment.roomId,
userId: comment.userId,
subject: comment.subject,
body: comment.body,
creationTimestamp: comment.creationTimestamp,
read: false,
revision: ''
} as Comment).subscribe(() => {
this.child.getComments();
this.notification.show(`Comment '${comment.subject}' successfully created.`);
});
} }
} }
...@@ -7,6 +7,7 @@ import { CommentService } from '../../../services/http/comment.service'; ...@@ -7,6 +7,7 @@ import { CommentService } from '../../../services/http/comment.service';
import { NotificationService } from '../../../services/util/notification.service'; import { NotificationService } from '../../../services/util/notification.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { LanguageService } from '../../../services/util/language.service'; import { LanguageService } from '../../../services/util/language.service';
import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service';
@Component({ @Component({
selector: 'app-comment', selector: 'app-comment',
...@@ -24,7 +25,8 @@ export class CommentComponent implements OnInit { ...@@ -24,7 +25,8 @@ export class CommentComponent implements OnInit {
private commentService: CommentService, private commentService: CommentService,
private notification: NotificationService, private notification: NotificationService,
private translateService: TranslateService, private translateService: TranslateService,
protected langService: LanguageService) { protected langService: LanguageService,
private wsCommentService: WsCommentServiceService) {
langService.langEmitter.subscribe(lang => translateService.use(lang)); } langService.langEmitter.subscribe(lang => translateService.use(lang)); }
ngOnInit() { ngOnInit() {
...@@ -35,23 +37,23 @@ export class CommentComponent implements OnInit { ...@@ -35,23 +37,23 @@ export class CommentComponent implements OnInit {
} }
setRead(comment: Comment): void { setRead(comment: Comment): void {
comment.read = !comment.read; this.comment = this.wsCommentService.toggleRead(comment);
this.commentService.updateComment(comment).subscribe(); // this.commentService.updateComment(comment).subscribe();
} }
setCorrect(comment: Comment): void { setCorrect(comment: Comment): void {
comment.correct = !comment.correct; this.comment = this.wsCommentService.toggleCorrect(comment);
this.commentService.updateComment(comment).subscribe(); // this.commentService.updateComment(comment).subscribe();
} }
setFavorite(comment: Comment): void { setFavorite(comment: Comment): void {
comment.favorite = !comment.favorite; this.comment = this.wsCommentService.toggleFavorite(comment);
this.commentService.updateComment(comment).subscribe(); // this.commentService.updateComment(comment).subscribe();
} }
delete(comment: Comment): void { delete(comment: Comment): void {
this.commentService.deleteComment(comment.id).subscribe(room => { this.commentService.deleteComment(comment.id).subscribe(room => {
this.notification.show(`Comment '${comment.subject}' successfully deleted.`); this.notification.show(`Comment '${comment.body}' successfully deleted.`);
}); });
} }
} }
...@@ -36,14 +36,14 @@ export class FeedbackBarometerPageComponent implements OnInit { ...@@ -36,14 +36,14 @@ export class FeedbackBarometerPageComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.userRole = this.authenticationService.getRole(); this.userRole = this.authenticationService.getRole();
this.rxStompService.watch(`/room/${this.roomId}/feedback.stream`).subscribe((message: Message) => { this.rxStompService.watch(`/queue/${this.roomId}.feedback.stream`).subscribe((message: Message) => {
this.parseIncomingMessage(message); this.parseIncomingMessage(message);
}); });
const getFeedback = new GetFeedback(); const getFeedback = new GetFeedback();
this.rxStompService.publish({ this.rxStompService.publish({
destination: `/backend/room/${this.roomId}/feedback.query`, destination: `/backend/queue/${this.roomId}.feedback.query`,
body: JSON.stringify(getFeedback) body: JSON.stringify(getFeedback)
}); });
} }
...@@ -59,7 +59,7 @@ export class FeedbackBarometerPageComponent implements OnInit { ...@@ -59,7 +59,7 @@ export class FeedbackBarometerPageComponent implements OnInit {
submitFeedback(state: number) { submitFeedback(state: number) {
const createFeedback = new CreateFeedback(state); const createFeedback = new CreateFeedback(state);
this.rxStompService.publish({ this.rxStompService.publish({
destination: `/backend/room/${this.roomId}/feedback.command`, destination: `/backend/queue/${this.roomId}.feedback.command`,
body: JSON.stringify(createFeedback) body: JSON.stringify(createFeedback)
}); });
} }
......
...@@ -3,26 +3,23 @@ export class Comment { ...@@ -3,26 +3,23 @@ export class Comment {
roomId: string; roomId: string;
userId: string; userId: string;
revision: string; revision: string;
subject: string;
body: string; body: string;
read: boolean; read: boolean;
correct: boolean; correct: boolean;
favorite: boolean; favorite: boolean;
creationTimestamp: number; creationTimestamp: Date;
constructor(roomId: string = '', constructor(roomId: string = '',
userId: string = '', userId: string = '',
subject: string = '',
body: string = '', body: string = '',
read: boolean = false, read: boolean = false,
correct: boolean = false, correct: boolean = false,
favorite: boolean = false, favorite: boolean = false,
creationTimestamp: number = 0) { creationTimestamp: Date = null) {
this.id = ''; this.id = '';
this.roomId = roomId; this.roomId = roomId;
this.userId = userId; this.userId = userId;
this.revision = ''; this.revision = '';
this.subject = subject;
this.body = body; this.body = body;
this.read = read; this.read = read;
this.correct = correct; this.correct = correct;
......
export class CreateComment {
type: string;
payload: {
roomId: string;
creatorId: string;
body: string;
};
constructor(roomId: string, creatorId: string, body: string) {
this.type = 'CreateComment';
this.payload = {
roomId: roomId,
creatorId: creatorId,
body: body
};
}
}
import { TSMap } from 'typescript-map';
export class PatchComment {
type: string;
payload: {
id: string;
changes: TSMap<string, any>;
};
constructor(id: string, changes: TSMap<string, any>) {
this.type = 'PatchComment';
this.payload = {
id: id,
changes: changes
};
}
}
...@@ -18,6 +18,6 @@ export const myRxStompConfig: InjectableRxStompConfig = { ...@@ -18,6 +18,6 @@ export const myRxStompConfig: InjectableRxStompConfig = {
// It can be quite verbose, not recommended in production // It can be quite verbose, not recommended in production
// Skip this key to stop logging to console // Skip this key to stop logging to console
debug: (msg: string): void => { debug: (msg: string): void => {
// console.log(new Date(), 'STOMP debug: ' + msg); console.log(new Date(), 'STOMP debug: ' + msg);
} }
}; };
...@@ -32,8 +32,7 @@ export class CommentService extends BaseHttpService { ...@@ -32,8 +32,7 @@ export class CommentService extends BaseHttpService {
addComment(comment: Comment): Observable<Comment> { addComment(comment: Comment): Observable<Comment> {
const connectionUrl = this.apiUrl.base + this.apiUrl.comment + '/'; const connectionUrl = this.apiUrl.base + this.apiUrl.comment + '/';
return this.http.post<Comment>(connectionUrl, return this.http.post<Comment>(connectionUrl,
{ { roomId: comment.roomId, body: comment.body,
roomId: comment.roomId, subject: comment.subject, body: comment.body,
read: comment.read, creationTimestamp: comment.creationTimestamp read: comment.read, creationTimestamp: comment.creationTimestamp
}, httpOptions).pipe( }, httpOptions).pipe(
tap(_ => ''), tap(_ => ''),
......
/* import { TestBed } from '@angular/core/testing';
import { WsCommentServiceService } from './ws-comment-service.service';
describe('WsCommentServiceService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: WsCommentServiceService = TestBed.get(WsCommentServiceService);
expect(service).toBeTruthy();
});
});
*/
import { Injectable } from '@angular/core';
import { Comment } from '../../models/comment';
import { RxStompService } from '@stomp/ng2-stompjs';
import { CreateComment } from '../../models/messages/create-comment';
import { PatchComment } from '../../models/messages/patch-comment';
import { TSMap } from 'typescript-map';
@Injectable({
providedIn: 'root'
})
export class WsCommentServiceService {
constructor(private rxStompService: RxStompService) { }
add(comment: Comment): void {
const message = new CreateComment(comment.roomId, comment.userId, comment.body);
this.rxStompService.publish({
destination: `/queue/comment.command.create`,
body: JSON.stringify(message),
headers: {
'content-type': 'application/json'
}
});
}
toggleRead(comment: Comment): Comment {
console.log(comment);
comment.read = !comment.read;
const changes = new TSMap<string, any>();
changes.set('read', comment.read);
this.patchComment(comment, changes);
return comment;
}
toggleFavorite(comment: Comment): Comment {
comment.favorite = !comment.favorite;
const changes = new TSMap<string, any>();
changes.set('favorite', comment.favorite);
this.patchComment(comment, changes);
return comment;
}
toggleCorrect(comment: Comment): Comment {
comment.correct = !comment.correct;
const changes = new TSMap<string, any>();
changes.set('correct', comment.correct);
this.patchComment(comment, changes);
return comment;
}
private patchComment(comment: Comment, changes: TSMap<string, any>): void {
const message = new PatchComment(comment.id, changes);
console.log(message);
this.rxStompService.publish({
destination: `/queue/comment.command.patch`,
body: JSON.stringify(message),
headers: {
'content-type': 'application/json'
}
});
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment