Use includes on liked, music, score, search and fav pages
This commit is contained in:
@@ -21,12 +21,12 @@ import {
|
||||
Response,
|
||||
Query,
|
||||
Param,
|
||||
} from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { JwtAuthGuard } from './jwt-auth.guard';
|
||||
import { LocalAuthGuard } from './local-auth.guard';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
import { UsersService } from 'src/users/users.service';
|
||||
} from "@nestjs/common";
|
||||
import { AuthService } from "./auth.service";
|
||||
import { JwtAuthGuard } from "./jwt-auth.guard";
|
||||
import { LocalAuthGuard } from "./local-auth.guard";
|
||||
import { RegisterDto } from "./dto/register.dto";
|
||||
import { UsersService } from "src/users/users.service";
|
||||
import {
|
||||
ApiBadRequestResponse,
|
||||
ApiBearerAuth,
|
||||
@@ -36,39 +36,41 @@ import {
|
||||
ApiOperation,
|
||||
ApiTags,
|
||||
ApiUnauthorizedResponse,
|
||||
} from '@nestjs/swagger';
|
||||
import { User } from '../models/user';
|
||||
import { JwtToken } from './models/jwt';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { Profile } from './dto/profile.dto';
|
||||
import { Setting } from 'src/models/setting';
|
||||
import { UpdateSettingDto } from 'src/settings/dto/update-setting.dto';
|
||||
import { SettingsService } from 'src/settings/settings.service';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { writeFile } from 'fs';
|
||||
import { PasswordResetDto } from './dto/password_reset.dto ';
|
||||
} from "@nestjs/swagger";
|
||||
import { User } from "../models/user";
|
||||
import { JwtToken } from "./models/jwt";
|
||||
import { LoginDto } from "./dto/login.dto";
|
||||
import { Profile } from "./dto/profile.dto";
|
||||
import { Setting } from "src/models/setting";
|
||||
import { UpdateSettingDto } from "src/settings/dto/update-setting.dto";
|
||||
import { SettingsService } from "src/settings/settings.service";
|
||||
import { AuthGuard } from "@nestjs/passport";
|
||||
import { FileInterceptor } from "@nestjs/platform-express";
|
||||
import { writeFile } from "fs";
|
||||
import { PasswordResetDto } from "./dto/password_reset.dto ";
|
||||
import { mapInclude } from "src/utils/include";
|
||||
import { SongController } from "src/song/song.controller";
|
||||
|
||||
@ApiTags('auth')
|
||||
@Controller('auth')
|
||||
@ApiTags("auth")
|
||||
@Controller("auth")
|
||||
export class AuthController {
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private usersService: UsersService,
|
||||
private settingsService: SettingsService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Get('login/google')
|
||||
@UseGuards(AuthGuard('google'))
|
||||
@ApiOperation({ description: 'Redirect to google login page' })
|
||||
googleLogin() {}
|
||||
@Get("login/google")
|
||||
@UseGuards(AuthGuard("google"))
|
||||
@ApiOperation({ description: "Redirect to google login page" })
|
||||
googleLogin() { }
|
||||
|
||||
@Get('logged/google')
|
||||
@Get("logged/google")
|
||||
@ApiOperation({
|
||||
description:
|
||||
'Redirect to the front page after connecting to the google account',
|
||||
"Redirect to the front page after connecting to the google account",
|
||||
})
|
||||
@UseGuards(AuthGuard('google'))
|
||||
@UseGuards(AuthGuard("google"))
|
||||
async googleLoginCallbakc(@Req() req: any) {
|
||||
let user = await this.usersService.user({ googleID: req.user.googleID });
|
||||
if (!user) {
|
||||
@@ -78,13 +80,13 @@ export class AuthController {
|
||||
return this.authService.login(user);
|
||||
}
|
||||
|
||||
@Post('register')
|
||||
@ApiOperation({ description: 'Register a new user' })
|
||||
@ApiConflictResponse({ description: 'Username or email already taken' })
|
||||
@Post("register")
|
||||
@ApiOperation({ description: "Register a new user" })
|
||||
@ApiConflictResponse({ description: "Username or email already taken" })
|
||||
@ApiOkResponse({
|
||||
description: 'Successfully registered, email sent to verify',
|
||||
description: "Successfully registered, email sent to verify",
|
||||
})
|
||||
@ApiBadRequestResponse({ description: 'Invalid data or database error' })
|
||||
@ApiBadRequestResponse({ description: "Invalid data or database error" })
|
||||
async register(@Body() registerDto: RegisterDto): Promise<void> {
|
||||
try {
|
||||
const user = await this.usersService.createUser(registerDto);
|
||||
@@ -92,73 +94,73 @@ export class AuthController {
|
||||
await this.authService.sendVerifyMail(user);
|
||||
} catch (e) {
|
||||
// check if the error is a duplicate key error
|
||||
if (e.code === 'P2002') {
|
||||
throw new ConflictException('Username or email already taken');
|
||||
if (e.code === "P2002") {
|
||||
throw new ConflictException("Username or email already taken");
|
||||
}
|
||||
console.error(e);
|
||||
throw new BadRequestException();
|
||||
}
|
||||
}
|
||||
|
||||
@Put('verify')
|
||||
@Put("verify")
|
||||
@HttpCode(200)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiOperation({ description: 'Verify the email of the user' })
|
||||
@ApiOkResponse({ description: 'Successfully verified' })
|
||||
@ApiBadRequestResponse({ description: 'Invalid or expired token' })
|
||||
@ApiOperation({ description: "Verify the email of the user" })
|
||||
@ApiOkResponse({ description: "Successfully verified" })
|
||||
@ApiBadRequestResponse({ description: "Invalid or expired token" })
|
||||
async verify(
|
||||
@Request() req: any,
|
||||
@Query('token') token: string,
|
||||
@Query("token") token: string,
|
||||
): Promise<void> {
|
||||
if (await this.authService.verifyMail(req.user.id, token)) return;
|
||||
throw new BadRequestException('Invalid token. Expired or invalid.');
|
||||
throw new BadRequestException("Invalid token. Expired or invalid.");
|
||||
}
|
||||
|
||||
@Put('reverify')
|
||||
@Put("reverify")
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@HttpCode(200)
|
||||
@ApiOperation({ description: 'Resend the verification email' })
|
||||
@ApiOperation({ description: "Resend the verification email" })
|
||||
async reverify(@Request() req: any): Promise<void> {
|
||||
const user = await this.usersService.user({ id: req.user.id });
|
||||
if (!user) throw new BadRequestException('Invalid user');
|
||||
if (!user) throw new BadRequestException("Invalid user");
|
||||
await this.authService.sendVerifyMail(user);
|
||||
}
|
||||
|
||||
@HttpCode(200)
|
||||
@Put('password-reset')
|
||||
@Put("password-reset")
|
||||
async password_reset(
|
||||
@Body() resetDto: PasswordResetDto,
|
||||
@Query('token') token: string,
|
||||
@Query("token") token: string,
|
||||
): Promise<void> {
|
||||
if (await this.authService.changePassword(resetDto.password, token)) return;
|
||||
throw new BadRequestException('Invalid token. Expired or invalid.');
|
||||
throw new BadRequestException("Invalid token. Expired or invalid.");
|
||||
}
|
||||
|
||||
@HttpCode(200)
|
||||
@Put('forgot-password')
|
||||
async forgot_password(@Query('email') email: string): Promise<void> {
|
||||
@Put("forgot-password")
|
||||
async forgot_password(@Query("email") email: string): Promise<void> {
|
||||
console.log(email);
|
||||
const user = await this.usersService.user({ email: email });
|
||||
if (!user) throw new BadRequestException('Invalid user');
|
||||
if (!user) throw new BadRequestException("Invalid user");
|
||||
await this.authService.sendPasswordResetMail(user);
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
@Post("login")
|
||||
@ApiBody({ type: LoginDto })
|
||||
@HttpCode(200)
|
||||
@UseGuards(LocalAuthGuard)
|
||||
@ApiBody({ type: LoginDto })
|
||||
@ApiOperation({ description: 'Login with username and password' })
|
||||
@ApiOkResponse({ description: 'Successfully logged in', type: JwtToken })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid credentials' })
|
||||
@ApiOperation({ description: "Login with username and password" })
|
||||
@ApiOkResponse({ description: "Successfully logged in", type: JwtToken })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid credentials" })
|
||||
async login(@Request() req: any): Promise<JwtToken> {
|
||||
return this.authService.login(req.user);
|
||||
}
|
||||
|
||||
@Post('guest')
|
||||
@Post("guest")
|
||||
@HttpCode(200)
|
||||
@ApiOperation({ description: 'Login as a guest account' })
|
||||
@ApiOkResponse({ description: 'Successfully logged in', type: JwtToken })
|
||||
@ApiOperation({ description: "Login as a guest account" })
|
||||
@ApiOkResponse({ description: "Successfully logged in", type: JwtToken })
|
||||
async guest(): Promise<JwtToken> {
|
||||
const user = await this.usersService.createGuest();
|
||||
await this.settingsService.createUserSetting(user.id);
|
||||
@@ -167,27 +169,27 @@ export class AuthController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ description: 'Get the profile picture of connected user' })
|
||||
@ApiOkResponse({ description: 'The user profile picture' })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Get('me/picture')
|
||||
@ApiOperation({ description: "Get the profile picture of connected user" })
|
||||
@ApiOkResponse({ description: "The user profile picture" })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Get("me/picture")
|
||||
async getProfilePicture(@Request() req: any, @Response() res: any) {
|
||||
return await this.usersService.getProfilePicture(req.user.id, res);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'The user profile picture' })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Post('me/picture')
|
||||
@ApiOperation({ description: 'Upload a new profile picture' })
|
||||
@UseInterceptors(FileInterceptor('file'))
|
||||
@ApiOkResponse({ description: "The user profile picture" })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Post("me/picture")
|
||||
@ApiOperation({ description: "Upload a new profile picture" })
|
||||
@UseInterceptors(FileInterceptor("file"))
|
||||
async postProfilePicture(
|
||||
@Request() req: any,
|
||||
@UploadedFile(
|
||||
new ParseFilePipeBuilder()
|
||||
.addFileTypeValidator({
|
||||
fileType: 'jpeg',
|
||||
fileType: "jpeg",
|
||||
})
|
||||
.build({
|
||||
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
@@ -203,10 +205,10 @@ export class AuthController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully logged in', type: User })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Get('me')
|
||||
@ApiOperation({ description: 'Get the user info of connected user' })
|
||||
@ApiOkResponse({ description: "Successfully logged in", type: User })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Get("me")
|
||||
@ApiOperation({ description: "Get the user info of connected user" })
|
||||
async getProfile(@Request() req: any): Promise<User> {
|
||||
const user = await this.usersService.user({ id: req.user.id });
|
||||
if (!user) throw new InternalServerErrorException();
|
||||
@@ -215,10 +217,10 @@ export class AuthController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully edited profile', type: User })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Put('me')
|
||||
@ApiOperation({ description: 'Edit the profile of connected user' })
|
||||
@ApiOkResponse({ description: "Successfully edited profile", type: User })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Put("me")
|
||||
@ApiOperation({ description: "Edit the profile of connected user" })
|
||||
editProfile(
|
||||
@Request() req: any,
|
||||
@Body() profile: Partial<Profile>,
|
||||
@@ -241,20 +243,20 @@ export class AuthController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully deleted', type: User })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Delete('me')
|
||||
@ApiOperation({ description: 'Delete the profile of connected user' })
|
||||
@ApiOkResponse({ description: "Successfully deleted", type: User })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Delete("me")
|
||||
@ApiOperation({ description: "Delete the profile of connected user" })
|
||||
deleteSelf(@Request() req: any): Promise<User> {
|
||||
return this.usersService.deleteUser({ id: req.user.id });
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully edited settings', type: Setting })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Patch('me/settings')
|
||||
@ApiOperation({ description: 'Edit the settings of connected user' })
|
||||
@ApiOkResponse({ description: "Successfully edited settings", type: Setting })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Patch("me/settings")
|
||||
@ApiOperation({ description: "Edit the settings of connected user" })
|
||||
udpateSettings(
|
||||
@Request() req: any,
|
||||
@Body() settingUserDto: UpdateSettingDto,
|
||||
@@ -267,10 +269,10 @@ export class AuthController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully edited settings', type: Setting })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Get('me/settings')
|
||||
@ApiOperation({ description: 'Get the settings of connected user' })
|
||||
@ApiOkResponse({ description: "Successfully edited settings", type: Setting })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Get("me/settings")
|
||||
@ApiOperation({ description: "Get the settings of connected user" })
|
||||
async getSettings(@Request() req: any): Promise<Setting> {
|
||||
const result = await this.settingsService.getUserSetting({
|
||||
userId: +req.user.id,
|
||||
@@ -281,28 +283,31 @@ export class AuthController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully added liked song' })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Post('me/likes/:id')
|
||||
addLikedSong(@Request() req: any, @Param('id') songId: number) {
|
||||
@ApiOkResponse({ description: "Successfully added liked song" })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Post("me/likes/:id")
|
||||
addLikedSong(@Request() req: any, @Param("id") songId: number) {
|
||||
return this.usersService.addLikedSong(+req.user.id, +songId);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully removed liked song' })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Delete('me/likes/:id')
|
||||
removeLikedSong(@Request() req: any, @Param('id') songId: number) {
|
||||
@ApiOkResponse({ description: "Successfully removed liked song" })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Delete("me/likes/:id")
|
||||
removeLikedSong(@Request() req: any, @Param("id") songId: number) {
|
||||
return this.usersService.removeLikedSong(+req.user.id, +songId);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponse({ description: 'Successfully retrieved liked song' })
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid token' })
|
||||
@Get('me/likes')
|
||||
getLikedSongs(@Request() req: any) {
|
||||
return this.usersService.getLikedSongs(+req.user.id);
|
||||
@ApiOkResponse({ description: "Successfully retrieved liked song" })
|
||||
@ApiUnauthorizedResponse({ description: "Invalid token" })
|
||||
@Get("me/likes")
|
||||
getLikedSongs(@Request() req: any, @Query("include") include: string) {
|
||||
return this.usersService.getLikedSongs(
|
||||
+req.user.id,
|
||||
mapInclude(include, req, SongController.includableFields),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@ import {
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { User, Prisma } from '@prisma/client';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { createHash, randomUUID } from 'crypto';
|
||||
import { createReadStream, existsSync } from 'fs';
|
||||
import fetch from 'node-fetch';
|
||||
} from "@nestjs/common";
|
||||
import { User, Prisma } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import * as bcrypt from "bcryptjs";
|
||||
import { createHash, randomUUID } from "crypto";
|
||||
import { createReadStream, existsSync } from "fs";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
constructor(private prisma: PrismaService) { }
|
||||
|
||||
async user(
|
||||
userWhereUniqueInput: Prisma.UserWhereUniqueInput,
|
||||
@@ -53,7 +53,7 @@ export class UsersService {
|
||||
isGuest: true,
|
||||
// Not realyl clean but better than a separate table or breaking the api by adding nulls.
|
||||
email: null,
|
||||
password: '',
|
||||
password: "",
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -63,7 +63,7 @@ export class UsersService {
|
||||
data: Prisma.UserUpdateInput;
|
||||
}): Promise<User> {
|
||||
const { where, data } = params;
|
||||
if (typeof data.password === 'string')
|
||||
if (typeof data.password === "string")
|
||||
data.password = await bcrypt.hash(data.password, 8);
|
||||
else if (data.password && data.password.set)
|
||||
data.password = await bcrypt.hash(data.password.set, 8);
|
||||
@@ -89,9 +89,9 @@ export class UsersService {
|
||||
const user = await this.user({ id: userId });
|
||||
if (!user) throw new InternalServerErrorException();
|
||||
if (!user.email) throw new NotFoundException();
|
||||
const hash = createHash('md5')
|
||||
const hash = createHash("md5")
|
||||
.update(user.email.trim().toLowerCase())
|
||||
.digest('hex');
|
||||
.digest("hex");
|
||||
const resp = await fetch(
|
||||
`https://www.gravatar.com/avatar/${hash}.jpg?d=404&s=200`,
|
||||
);
|
||||
@@ -105,9 +105,10 @@ export class UsersService {
|
||||
});
|
||||
}
|
||||
|
||||
async getLikedSongs(userId: number) {
|
||||
async getLikedSongs(userId: number, include?: Prisma.SongInclude) {
|
||||
return this.prisma.likedSongs.findMany({
|
||||
where: { userId: userId },
|
||||
include: { song: include ? { include } : true },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user