feat(web,server): activity (#4682)

* feat: activity

* regenerate api

* fix: make asset owner unable to delete comment

* fix: merge

* fix: tests

* feat: use textarea instead of input

* fix: do actions only if the album is shared

* fix: placeholder opacity

* fix(web): improve messages UI

* fix(web): improve input message UI

* pr feedback

* fix: tests

* pr feedback

* pr feedback

* pr feedback

* fix permissions

* regenerate api

* pr feedback

* pr feedback

* multiple improvements on web

* fix: ui colors

* WIP

* chore: open api

* pr feedback

* fix: add comment

* chore: clean up

* pr feedback

* refactor: endpoints

* chore: open api

* fix: filter by type

* fix: e2e

* feat: e2e remove own comment

* fix: web tests

* remove console.log

* chore: cleanup

* fix: ui tweaks

* pr feedback

* fix web test

* fix: unit tests

* chore: remove unused code

* revert useless changes

* fix: grouping messages

* fix: remove nullable on updatedAt

* fix: text overflow

* styling

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
martin
2023-11-01 04:13:34 +01:00
committed by GitHub
parent 68f6446718
commit ce5966c23d
66 changed files with 4487 additions and 38 deletions
@@ -0,0 +1,80 @@
import { ActivityEntity } from '@app/infra/entities';
import { Inject, Injectable } from '@nestjs/common';
import { AccessCore, Permission } from '../access';
import { AuthUserDto } from '../auth';
import { IAccessRepository, IActivityRepository } from '../repositories';
import {
ActivityCreateDto,
ActivityDto,
ActivityResponseDto,
ActivitySearchDto,
ActivityStatisticsResponseDto,
MaybeDuplicate,
ReactionType,
mapActivity,
} from './activity.dto';
@Injectable()
export class ActivityService {
private access: AccessCore;
constructor(
@Inject(IAccessRepository) accessRepository: IAccessRepository,
@Inject(IActivityRepository) private repository: IActivityRepository,
) {
this.access = AccessCore.create(accessRepository);
}
async getAll(authUser: AuthUserDto, dto: ActivitySearchDto): Promise<ActivityResponseDto[]> {
await this.access.requirePermission(authUser, Permission.ALBUM_READ, dto.albumId);
const activities = await this.repository.search({
albumId: dto.albumId,
assetId: dto.assetId,
isLiked: dto.type && dto.type === ReactionType.LIKE,
});
return activities.map(mapActivity);
}
async getStatistics(authUser: AuthUserDto, dto: ActivityDto): Promise<ActivityStatisticsResponseDto> {
await this.access.requirePermission(authUser, Permission.ALBUM_READ, dto.albumId);
return { comments: await this.repository.getStatistics(dto.assetId, dto.albumId) };
}
async create(authUser: AuthUserDto, dto: ActivityCreateDto): Promise<MaybeDuplicate<ActivityResponseDto>> {
await this.access.requirePermission(authUser, Permission.ACTIVITY_CREATE, dto.albumId);
const common = {
userId: authUser.id,
assetId: dto.assetId,
albumId: dto.albumId,
};
let activity: ActivityEntity | null = null;
let duplicate = false;
if (dto.type === 'like') {
delete dto.comment;
[activity] = await this.repository.search({
...common,
isLiked: true,
});
duplicate = !!activity;
}
if (!activity) {
activity = await this.repository.create({
...common,
isLiked: dto.type === ReactionType.LIKE,
comment: dto.comment,
});
}
return { duplicate, value: mapActivity(activity) };
}
async delete(authUser: AuthUserDto, id: string): Promise<void> {
await this.access.requirePermission(authUser, Permission.ACTIVITY_DELETE, id);
await this.repository.delete(id);
}
}