-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
14 changed files
with
1,185 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
import { HttpModule } from '@nestjs/axios'; | ||
import { Module } from '@nestjs/common'; | ||
import { UsersModule } from 'src/users/users.module'; | ||
import { DatabaseModule } from 'src/database/database.module'; | ||
import { StorageModule } from 'src/storage/storage.module'; | ||
import { AmazingPictureResolver } from './amazing_picture.resolver'; | ||
import { AmazingPictureService } from './amazing_picture.service'; | ||
|
||
@Module({ | ||
imports: [HttpModule, UsersModule], | ||
imports: [StorageModule, DatabaseModule], | ||
providers: [AmazingPictureResolver, AmazingPictureService], | ||
}) | ||
export class AmazingPictureModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,29 @@ | ||
import { UnauthorizedException } from '@nestjs/common'; | ||
import { UseGuards } from '@nestjs/common'; | ||
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; | ||
import { UserID } from 'src/users/decorators/user-id.decorator'; | ||
import { FileUpload, GraphQLUpload } from 'graphql-upload'; | ||
import { SiteRoles } from 'src/users/decorators/site-roles.decorator'; | ||
import { SiteRoleGuard } from 'src/users/guards/site-role.guard'; | ||
import { UserRole } from 'src/users/models/user.model'; | ||
import { UsersService } from 'src/users/users.service'; | ||
import { env } from 'src/utils/envs'; | ||
import { AmazingPictureService } from './amazing_picture.service'; | ||
|
||
@Resolver() | ||
export class AmazingPictureResolver { | ||
constructor( | ||
private readonly amazingPictureService: AmazingPictureService, | ||
private readonly usersService: UsersService, | ||
) {} | ||
constructor(private readonly amazingPictureService: AmazingPictureService) {} | ||
|
||
@Query((returns) => String) | ||
amazingPicture() { | ||
return `http://${env.storage.host}:${env.storage.port}/storage/amazing_picture`; | ||
async amazingPicture() { | ||
return await this.amazingPictureService.find(); | ||
} | ||
|
||
@Mutation((returns) => Boolean) | ||
async setAmazingPicture( | ||
@UserID() user_id: string, | ||
@Args('amazing_picture') amazing_picture: string, | ||
@UseGuards(SiteRoleGuard) | ||
@SiteRoles(UserRole.ADMIN) | ||
async updateAmazingPicture( | ||
@Args('file', { type: () => GraphQLUpload }) file: FileUpload, | ||
): Promise<boolean> { | ||
// if ((await this.usersService.getSiteRole(user_id)) === UserRole.USER) | ||
// throw new UnauthorizedException( | ||
// 'The user does not have permission to change the amazing picture.', | ||
// ); | ||
await this.amazingPictureService.deleteAmazingPicture(); | ||
return await this.amazingPictureService.uploadAmazingPicture( | ||
amazing_picture, | ||
return ( | ||
(await this.amazingPictureService.delete()) && | ||
(await this.amazingPictureService.create(file)) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,43 @@ | ||
import { HttpService } from '@nestjs/axios'; | ||
import { Injectable } from '@nestjs/common'; | ||
import { AxiosResponse } from 'axios'; | ||
import { Injectable, InternalServerErrorException } from '@nestjs/common'; | ||
import { FileUpload } from 'graphql-upload'; | ||
import { DatabaseService } from 'src/database/database.service'; | ||
import { StorageService } from 'src/storage/storage.service'; | ||
import { env } from 'src/utils/envs'; | ||
|
||
@Injectable() | ||
export class AmazingPictureService { | ||
constructor(private readonly httpService: HttpService) {} | ||
constructor( | ||
private readonly storageService: StorageService, | ||
private readonly databaseService: DatabaseService, | ||
) {} | ||
|
||
uploadAmazingPicture(amazing_picture: string): Promise<boolean> { | ||
return new Promise((resolve, reject) => { | ||
this.httpService | ||
.post( | ||
`http://${env.storage.host}:${env.storage.port}/upload/amazing_picture`, | ||
amazing_picture, | ||
) | ||
.subscribe({ | ||
next: async (axiosResponse: AxiosResponse) => { | ||
if (axiosResponse.status === 201) resolve(true); | ||
else resolve(false); | ||
}, | ||
error(error) { | ||
reject(error); | ||
}, | ||
complete() {}, | ||
}); | ||
}); | ||
async find() { | ||
return ( | ||
await this.databaseService.executeQuery( | ||
`SELECT url FROM ${env.database.schema}.storage_url WHERE filename = "amazing_picture";`, | ||
) | ||
).at(0)?.url; | ||
} | ||
|
||
deleteAmazingPicture(): void { | ||
this.httpService.delete( | ||
`http://${env.storage.host}:${env.storage.port}/delete/amazing_picture`, | ||
async create(file: FileUpload) { | ||
const amazingUrl = await this.storageService.post(file); | ||
if (!amazingUrl) | ||
throw new InternalServerErrorException( | ||
`Error occured during upload file, ${file.filename}`, | ||
); | ||
await this.databaseService.executeQuery( | ||
`INSERT INTO ${env.database.schema}.storage_url(filename, url) VALUES("amazing_picture", "${amazingUrl}");`, | ||
); | ||
return true; | ||
} | ||
|
||
async delete() { | ||
const filename = ( | ||
await this.databaseService.executeQuery( | ||
`DELETE FROM ${env.database.schema}.storage_url WHERE filename = "amazing_picture" RETURNING "url";`, | ||
) | ||
).at(0)?.url; | ||
await this.storageService.delete(filename); | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { SetMetadata } from '@nestjs/common'; | ||
import { UserRole } from 'src/users/models/user.model'; | ||
|
||
export const SITE_ROLES_KEY = 'siteRoles'; | ||
export const SiteRoles = (...roles: UserRole[]) => | ||
SetMetadata(SITE_ROLES_KEY, roles); |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; | ||
import { Reflector } from '@nestjs/core'; | ||
import { GqlContextType, GqlExecutionContext } from '@nestjs/graphql'; | ||
import { SITE_ROLES_KEY } from '../decorators/site-roles.decorator'; | ||
import { UserRole } from '../models/user.model'; | ||
import { UsersService } from '../users.service'; | ||
|
||
@Injectable() | ||
export class SiteRoleGuard implements CanActivate { | ||
constructor( | ||
private readonly usersService: UsersService, | ||
private readonly reflector: Reflector, | ||
) {} | ||
|
||
async canActivate( | ||
context: ExecutionContext & { req: any }, | ||
): Promise<boolean> { | ||
const requiredRoles: UserRole[] = this.reflector.get<UserRole[]>( | ||
SITE_ROLES_KEY, | ||
context.getHandler(), | ||
); | ||
|
||
if (!requiredRoles) return true; | ||
|
||
let session: { uid: string }; | ||
if (context.getType() === 'http') { | ||
session = context.switchToHttp().getRequest().session; | ||
} else if (context.getType<GqlContextType>() === 'graphql') { | ||
session = GqlExecutionContext.create(context).getContext().req.session; | ||
} else { | ||
throw `Unexpected context type: ${context.getType()}`; | ||
} | ||
|
||
const userSiteRole: UserRole = await this.usersService.getSiteRole( | ||
session.uid, | ||
); | ||
|
||
for (const requiredRole of requiredRoles) { | ||
if (requiredRole === UserRole.OWNER && userSiteRole !== UserRole.OWNER) | ||
return false; | ||
else if ( | ||
requiredRole === UserRole.ADMIN && | ||
userSiteRole === UserRole.USER | ||
) | ||
return false; | ||
} | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.