Skip to content
This repository was archived by the owner on Apr 16, 2024. It is now read-only.

Commit a9a27e6

Browse files
Merge pull request #732 from h-da/bugfix/731-repair-notification-settings
Repair notification settings
2 parents ac3b2ee + 28c103b commit a9a27e6

File tree

5 files changed

+82
-100
lines changed

5 files changed

+82
-100
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1616
- Reload user list after deleting an account. [#724](https://github.com/h-da/geli/pull/724)
1717
- Validate form before submit when creating a new course. [#724](https://github.com/h-da/geli/pull/724)
1818
- Validate :id for CourseController details route. [#724](https://github.com/h-da/geli/pull/724)
19+
- `getNotificationSettings` does not create new notification settings. [#731](https://github.com/h-da/geli/issues/731)
20+
- Remove `isCourseTeacherOrAdmin` and `isMemberOfCourse`from UserService. [#731](https://github.com/h-da/geli/issues/731)
21+
22+
### Fixed
23+
- Fixed broken notification settings. [#731](https://github.com/h-da/geli/issues/731)
1924

2025
### Fixed
2126
- Fixed broken Apidoc [#737](https://github.com/h-da/geli/issues/737)

app/webFrontend/src/app/models/NotificationSettings.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import {INotificationSettings} from '../../../../../shared/models/INotificationSettings';
2-
import {ICourse} from '../../../../../shared/models/ICourse';
32
import {IUser} from '../../../../../shared/models/IUser';
3+
import {ICourseDashboard} from '../../../../../shared/models/ICourseDashboard';
44

55
export class NotificationSettings implements INotificationSettings {
66

77
_id: any;
8-
course: ICourse;
8+
course: ICourseDashboard;
99
user: IUser;
1010
notificationType: string;
1111
emailNotification: boolean;
1212

13-
constructor(user: IUser, course: ICourse) {
13+
constructor(user: IUser, course: ICourseDashboard) {
1414
this.course = course;
1515
this.user = user;
1616
}

app/webFrontend/src/app/shared/services/user.service.ts

-19
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,4 @@ export class UserService {
4444
isLoggedInUser(user: IUser): boolean {
4545
return this.user._id === user._id;
4646
}
47-
48-
isCourseTeacherOrAdmin(course: ICourse) {
49-
if (this.isStudent()) {
50-
return false;
51-
}
52-
if (this.isAdmin()) {
53-
return true;
54-
}
55-
56-
if (course.courseAdmin._id === this.user._id) {
57-
return true;
58-
}
59-
60-
return ( course.teachers.filter(teacher => teacher._id === this.user._id).length);
61-
}
62-
63-
isMemberOfCourse(course: ICourse) {
64-
return course.students.filter(obj => obj._id === this.user._id).length > 0;
65-
}
6647
}
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,126 @@
11
import {Component, OnInit} from '@angular/core';
22
import {UserService} from '../../shared/services/user.service';
33
import {CourseService, NotificationSettingsService} from '../../shared/services/data.service';
4-
import {ICourse} from '../../../../../../shared/models/ICourse';
5-
import {MatSnackBar, MatTableDataSource} from '@angular/material';
4+
import {MatTableDataSource} from '@angular/material';
5+
import {SnackBarService} from '../../shared/services/snack-bar.service';
66
import {SelectionModel} from '@angular/cdk/collections';
77
import {
8-
INotificationSettings, NOTIFICATION_TYPE_ALL_CHANGES,
8+
INotificationSettings,
9+
NOTIFICATION_TYPE_ALL_CHANGES,
910
NOTIFICATION_TYPE_NONE
1011
} from '../../../../../../shared/models/INotificationSettings';
1112
import {NotificationSettings} from '../../models/NotificationSettings';
12-
import {isNullOrUndefined} from 'util';
13-
import {AfterContentInit} from '@angular/core/src/metadata/lifecycle_hooks';
13+
import {ICourseDashboard} from '../../../../../../shared/models/ICourseDashboard';
1414

1515
@Component({
1616
selector: 'app-user-settings',
1717
templateUrl: './user-settings.component.html',
1818
styleUrls: ['./user-settings.component.scss']
1919
})
20-
export class UserSettingsComponent implements OnInit, AfterContentInit {
20+
export class UserSettingsComponent implements OnInit {
2121

22-
myCourses: ICourse[];
22+
myCourses: ICourseDashboard[];
2323
displayedColumns = ['name', 'Notifications', 'email'];
24-
dataSource: MatTableDataSource<ICourse>;
25-
notificationSelection = new SelectionModel<ICourse>(true, []);
26-
emailSelection = new SelectionModel<ICourse>(true, []);
24+
dataSource: MatTableDataSource<ICourseDashboard>;
25+
notificationSelection = new SelectionModel<ICourseDashboard>(true, []);
26+
emailSelection = new SelectionModel<ICourseDashboard>(true, []);
2727
notificationSettings: INotificationSettings[];
2828

29-
constructor(public userService: UserService,
30-
public courseService: CourseService,
31-
public notificationSettingsService: NotificationSettingsService,
32-
public snackBar: MatSnackBar) {
29+
constructor(private userService: UserService,
30+
private courseService: CourseService,
31+
private notificationSettingsService: NotificationSettingsService,
32+
private snackBar: SnackBarService) {
3333
}
3434

35-
ngOnInit() {
36-
this.getCourses();
37-
this.getNotificationSettings().then(() => {
38-
this.setSelection();
39-
});
40-
}
41-
async ngAfterContentInit() {
35+
async ngOnInit() {
36+
await this.getCourses();
4237
await this.getNotificationSettings();
43-
this.setSelection();
38+
this.setSelection();
4439
}
4540

46-
getCourses() {
41+
async getCourses() {
4742
this.myCourses = [];
48-
this.courseService.readItems().then(courses => {
49-
courses.forEach((course: ICourse) => {
50-
if (this.userService.isMemberOfCourse(course)) {
51-
this.myCourses.push(course);
52-
}
53-
});
54-
this.dataSource = new MatTableDataSource<ICourse>(this.myCourses);
55-
});
43+
try {
44+
this.myCourses = (await this.courseService.readItems<ICourseDashboard>())
45+
.filter((course: ICourseDashboard) => course.userIsCourseMember);
46+
this.dataSource = new MatTableDataSource<ICourseDashboard>(this.myCourses);
47+
} catch (err) {
48+
this.snackBar.open('Could not fetch courses');
49+
}
5650
}
5751

5852
async getNotificationSettings() {
59-
const settings = await this.notificationSettingsService.getNotificationSettingsPerUser(this.userService.user);
60-
if (settings.length <= 0) {
61-
await Promise.all(this.myCourses.map(async (course) => {
62-
const newSetting = await this.notificationSettingsService.createItem({user: this.userService.user, course: course});
63-
settings.push(newSetting);
64-
}));
65-
}
66-
this.notificationSettings = settings;
53+
this.notificationSettings = await this.notificationSettingsService.getNotificationSettingsPerUser(this.userService.user);
6754
}
6855

6956
setSelection() {
70-
if (this.notificationSettings) {
71-
this.notificationSettings.forEach((setting: INotificationSettings) => {
72-
const courseWithNotificationSettings = this.myCourses.find(x => x._id === setting.course._id);
73-
if (courseWithNotificationSettings) {
74-
if (setting.notificationType === NOTIFICATION_TYPE_ALL_CHANGES) {
75-
this.notificationSelection.select(courseWithNotificationSettings);
76-
}
77-
if (setting.emailNotification) {
78-
this.emailSelection.select(courseWithNotificationSettings);
79-
}
80-
}
81-
});
57+
if (!this.notificationSettings) {
58+
return;
8259
}
60+
61+
this.notificationSettings.forEach((setting: INotificationSettings) => {
62+
const course = this.myCourses.find(tmp => tmp._id === setting.course._id);
63+
64+
if (course === undefined) {
65+
return;
66+
}
67+
68+
if (setting.notificationType === NOTIFICATION_TYPE_ALL_CHANGES) {
69+
this.notificationSelection.select(course);
70+
}
71+
72+
if (setting.emailNotification) {
73+
this.emailSelection.select(course);
74+
}
75+
});
8376
}
8477

85-
saveNotificationSettings() {
86-
try {
87-
this.myCourses.forEach(async course => {
88-
let settings: INotificationSettings;
89-
this.notificationSettings.forEach((x) => {
90-
if (x.course._id === course._id) {
91-
settings = x;
92-
}
93-
});
94-
if (settings === null || settings === undefined) {
78+
async saveNotificationSettings() {
79+
const errors = [];
80+
81+
for (const course of this.myCourses) {
82+
try {
83+
let settings = this.notificationSettings.find(tmp => tmp.course._id === course._id);
84+
85+
if (settings === undefined) {
9586
settings = await this.notificationSettingsService.createItem(new NotificationSettings(this.userService.user, course));
9687
this.notificationSettings.push(settings);
9788
}
89+
9890
if (this.notificationSelection.isSelected(course)) {
9991
settings.notificationType = NOTIFICATION_TYPE_ALL_CHANGES;
10092
} else {
10193
settings.notificationType = NOTIFICATION_TYPE_NONE;
10294
}
95+
10396
if (this.emailSelection.isSelected(course)) {
10497
settings.emailNotification = true;
10598
} else {
10699
settings.emailNotification = false;
107100
}
101+
108102
await this.notificationSettingsService.updateItem(settings);
109-
});
110-
this.snackBar.open('Notification settings updated successfully.', '', {duration: 3000});
111-
} catch (error) {
112-
this.snackBar.open(error.message, 'Dismiss');
103+
} catch (err) {
104+
if (errors.indexOf(err.error.message) === -1) {
105+
errors.push(err.error.message);
106+
}
107+
}
113108
}
114-
}
115109

116-
isAllSelected(selectionModel: SelectionModel<ICourse>) {
117-
const numSelected = selectionModel.selected.length;
118-
const numRows = this.dataSource.data.length;
119-
return numSelected === numRows;
110+
if (errors.length === 0) {
111+
this.snackBar.open('Notification settings updated successfully.');
112+
} else {
113+
this.snackBar.openLong('Failed to save notification settings: ' + errors.join(', '));
114+
}
120115
}
121116

122-
masterToggle(selectionModel: SelectionModel<ICourse>) {
123-
this.isAllSelected(selectionModel) ?
124-
selectionModel.clear() :
125-
this.dataSource.data.forEach(row => selectionModel.select(row));
117+
isAllSelected(selectionModel: SelectionModel<ICourseDashboard>) {
118+
return selectionModel.selected.length === this.dataSource.data.length;
126119
}
127120

128-
121+
masterToggle(selectionModel: SelectionModel<ICourseDashboard>) {
122+
this.isAllSelected(selectionModel)
123+
? selectionModel.clear()
124+
: this.dataSource.data.forEach(row => selectionModel.select(row));
125+
}
129126
}

shared/models/INotificationSettings.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {ICourse} from './ICourse';
21
import {IUser} from './IUser';
2+
import {ICourseDashboard} from './ICourseDashboard';
33

44
export const NOTIFICATION_TYPE_NONE = 'none';
55
export const NOTIFICATION_TYPE_CHANGES_WITH_RELATIONIONSHIP = 'relatedChanges';
@@ -12,9 +12,8 @@ export const NOTIFICATION_TYPES = [
1212

1313
export interface INotificationSettings {
1414
_id: any;
15-
course: ICourse;
15+
course: ICourseDashboard;
1616
user: IUser;
1717
notificationType: string;
1818
emailNotification: boolean;
1919
}
20-

0 commit comments

Comments
 (0)