الملفات
back_end_oudelaa/src/modules/posts/posts.controller.ts

322 أسطر
12 KiB
TypeScript

import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Param,
Patch,
Post,
Query,
UploadedFiles,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { MultipartFormDataGuard } from '../../common/guards/multipart-form-data.guard';
import { SuperAdminPermissionsGuard } from '../../common/guards/superadmin-permissions.guard';
import { SuperAdminJwtAuthGuard } from '../../common/guards/super-admin-jwt-auth.guard';
import { JwtPayload } from '../../common/interfaces/jwt-payload.interface';
import { SuperAdminPermissions } from '../../common/decorators/superadmin-permissions.decorator';
import { AdminPostQueryDto } from './dto/admin-post-query.dto';
import { CreateReelDto } from './dto/create-reel.dto';
import { CreatePostDto } from './dto/create-post.dto';
import { CreateRepostDto } from './dto/create-repost.dto';
import { PostQueryDto } from './dto/post-query.dto';
import { ReelQueryDto } from './dto/reel-query.dto';
import { UpdateCommentSettingsDto } from './dto/update-comment-settings.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { PostsService } from './posts.service';
import { SUPERADMIN_PERMISSIONS } from '../superadmin/superadmin-permissions';
@ApiTags('Posts')
@Controller('posts')
export class PostsController {
constructor(private readonly postsService: PostsService) {}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, MultipartFormDataGuard)
@UseInterceptors(
FileFieldsInterceptor([
{ name: 'imageFiles', maxCount: 10 },
{ name: 'videoFile', maxCount: 1 },
{ name: 'audioFile', maxCount: 1 },
]),
)
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
content: { type: 'string', example: 'First post #music' },
visibility: { type: 'string', enum: ['public', 'followers', 'private'] },
imageUrls: { type: 'array', items: { type: 'string' } },
imageCaptions: { type: 'array', items: { type: 'string' } },
imageAltTexts: { type: 'array', items: { type: 'string' } },
taggedUserIds: { type: 'array', items: { type: 'string' } },
collaboratorIds: { type: 'array', items: { type: 'string' } },
mentionUsernames: { type: 'array', items: { type: 'string' } },
location: { type: 'string', example: 'Riyadh, Saudi Arabia' },
latitude: { type: 'number', example: 24.7136 },
longitude: { type: 'number', example: 46.6753 },
videoUrl: { type: 'string', example: 'https://cdn.example.com/video.mp4' },
audioUrl: { type: 'string', example: 'https://cdn.example.com/audio.mp3' },
durationSeconds: { type: 'number', example: 54 },
thumbnailUrl: { type: 'string', example: 'https://cdn.example.com/cover.jpg' },
style: { type: 'string', example: 'Sharqi' },
maqam: { type: 'string', example: 'Hijaz' },
rhythmSignature: { type: 'string', example: '6/8' },
waveformPeaks: { type: 'array', items: { type: 'number' } },
commentsDisabled: { type: 'boolean' },
commentsFollowersOnly: { type: 'boolean' },
imageFiles: { type: 'array', items: { type: 'string', format: 'binary' } },
videoFile: { type: 'string', format: 'binary' },
audioFile: { type: 'string', format: 'binary' },
},
},
})
@Post()
async create(
@CurrentUser() user: JwtPayload,
@Body() dto: CreatePostDto,
@UploadedFiles()
files?: {
imageFiles?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
videoFile?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
audioFile?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
},
) {
return this.postsService.create(
user.sub,
dto,
files?.imageFiles ?? [],
files?.videoFile?.[0],
files?.audioFile?.[0],
);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('user/:userId')
async findUserPosts(@Param('userId') userId: string, @Query() query: PostQueryDto) {
return this.postsService.findUserPosts(userId, query);
}
@ApiBearerAuth()
@UseGuards(SuperAdminJwtAuthGuard, SuperAdminPermissionsGuard)
@SuperAdminPermissions(SUPERADMIN_PERMISSIONS.CONTENT_MODERATE)
@Get('admin/moderation')
async findPlatformPosts(@Query() query: AdminPostQueryDto) {
return this.postsService.findPlatformPosts(query);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, MultipartFormDataGuard)
@UseInterceptors(
FileFieldsInterceptor([
{ name: 'videoFile', maxCount: 1 },
]),
)
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
content: { type: 'string', example: 'New reel from oud session #reel' },
visibility: { type: 'string', enum: ['public', 'followers', 'private'] },
videoUrl: { type: 'string', example: 'https://cdn.example.com/reel.mp4' },
durationSeconds: { type: 'number', example: 42 },
thumbnailUrl: { type: 'string', example: 'https://cdn.example.com/reel-cover.jpg' },
style: { type: 'string', example: 'Sharqi' },
maqam: { type: 'string', example: 'Hijaz' },
rhythmSignature: { type: 'string', example: '6/8' },
mentionUsernames: { type: 'array', items: { type: 'string' } },
videoFile: { type: 'string', format: 'binary' },
},
},
})
@Post('reels')
async createReel(
@CurrentUser() user: JwtPayload,
@Body() dto: CreateReelDto,
@UploadedFiles()
files?: {
videoFile?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
},
) {
return this.postsService.createReel(user.sub, dto, files?.videoFile?.[0]);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('reels')
async findReels(@Query() query: ReelQueryDto) {
return this.postsService.findReels(query);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get(':postId')
async findById(@Param('postId') postId: string) {
return this.postsService.findById(postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, MultipartFormDataGuard)
@UseInterceptors(
FileFieldsInterceptor([
{ name: 'imageFiles', maxCount: 10 },
{ name: 'videoFile', maxCount: 1 },
{ name: 'audioFile', maxCount: 1 },
]),
)
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
content: { type: 'string', example: 'Updated content' },
visibility: { type: 'string', enum: ['public', 'followers', 'private'] },
imageUrls: { type: 'array', items: { type: 'string' } },
imageCaptions: { type: 'array', items: { type: 'string' } },
imageAltTexts: { type: 'array', items: { type: 'string' } },
taggedUserIds: { type: 'array', items: { type: 'string' } },
collaboratorIds: { type: 'array', items: { type: 'string' } },
mentionUsernames: { type: 'array', items: { type: 'string' } },
location: { type: 'string', example: 'Jeddah, Saudi Arabia' },
latitude: { type: 'number', example: 21.5433 },
longitude: { type: 'number', example: 39.1728 },
videoUrl: { type: 'string', example: 'https://cdn.example.com/video.mp4' },
audioUrl: { type: 'string', example: 'https://cdn.example.com/audio.mp3' },
durationSeconds: { type: 'number', example: 54 },
thumbnailUrl: { type: 'string', example: 'https://cdn.example.com/cover.jpg' },
style: { type: 'string', example: 'Sharqi' },
maqam: { type: 'string', example: 'Hijaz' },
rhythmSignature: { type: 'string', example: '6/8' },
waveformPeaks: { type: 'array', items: { type: 'number' } },
commentsDisabled: { type: 'boolean' },
commentsFollowersOnly: { type: 'boolean' },
imageFiles: { type: 'array', items: { type: 'string', format: 'binary' } },
videoFile: { type: 'string', format: 'binary' },
audioFile: { type: 'string', format: 'binary' },
},
},
})
@Patch(':postId')
async update(
@CurrentUser() user: JwtPayload,
@Param('postId') postId: string,
@Body() dto: UpdatePostDto,
@UploadedFiles()
files?: {
imageFiles?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
videoFile?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
audioFile?: Array<{ mimetype?: string; size: number; buffer: Buffer; originalname?: string }>;
},
) {
return this.postsService.update(
user.sub,
postId,
dto,
files?.imageFiles ?? [],
files?.videoFile?.[0],
files?.audioFile?.[0],
);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Post(':postId/repost')
async repost(
@CurrentUser() user: JwtPayload,
@Param('postId') postId: string,
@Body() dto: CreateRepostDto,
) {
return this.postsService.createRepost(user.sub, postId, dto);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Patch(':postId/comment-settings')
async updateCommentSettings(
@CurrentUser() user: JwtPayload,
@Param('postId') postId: string,
@Body() dto: UpdateCommentSettingsDto,
) {
return this.postsService.updateCommentSettings(user.sub, postId, dto);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Patch(':postId/pin-profile')
async pinToProfile(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.pinToProfile(user.sub, postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Patch(':postId/unpin-profile')
async unpinFromProfile(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.unpinFromProfile(user.sub, postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Patch(':postId/archive')
async archive(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.archive(user.sub, postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Patch(':postId/restore-archive')
async restoreArchive(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.restoreArchived(user.sub, postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Delete(':postId')
async remove(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
await this.postsService.remove(user.sub, postId);
return { success: true };
}
@ApiBearerAuth()
@UseGuards(SuperAdminJwtAuthGuard, SuperAdminPermissionsGuard)
@SuperAdminPermissions(SUPERADMIN_PERMISSIONS.CONTENT_MODERATE)
@Delete('admin/:postId')
async removeBySuperAdmin(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
await this.postsService.removeBySuperAdmin(user.email ?? user.sub, postId);
return { success: true };
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
@Post(':postId/view')
async registerView(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.registerView(user.sub, postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
@Post(':postId/play')
async registerPlay(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.registerPlay(user.sub, postId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
@Post(':postId/share')
async registerShare(@CurrentUser() user: JwtPayload, @Param('postId') postId: string) {
return this.postsService.registerShare(user.sub, postId);
}
}