Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.

Commit d3f9208

Browse files
committed
Add authorization to user-notification and entity-permission (WIP)
1 parent e22dddd commit d3f9208

File tree

9 files changed

+78
-66
lines changed

9 files changed

+78
-66
lines changed

client/app/app.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
22
import { MatSidenav } from '@angular/material/sidenav';
33
import { SecondarySidenavComponent } from 'components/sidenav/secondary-sidenav/secondary-sidenav.component';
44
import { SecondarySidenavService } from 'components/sidenav/secondary-sidenav/secondary-sidenav.service';
5-
import { UserNotificationDataService } from 'components/user-notification/user-notification-data.service';
65
import { PageTitleService } from 'components/page-title/page-title.service';
76

87
@Component({
@@ -26,7 +25,7 @@ import { PageTitleService } from 'components/page-title/page-title.service';
2625
<app-secondary-sidenav #secondarySidenavContent></app-secondary-sidenav>
2726
</mat-sidenav>
2827
</mat-sidenav-container>`,
29-
providers: [UserNotificationDataService, PageTitleService],
28+
providers: [PageTitleService],
3029
})
3130
export class AppComponent implements OnInit, AfterViewInit {
3231
@ViewChild('secondarySidenav', { static: true }) private secondarySidenav: MatSidenav;

client/components/page-title/page-title.service.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import { Injectable, OnDestroy } from '@angular/core';
22
import { Title } from '@angular/platform-browser';
33
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
4-
import { map } from 'rxjs/operators';
5-
import { UserNotificationDataService } from 'components/user-notification/user-notification-data.service';
64

75
@Injectable()
86
export class PageTitleService implements OnDestroy {
97
private title: BehaviorSubject<string> = new BehaviorSubject<string>('');
8+
private numNotifications: BehaviorSubject<number> = new BehaviorSubject<number>(0);
109
private subscription: Subscription;
1110

12-
static parameters = [Title, UserNotificationDataService];
13-
constructor(private bodyTitle: Title, private userNotificationDataService: UserNotificationDataService) {
14-
combineLatest(
15-
this.title,
16-
this.userNotificationDataService.notifications().pipe(map(notifications => notifications.length))
17-
).subscribe(
11+
static parameters = [Title];
12+
constructor(private bodyTitle: Title) {
13+
combineLatest(this.title, this.numNotifications).subscribe(
1814
([title, numNotifications]) => {
1915
title = title !== '' ? `${title} | ` : '';
2016
let notification = numNotifications > 0 ? `(${numNotifications}) ` : '';
@@ -33,4 +29,8 @@ export class PageTitleService implements OnDestroy {
3329
setTitle(title: string): void {
3430
this.title.next(title);
3531
}
32+
33+
setNumNotifications(numNotifications: number): void {
34+
this.numNotifications.next(numNotifications);
35+
}
3636
}

client/components/user-notification/user-notification-button/user-notification-button.component.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { Component, OnInit } from '@angular/core';
22
import { UserNotificationSidenavService } from '../user-notification-sidenav/user-notification-sidenav.service';
33
import { UserNotificationDataService } from '../user-notification-data.service';
44
import { Observable } from 'rxjs';
5-
import { map } from 'rxjs/operators';
5+
import { map, tap } from 'rxjs/operators';
6+
import { PageTitleService } from 'components/page-title/page-title.service';
67

78
@Component({
89
selector: 'user-notification-button',
@@ -12,16 +13,18 @@ import { map } from 'rxjs/operators';
1213
export class UserNotificationButtonComponent implements OnInit {
1314
private numNotifications$: Observable<number>; // used in html
1415

15-
static parameters = [UserNotificationDataService, UserNotificationSidenavService];
16+
static parameters = [UserNotificationDataService, UserNotificationSidenavService, PageTitleService];
1617
constructor(
1718
private userNotificationDataService: UserNotificationDataService,
18-
private userNotificationSidenavService: UserNotificationSidenavService
19+
private userNotificationSidenavService: UserNotificationSidenavService,
20+
private pageTitleService: PageTitleService
1921
) {}
2022

2123
ngOnInit() {
22-
this.numNotifications$ = this.userNotificationDataService
23-
.notifications()
24-
.pipe(map(notifications => notifications.length));
24+
this.numNotifications$ = this.userNotificationDataService.notifications().pipe(
25+
tap(notifications => this.pageTitleService.setNumNotifications(notifications.length)),
26+
map(notifications => notifications.length)
27+
);
2528
}
2629

2730
toggleNotifications(): void {

client/components/user-notification/user-notification-data.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@ export class UserNotificationDataService implements OnDestroy {
1313
static parameters = [SocketService, UserNotificationService];
1414
constructor(private socketService: SocketService, private userNotificationService: UserNotificationService) {
1515
this.notificationSocketModel = 'notifications';
16+
1617
// TODO: Need an endpoint to get only the archived notifications
18+
console.log('INIT NOTIFICATION DATA SERVICE');
1719
this.userNotificationService.queryNotifications({ archived: false }).subscribe(
1820
notifications => {
21+
console.log('Number of unarchive notifications', notifications.length);
1922
this.notifications_.next(notifications);
2023
this.socketService.syncArraySubject(
2124
this.notificationSocketModel,
2225
this.notifications_,
2326
(items: UserNotification[]) => {
27+
console.log('received notifications update from websockets');
2428
// TODO: Remove when listening only to unarchive notifications
2529
return flow(
2630
filter<UserNotification>(n => !n.archived),

server/api/entity-permission/entity-permission.events.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,32 @@
22
* EntityPermission model events
33
*/
44

5-
import {EventEmitter} from 'events';
5+
import { EventEmitter } from 'events';
66
var EntityPermissionEvents = new EventEmitter();
77

88
// Set max event listeners (0 == unlimited)
99
EntityPermissionEvents.setMaxListeners(0);
1010

1111
// Model events
1212
var events = {
13-
save: 'save',
14-
remove: 'remove'
13+
save: 'save',
14+
remove: 'remove',
1515
};
1616

1717
// Register the event emitter to the model events
1818
function registerEvents(EntityPermission) {
19-
for(var e in events) {
20-
let event = events[e];
21-
EntityPermission.post(e, emitEvent(event));
22-
}
19+
for (var e in events) {
20+
let event = events[e];
21+
EntityPermission.post(e, emitEvent(event));
22+
}
2323
}
2424

2525
function emitEvent(event) {
26-
return function(doc) {
27-
EntityPermissionEvents.emit(event + ':' + doc._id, doc);
28-
EntityPermissionEvents.emit(event, doc);
29-
};
26+
return function (doc) {
27+
EntityPermissionEvents.emit(`${event}:${doc._id}`, doc);
28+
EntityPermissionEvents.emit(event, doc);
29+
};
3030
}
3131

32-
export {registerEvents};
32+
export { registerEvents };
3333
export default EntityPermissionEvents;

server/api/entity-permission/entity-permission.socket.js

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,23 @@ export function register(spark) {
2121

2222
function createListener(namespace, event, spark) {
2323
return function (doc) {
24-
// TODO Fix authorization
25-
// authBase.canReadEntity(
26-
// spark.userId,
27-
// doc.entityId,
28-
// entityTypes.PROJECT.value,
29-
// doc.visibility,
30-
// Object.values(accessTypes).map(access => access.value),
31-
// [
32-
// inviteStatusTypes.ACCEPTED.value,
33-
// inviteStatusTypes.PENDING.value
34-
// ]
35-
// )
36-
// .then(hasAccess => {
37-
// if (hasAccess) {
38-
spark.emit(`${namespace}:${event}`, doc);
39-
spark.emit(`entity:${doc.entityId}:${namespace}:${event}`, doc);
40-
// }
41-
// })
42-
// .catch(err => console.error(`Unable to create listener: ${err}`));
24+
// For now we only support entity-permission for PROJECT
25+
// ENTITY-PERMISSION ARE NO LONGER USED AS NOTIFICATIONS (SEE NEW USER-NOTIFICATION).
26+
// TODO Use authentication implementation from project api (no duplicated code)
27+
if (doc.entityType === entityTypes.PROJECT.value) {
28+
const isTargetUser = doc.user._id === spark.userId;
29+
const isProjectAdmin = authBase.hasEntityPermission(
30+
spark.userId,
31+
doc.entityId,
32+
entityTypes.PROJECT.value,
33+
[accessTypes.ADMIN.value],
34+
[inviteStatusTypes.ACCEPTED.value]
35+
);
36+
if (isTargetUser || isProjectAdmin) {
37+
spark.emit(`${namespace}:${event}`, doc);
38+
spark.emit(`entity:${doc.entityId}:${namespace}:${event}`, doc);
39+
}
40+
}
4341
};
4442
}
4543

server/api/user-notification/user-notification.socket.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ export function register(spark) {
1919

2020
function createListener(event, spark) {
2121
return doc => {
22-
spark.emit(event, doc);
22+
console.log('Could emit user notification', doc._id);
23+
console.log('doc.user._id', doc.user._id);
24+
console.log('spark.userId', spark.userId);
25+
if (doc && doc.user._id.toString() === spark.userId) {
26+
console.log('EMITTING USER NOTIFICATION', doc);
27+
spark.emit(event, doc);
28+
}
2329
};
2430
}
2531

server/config/seeds/development/entity-notifications.js

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,23 @@ import { adminUserId, testUserId } from './users';
33

44
import { notificationTypes, entityTypes } from '../../environment/shared';
55

6-
let entityNotifications = [{
7-
notificationType: notificationTypes.ENTITY_NOTIFICATION.value,
8-
user: testUserId,
9-
createdBy: adminUserId,
10-
archived: false,
11-
entityId: report2Id,
12-
entityType: entityTypes.INSIGHT.value
13-
},
14-
{
15-
notificationType: notificationTypes.ENTITY_NOTIFICATION.value,
16-
user: adminUserId,
17-
createdBy: testUserId,
18-
archived: false,
19-
entityId: report3Id,
20-
entityType: entityTypes.INSIGHT.value
21-
}];
6+
let entityNotifications = [
7+
{
8+
notificationType: notificationTypes.ENTITY_NOTIFICATION.value,
9+
user: testUserId,
10+
createdBy: adminUserId,
11+
archived: false,
12+
entityId: report2Id,
13+
entityType: entityTypes.INSIGHT.value,
14+
},
15+
{
16+
notificationType: notificationTypes.ENTITY_NOTIFICATION.value,
17+
user: adminUserId,
18+
createdBy: testUserId,
19+
archived: false,
20+
entityId: report3Id,
21+
entityType: entityTypes.INSIGHT.value,
22+
},
23+
];
2224

2325
export { entityNotifications };

server/config/seeds/development/message-notifications.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ let messageNotifications = [{
66
user: adminUserId,
77
createdBy: testUserId,
88
archived: false,
9-
messageBody: 'test message body'
9+
messageBody: 'test message for admin'
1010
},
1111
{
1212
notificationType: notificationTypes.MESSAGE_NOTIFICATION.value,
1313
user: testUserId,
1414
createdBy: adminUserId,
1515
archived: false,
16-
messageBody: 'test message 2'
16+
messageBody: 'test message for test user'
1717
}];
1818

1919
export { messageNotifications };

0 commit comments

Comments
 (0)