From bdf2167d04335339d6b6f4503baf821f657f9e47 Mon Sep 17 00:00:00 2001 From: RXRD <118821868+RiXelanya@users.noreply.github.com> Date: Wed, 15 Nov 2023 09:15:04 +0700 Subject: [PATCH] feat: enable editors in timeline for multi user timeline (#931) * feat: multi-user timeline * Update user-experience.service.ts * Update experience.controller.ts * format fix --- src/__tests__/helpers/database.helper.ts | 4 ++ src/controllers/user/experience.controller.ts | 9 ++- src/models/experience-editor.model.ts | 55 +++++++++++++++++++ src/models/experience.model.ts | 4 ++ src/models/index.ts | 1 + .../experience-editor.repository.ts | 15 +++++ src/repositories/experience.repository.ts | 17 ++++++ src/repositories/index.ts | 1 + src/services/user-experience.service.ts | 19 ++++++- src/services/user.service.ts | 7 ++- 10 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 src/models/experience-editor.model.ts create mode 100644 src/repositories/experience-editor.repository.ts diff --git a/src/__tests__/helpers/database.helper.ts b/src/__tests__/helpers/database.helper.ts index 8eed8a421..d2ce5550e 100644 --- a/src/__tests__/helpers/database.helper.ts +++ b/src/__tests__/helpers/database.helper.ts @@ -35,6 +35,7 @@ import { UnlockableContentRepository, ContentPriceRepository, TimelineConfigRepository, + ExperienceEditorRepository, } from '../../repositories'; import { ActivityLogService, @@ -145,10 +146,13 @@ export async function givenRepositories(testdb: any) { async () => userRepository, async () => experienceUserRepository, async () => experiencePostRepository, + async () => experienceEditorRepository, async () => postRepository, ); const experienceUserRepository: ExperienceUserRepository = new ExperienceUserRepository(testdb); + const experienceEditorRepository: ExperienceUserRepository = + new ExperienceEditorRepository(testdb); const experiencePostRepository: ExperiencePostRepository = new ExperiencePostRepository(testdb); const commentRepository: CommentRepository = new CommentRepository( diff --git a/src/controllers/user/experience.controller.ts b/src/controllers/user/experience.controller.ts index 9c246cfb6..f0c55e386 100644 --- a/src/controllers/user/experience.controller.ts +++ b/src/controllers/user/experience.controller.ts @@ -91,7 +91,11 @@ export class UserExperienceController { @post('/user/experiences') @response(200, { description: 'CREATE user experience', - content: {'application/json': {schema: getModelSchemaRef(Experience)}}, + content: { + 'application/json': { + schema: getModelSchemaRef(Experience, {includeRelations: true}), + }, + }, }) async create( @requestBody({ @@ -106,8 +110,9 @@ export class UserExperienceController { }) experience: Omit, @param.query.string('experienceId') experienceId?: string, + @param.array('editors', 'query', {type: 'string'}) editors?: string[], ): Promise { - return this.userService.createExperience(experience, experienceId); + return this.userService.createExperience(experience, experienceId, editors); } @patch('/user/experiences/{id}') diff --git a/src/models/experience-editor.model.ts b/src/models/experience-editor.model.ts new file mode 100644 index 000000000..3624a360c --- /dev/null +++ b/src/models/experience-editor.model.ts @@ -0,0 +1,55 @@ +import {Entity, model, property} from '@loopback/repository'; + +@model({ + settings: { + strictObjectIDCoercion: true, + mongodb: { + collection: 'ExperienceEditors', + }, + indexes: { + uniqueUserExperienceIndex: { + keys: { + userId: 1, + experienceId: 1, + }, + options: { + unique: true, + }, + }, + }, + }, +}) +export class ExperienceEditor extends Entity { + @property({ + type: 'string', + id: true, + generated: true, + mongodb: { + dataType: 'ObjectId', + }, + }) + id?: string; + + @property({ + type: 'string', + required: false, + }) + experienceId: string; + + @property({ + type: 'string', + required: false, + }) + userId: string; + + constructor(data?: Partial) { + super(data); + } +} + +export interface ExperienceEditorRelations { + // describe navigational properties here +} + +export type ExperienceEditorWithRelations = ExperienceEditor & + ExperienceEditorRelations; diff --git a/src/models/experience.model.ts b/src/models/experience.model.ts index b65d126ab..205c778f2 100644 --- a/src/models/experience.model.ts +++ b/src/models/experience.model.ts @@ -8,6 +8,7 @@ import { import {People} from './people.model'; import {User} from './user.model'; import {ExperienceUser} from './experience-user.model'; +import {ExperienceEditor} from './experience-editor.model'; import {UserWithRelations} from './user.model'; import {Post} from './post.model'; import {ExperiencePost} from './experience-post.model'; @@ -157,6 +158,9 @@ export class Experience extends Entity { @hasMany(() => User, {through: {model: () => ExperienceUser}}) users?: User[]; + @hasMany(() => User, {through: {model: () => ExperienceEditor}}) + editors?: User[]; + constructor(data?: Partial) { super(data); } diff --git a/src/models/index.ts b/src/models/index.ts index eda5bf33a..e4b0cf5b5 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -9,6 +9,7 @@ export * from './embedded-url.model'; export * from './exchange-rate.model'; export * from './experience-post.model'; export * from './experience-user.model'; +export * from './experience-editor.model'; export * from './experience.model'; export * from './friend.model'; export * from './identity.model'; diff --git a/src/repositories/experience-editor.repository.ts b/src/repositories/experience-editor.repository.ts new file mode 100644 index 000000000..026840a0f --- /dev/null +++ b/src/repositories/experience-editor.repository.ts @@ -0,0 +1,15 @@ +import {bind, BindingScope, inject} from '@loopback/core'; +import {DefaultCrudRepository} from '@loopback/repository'; +import {MongoDataSource} from '../datasources'; +import {ExperienceEditor, ExperienceEditorRelations} from '../models'; + +@bind({scope: BindingScope.SINGLETON}) +export class ExperienceEditorRepository extends DefaultCrudRepository< + ExperienceEditor, + typeof ExperienceEditor.prototype.id, + ExperienceEditorRelations +> { + constructor(@inject('datasources.mongo') dataSource: MongoDataSource) { + super(ExperienceEditor, dataSource); + } +} diff --git a/src/repositories/experience.repository.ts b/src/repositories/experience.repository.ts index db5bd204d..624e99f27 100644 --- a/src/repositories/experience.repository.ts +++ b/src/repositories/experience.repository.ts @@ -11,11 +11,13 @@ import { ExperiencePost, ExperienceRelations, ExperienceUser, + ExperienceEditor, Post, User, } from '../models'; import {ExperiencePostRepository} from './experience-post.repository'; import {ExperienceUserRepository} from './experience-user.repository'; +import {ExperienceEditorRepository} from './experience-editor.repository'; import {PostRepository} from './post.repository'; import {UserRepository} from './user.repository'; @@ -34,6 +36,13 @@ export class ExperienceRepository extends DefaultCrudRepository< typeof Experience.prototype.id >; + public readonly editors: HasManyThroughRepositoryFactory< + User, + typeof User.prototype.id, + ExperienceEditor, + typeof Experience.prototype.id + >; + public readonly posts: HasManyThroughRepositoryFactory< Post, typeof Post.prototype.id, @@ -49,6 +58,8 @@ export class ExperienceRepository extends DefaultCrudRepository< protected experienceUserRepositoryGetter: Getter, @repository.getter('ExperiencePostRepository') protected experiencePostRepositoryGetter: Getter, + @repository.getter('ExperienceEditorRepository') + protected experienceEditorRepositoryGetter: Getter, @repository.getter('PostRepository') protected postRepositoryGetter: Getter, ) { @@ -65,6 +76,12 @@ export class ExperienceRepository extends DefaultCrudRepository< experienceUserRepositoryGetter, ); this.registerInclusionResolver('users', this.users.inclusionResolver); + this.editors = this.createHasManyThroughRepositoryFactoryFor( + 'editors', + userRepositoryGetter, + experienceEditorRepositoryGetter, + ); + this.registerInclusionResolver('editors', this.editors.inclusionResolver); this.user = this.createBelongsToAccessorFor('user', userRepositoryGetter); this.registerInclusionResolver('user', this.user.inclusionResolver); } diff --git a/src/repositories/index.ts b/src/repositories/index.ts index 9baac26c8..e14917d28 100644 --- a/src/repositories/index.ts +++ b/src/repositories/index.ts @@ -8,6 +8,7 @@ export * from './exchange-rate.repository'; export * from './experience.repository'; export * from './experience-post.repository'; export * from './experience-user.repository'; +export * from './experience-editor.repository'; export * from './friend.repository'; export * from './identity.repository'; export * from './language-setting.repository'; diff --git a/src/services/user-experience.service.ts b/src/services/user-experience.service.ts index 90ac99bee..2b9f3073c 100644 --- a/src/services/user-experience.service.ts +++ b/src/services/user-experience.service.ts @@ -267,6 +267,7 @@ export class UserExperienceService { public async create( experience: Omit, clonedId?: string, + editors?: string[], ): Promise { const userId = experience.createdBy; const people = this.validateExperienceData(experience); @@ -278,7 +279,7 @@ export class UserExperienceService { return this.userRepository .experiences(userId) .create(experience) - .then(async exp => this.afterCreate(exp, people, clonedId)); + .then(async exp => this.afterCreate(exp, people, clonedId, editors)); } public async subscribe( @@ -348,6 +349,7 @@ export class UserExperienceService { experience: Experience, people: People[], clonedId?: string, + editors?: string[], ): Promise { const userId = experience.createdBy; const experienceId = experience?.id ?? ''; @@ -420,6 +422,21 @@ export class UserExperienceService { ); } + if (editors) { + editors.map(editor => { + const link = this.experienceRepository + .editors(experienceId) + .link(editor); + const creation = this.userExperienceRepository.create({ + userId: editor, + experienceId, + }); + promises.push(link); + promises.push(creation); + return editor; + }); + } + Promise.allSettled(promises) as Promise; return experience; diff --git a/src/services/user.service.ts b/src/services/user.service.ts index 3c4fae72a..d061a9e54 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -783,12 +783,13 @@ export class UserService { } public async createExperience( - experince: Omit, + experience: Omit, clonedId?: string, + editors?: string[], ): Promise { await this.haveFullAccess(ControllerType.USEREXPERIENCE); - experince.createdBy = this.currentUser[securityId]; - return this.userExperienceService.create(experince, clonedId); + experience.createdBy = this.currentUser[securityId]; + return this.userExperienceService.create(experience, clonedId, editors); } public async subscribeExperience(id: string): Promise {