Skip to content

Commit

Permalink
move permission function into BaseService
Browse files Browse the repository at this point in the history
  • Loading branch information
EzzatOmar committed Nov 22, 2023
1 parent f52f803 commit 71fb3a0
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 129 deletions.
83 changes: 83 additions & 0 deletions apps/server/src/modules/board/service/base.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
AnyBoardDo,
AnyContentElementDo,
Card,
Column,
ColumnBoard,
Expand Down Expand Up @@ -34,6 +35,88 @@ export abstract class BaseService {
protected readonly courseRepo: CourseRepo
) {}

protected async createBoardPermissionCtx(
referenceId: EntityId,
parentReferenceId: EntityId | null,
name?: string
): Promise<PermissionContextEntity> {
const parentContext = parentReferenceId
? await this.permissionCtxRepo.findByContextReference(parentReferenceId)
: null;

const permissionCtxEntity = new PermissionContextEntity({
name,
parentContext,
contextReference: new ObjectId(referenceId),
});
await this.permissionCtxRepo.save(permissionCtxEntity);

return permissionCtxEntity;
}

protected async pocCreateSubmissionItemPermissionCtx(
userId: EntityId,
submissionContainer: SubmissionContainerElement,
submissionItemId: EntityId
) {
// NOTE: this will be simplified once we have user groups
const parentContext = await this.permissionCtxRepo.findByContextReference(submissionContainer.id);

const rootId = (await this.boardDoRepo.getAncestorIds(submissionContainer))[0];
const columnBoard = await this.boardDoRepo.findByClassAndId(ColumnBoard, rootId);
const course = await this.courseRepo.findById(columnBoard.context.id);
const revokeStudentsPermissions = course.students
.getItems()
.filter((student) => student.id !== userId)
.map((student) => {
return {
userId: student.id,
includedPermissions: [],
excludedPermissions: [PermissionCrud.UPDATE, PermissionCrud.DELETE],
};
});

const permissionCtxEntity = new PermissionContextEntity({
name: 'Element permission context',
parentContext,
contextReference: new ObjectId(submissionItemId),
userDelta: new UserDelta(revokeStudentsPermissions),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
}

protected async pocCreateElementPermissionCtx(element: AnyContentElementDo, parent: Card | SubmissionItem) {
const parentContext = await this.permissionCtxRepo.findByContextReference(parent.id);

if (element instanceof SubmissionContainerElement) {
// NOTE: this will be simplified once we have user groups
const rootId = (await this.boardDoRepo.getAncestorIds(parent))[0];
const columnBoard = await this.boardDoRepo.findByClassAndId(ColumnBoard, rootId);
const course = await this.courseRepo.findById(columnBoard.context.id);
const updatedStudentsPermissions = course.students.getItems().map((student) => {
return {
userId: student.id,
includedPermissions: [PermissionCrud.CREATE],
excludedPermissions: [],
};
});
const permissionCtxEntity = new PermissionContextEntity({
name: 'SubmissionContainerElement permission context',
parentContext,
contextReference: new ObjectId(element.id),
userDelta: new UserDelta(updatedStudentsPermissions),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
} else {
const permissionCtxEntity = new PermissionContextEntity({
name: 'Element permission context',
parentContext,
contextReference: new ObjectId(element.id),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
}
}

// NOTE: this is a idempotent in-place migration for POC purposes
protected async pocMigrateBoardToPermissionContext(id: EntityId) {
const hasPermissionContext = await this.permissionCtxRepo
Expand Down
25 changes: 11 additions & 14 deletions apps/server/src/modules/board/service/card.service.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { Card, Column, ContentElementType, EntityId, PermissionContextEntity } from '@shared/domain';
import { PermissionContextRepo } from '@shared/repo';
import { Card, Column, ContentElementType, EntityId } from '@shared/domain';
import { CourseRepo, PermissionContextRepo } from '@shared/repo';
import { ObjectId } from 'bson';
import { BoardDoRepo } from '../repo';
import { BoardDoService } from './board-do.service';
import { ContentElementService } from './content-element.service';
import { BaseService } from './base.service';

@Injectable()
export class CardService {
export class CardService extends BaseService {
constructor(
private readonly boardDoRepo: BoardDoRepo,
protected readonly boardDoRepo: BoardDoRepo,
private readonly boardDoService: BoardDoService,
private readonly contentElementService: ContentElementService,
private readonly permissionCtxRepo: PermissionContextRepo
) {}
protected readonly permissionCtxRepo: PermissionContextRepo,
protected readonly courseRepo: CourseRepo
) {
super(permissionCtxRepo, boardDoRepo, courseRepo);
}

async findById(cardId: EntityId): Promise<Card> {
return this.boardDoRepo.findByClassAndId(Card, cardId);
Expand All @@ -40,14 +44,7 @@ export class CardService {

parent.addChild(card);

const parentContext = await this.permissionCtxRepo.findByContextReference(parent.id);
const permissionCtxEntity = new PermissionContextEntity({
name: 'Card permission context',
parentContext,
contextReference: new ObjectId(card.id),
});
await this.permissionCtxRepo.save(permissionCtxEntity);

await this.createBoardPermissionCtx(card.id, parent.id, 'Card permission context');
await this.boardDoRepo.save(parent.children, parent);

if (requiredEmptyElements) {
Expand Down
24 changes: 11 additions & 13 deletions apps/server/src/modules/board/service/column.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { Injectable } from '@nestjs/common';
import { Column, ColumnBoard, EntityId, PermissionContextEntity } from '@shared/domain';
import { Column, ColumnBoard, EntityId } from '@shared/domain';
import { ObjectId } from 'bson';
import { PermissionContextRepo } from '@shared/repo';
import { CourseRepo, PermissionContextRepo } from '@shared/repo';
import { BoardDoRepo } from '../repo';
import { BoardDoService } from './board-do.service';
import { BaseService } from './base.service';

@Injectable()
export class ColumnService {
export class ColumnService extends BaseService {
constructor(
private readonly boardDoRepo: BoardDoRepo,
protected readonly boardDoRepo: BoardDoRepo,
private readonly boardDoService: BoardDoService,
private readonly permissionCtxRepo: PermissionContextRepo
) {}
protected readonly permissionCtxRepo: PermissionContextRepo,
protected readonly courseRepo: CourseRepo
) {
super(permissionCtxRepo, boardDoRepo, courseRepo);
}

async findById(columnId: EntityId): Promise<Column> {
const column = await this.boardDoRepo.findByClassAndId(Column, columnId);
Expand All @@ -29,13 +33,7 @@ export class ColumnService {

parent.addChild(column);

const parentContext = await this.permissionCtxRepo.findByContextReference(parent.id);
const permissionCtxEntity = new PermissionContextEntity({
name: 'Column permission context',
parentContext,
contextReference: new ObjectId(column.id),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
await this.createBoardPermissionCtx(column.id, parent.id, 'Column permission context');

await this.boardDoRepo.save(parent.children, parent);

Expand Down
56 changes: 9 additions & 47 deletions apps/server/src/modules/board/service/content-element.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,30 @@ import {
AnyBoardDo,
AnyContentElementDo,
Card,
ColumnBoard,
ContentElementFactory,
ContentElementType,
EntityId,
isAnyContentElement,
PermissionContextEntity,
PermissionCrud,
SubmissionContainerElement,
SubmissionItem,
UserDelta,
} from '@shared/domain';
import { CourseRepo, PermissionContextRepo } from '@shared/repo';
import { ObjectId } from 'bson';
import { AnyElementContentBody } from '../controller/dto';
import { BoardDoRepo } from '../repo';
import { BoardDoService } from './board-do.service';
import { ContentElementUpdateVisitor } from './content-element-update.visitor';
import { BaseService } from './base.service';

@Injectable()
export class ContentElementService {
export class ContentElementService extends BaseService {
constructor(
private readonly boardDoRepo: BoardDoRepo,
protected readonly boardDoRepo: BoardDoRepo,
private readonly boardDoService: BoardDoService,
private readonly contentElementFactory: ContentElementFactory,
private readonly permissionCtxRepo: PermissionContextRepo,
private readonly courseRepo: CourseRepo
) {}
protected readonly permissionCtxRepo: PermissionContextRepo,
protected readonly courseRepo: CourseRepo
) {
super(permissionCtxRepo, boardDoRepo, courseRepo);
}

async findById(elementId: EntityId): Promise<AnyContentElementDo> {
const element = await this.boardDoRepo.findById(elementId);
Expand All @@ -49,46 +46,11 @@ export class ContentElementService {
return parent;
}

async pocCreateElementPermissionCtx(
element: AnyContentElementDo,
parent: Card | SubmissionItem,
parentContext: PermissionContextEntity
) {
if (element instanceof SubmissionContainerElement) {
// NOTE: this will be simplified once we have user groups
const rootId = (await this.boardDoRepo.getAncestorIds(parent))[0];
const columnBoard = await this.boardDoRepo.findByClassAndId(ColumnBoard, rootId);
const course = await this.courseRepo.findById(columnBoard.context.id);
const updatedStudentsPermissions = course.students.getItems().map((student) => {
return {
userId: student.id,
includedPermissions: [PermissionCrud.CREATE],
excludedPermissions: [],
};
});
const permissionCtxEntity = new PermissionContextEntity({
name: 'SubmissionContainerElement permission context',
parentContext,
contextReference: new ObjectId(element.id),
userDelta: new UserDelta(updatedStudentsPermissions),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
} else {
const permissionCtxEntity = new PermissionContextEntity({
name: 'Element permission context',
parentContext,
contextReference: new ObjectId(element.id),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
}
}

async create(parent: Card | SubmissionItem, type: ContentElementType): Promise<AnyContentElementDo> {
const element = this.contentElementFactory.build(type);
parent.addChild(element);

const parentContext = await this.permissionCtxRepo.findByContextReference(parent.id);
await this.pocCreateElementPermissionCtx(element, parent, parentContext);
await this.pocCreateElementPermissionCtx(element, parent);

await this.boardDoRepo.save(parent.children, parent);
return element;
Expand Down
63 changes: 8 additions & 55 deletions apps/server/src/modules/board/service/submission-item.service.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,23 @@
import { ObjectId } from 'bson';
import { Injectable, NotFoundException, UnprocessableEntityException } from '@nestjs/common';
import { Injectable, UnprocessableEntityException } from '@nestjs/common';

import {
ColumnBoard,
EntityId,
isSubmissionContainerElement,
PermissionContextEntity,
PermissionCrud,
SubmissionContainerElement,
SubmissionItem,
UserDelta,
} from '@shared/domain';
import { EntityId, isSubmissionContainerElement, SubmissionContainerElement, SubmissionItem } from '@shared/domain';
import { ValidationError } from '@shared/common';

import { CourseRepo, PermissionContextRepo } from '@shared/repo';
import { BoardDoRepo } from '../repo';
import { BoardDoService } from './board-do.service';
import { BaseService } from './base.service';

@Injectable()
export class SubmissionItemService {
export class SubmissionItemService extends BaseService {
constructor(
private readonly boardDoRepo: BoardDoRepo,
protected readonly boardDoRepo: BoardDoRepo,
private readonly boardDoService: BoardDoService,
private readonly permissionCtxRepo: PermissionContextRepo,
private readonly courseRepo: CourseRepo
) {}

private async pocCreateSubmissionItemPermissionCtx(
userId: EntityId,
submissionContainer: SubmissionContainerElement,
submissionItemId: EntityId
protected readonly permissionCtxRepo: PermissionContextRepo,
protected readonly courseRepo: CourseRepo
) {
// NOTE: this will be simplified once we have user groups
const parentContext = await this.permissionCtxRepo.findByContextReference(submissionContainer.id);

const rootId = (await this.boardDoRepo.getAncestorIds(submissionContainer))[0];
const columnBoard = await this.boardDoRepo.findByClassAndId(ColumnBoard, rootId);
const course = await this.courseRepo.findById(columnBoard.context.id);
const revokeStudentsPermissions = course.students
.getItems()
.filter((student) => student.id !== userId)
.map((student) => {
return {
userId: student.id,
includedPermissions: [],
excludedPermissions: [PermissionCrud.UPDATE, PermissionCrud.DELETE],
};
});

const permissionCtxEntity = new PermissionContextEntity({
name: 'Element permission context',
parentContext,
contextReference: new ObjectId(submissionItemId),
userDelta: new UserDelta(revokeStudentsPermissions),
});
await this.permissionCtxRepo.save(permissionCtxEntity);
}

async findById(id: EntityId): Promise<SubmissionItem> {
const element = await this.boardDoRepo.findById(id);

if (!(element instanceof SubmissionItem)) {
throw new NotFoundException(`There is no '${element.constructor.name}' with this id`);
}

return element;
super(permissionCtxRepo, boardDoRepo, courseRepo);
}

async create(
Expand Down

0 comments on commit 71fb3a0

Please sign in to comment.