-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9740ca3
commit 0780512
Showing
15 changed files
with
190 additions
and
68 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
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
This file was deleted.
Oops, something went wrong.
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,18 @@ | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
import { IsBoolean, IsNotEmpty, IsString } from 'class-validator'; | ||
|
||
export class ResourceUserDto { | ||
@IsNotEmpty() | ||
@IsString() | ||
@ApiProperty({ type: String }) | ||
resourceId: string; | ||
|
||
@IsNotEmpty() | ||
@IsString() | ||
@ApiProperty({ type: String }) | ||
userId: string; | ||
|
||
@IsBoolean() | ||
@ApiProperty({ type: Date }) | ||
completedAt?: Date; | ||
} |
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,7 +1,9 @@ | ||
import { IsDate, IsOptional } from 'class-validator'; | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
import { IsDefined, IsNotEmpty } from 'class-validator'; | ||
|
||
export class UpdateResourceUserDto { | ||
@IsOptional() | ||
@IsDate() | ||
completedAt?: Date; | ||
@IsNotEmpty() | ||
@IsDefined() | ||
@ApiProperty({ type: Number }) | ||
storyblokId: number; | ||
} |
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,47 +1,61 @@ | ||
import { | ||
Body, | ||
Controller, | ||
HttpException, | ||
Param, | ||
Patch, | ||
Post, | ||
Req, | ||
UseGuards, | ||
} from '@nestjs/common'; | ||
import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; | ||
import { FirebaseAuthGuard } from 'src/firebase/firebase-auth.guard'; | ||
import { CreateResourceUserDto } from './dtos/create-resource-user.dto'; | ||
import { Body, Controller, Post, Req, UseGuards } from '@nestjs/common'; | ||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; | ||
import { Request } from 'express'; | ||
import { ControllerDecorator } from 'src/utils/controller.decorator'; | ||
import { UserEntity } from '../entities/user.entity'; | ||
import { FirebaseAuthGuard } from '../firebase/firebase-auth.guard'; | ||
import { UpdateResourceUserDto } from './dtos/update-resource-user.dto'; | ||
import { ResourceUserService } from './resource-user.service'; | ||
|
||
@Controller('v1/resource-user') | ||
@ApiTags('Resource User') | ||
@ControllerDecorator() | ||
@Controller('/v1/resource-user') | ||
export class ResourceUserController { | ||
constructor(private readonly resourceUserService: ResourceUserService) {} | ||
|
||
@Post() | ||
@ApiBearerAuth('access-token') | ||
@ApiOperation({ | ||
description: 'Updates resource_user table', | ||
description: | ||
'Stores relationship between a `User` and `Resource` records, once a user has started a resource.', | ||
}) | ||
@UseGuards(FirebaseAuthGuard) | ||
create(@Req() req: Request, @Body() createResourceUserDto: CreateResourceUserDto) { | ||
if (req['userEntity'].id !== createResourceUserDto.userId) { | ||
throw new HttpException('Unauthorized', 401); | ||
} | ||
return this.resourceUserService.create(createResourceUserDto); | ||
async createResourceUser( | ||
@Req() req: Request, | ||
@Body() createResourceUserDto: UpdateResourceUserDto, | ||
) { | ||
return await this.resourceUserService.createResourceUser( | ||
req['userEntity'] as UserEntity, | ||
createResourceUserDto, | ||
); | ||
} | ||
|
||
@Patch(':id') | ||
@Post('/complete') | ||
@ApiOperation({ | ||
description: 'Updates a users resources progress to completed', | ||
}) | ||
@ApiBearerAuth('access-token') | ||
@UseGuards(FirebaseAuthGuard) | ||
async complete(@Req() req: Request, @Body() updateResourceUserDto: UpdateResourceUserDto) { | ||
return await this.resourceUserService.setResourceUserCompleted( | ||
req['userEntity'] as UserEntity, | ||
updateResourceUserDto, | ||
true, | ||
); | ||
} | ||
|
||
@Post('/incomplete') | ||
@ApiOperation({ | ||
description: 'Updates resource_user table', | ||
description: | ||
'Updates a users resources progress to incomplete, undoing a previous complete action', | ||
}) | ||
@ApiBearerAuth('access-token') | ||
@UseGuards(FirebaseAuthGuard) | ||
update( | ||
@Req() req: Request, | ||
@Param('id') id: string, | ||
@Body() updateResourceUserDto: UpdateResourceUserDto, | ||
) { | ||
return this.resourceUserService.update(id, updateResourceUserDto); | ||
async incomplete(@Req() req: Request, @Body() updateResourceUserDto: UpdateResourceUserDto) { | ||
return await this.resourceUserService.setResourceUserCompleted( | ||
req['userEntity'] as UserEntity, | ||
updateResourceUserDto, | ||
false, | ||
); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,97 @@ | ||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; | ||
import { InjectRepository } from '@nestjs/typeorm'; | ||
import { ResourceUserEntity } from 'src/entities/resource-user.entity'; | ||
import { UserEntity } from 'src/entities/user.entity'; | ||
import { ResourceService } from 'src/resource/resource.service'; | ||
import { formatResourceUserObject } from 'src/utils/serialize'; | ||
import { Repository } from 'typeorm'; | ||
import { CreateResourceUserDto } from './dtos/create-resource-user.dto'; | ||
import { ResourceUserDto } from './dtos/resource-user.dto'; | ||
import { UpdateResourceUserDto } from './dtos/update-resource-user.dto'; | ||
|
||
@Injectable() | ||
export class ResourceUserService { | ||
constructor( | ||
@InjectRepository(ResourceUserEntity) | ||
private resourceUserRepository: Repository<ResourceUserEntity>, | ||
private resourceService: ResourceService, | ||
) {} | ||
|
||
create(createResourceUserDto: CreateResourceUserDto) { | ||
return this.resourceUserRepository.save(createResourceUserDto); | ||
private async getResourceUser({ | ||
resourceId, | ||
userId, | ||
}: ResourceUserDto): Promise<ResourceUserEntity> { | ||
return await this.resourceUserRepository | ||
.createQueryBuilder('resource_user') | ||
.leftJoinAndSelect('resource_user.resource', 'resource') | ||
.where('resource_user.userId = :userId', { userId }) | ||
.andWhere('resource_user.resourceId = :resourceId', { resourceId }) | ||
.getOne(); | ||
} | ||
|
||
update(id: string, updateResourceUserDto: UpdateResourceUserDto) { | ||
const resourceUser = this.resourceUserRepository.findOne({ where: { id } }); | ||
async createResourceUserRecord({ | ||
resourceId, | ||
userId, | ||
}: ResourceUserDto): Promise<ResourceUserEntity> { | ||
return await this.resourceUserRepository.save({ | ||
resourceId, | ||
userId, | ||
completedAt: null, | ||
}); | ||
} | ||
|
||
public async createResourceUser(user: UserEntity, { storyblokId }: UpdateResourceUserDto) { | ||
const resource = await this.resourceService.getResourceByStoryblokId(storyblokId); | ||
|
||
if (!resource) { | ||
throw new HttpException('RESOURCE NOT FOUND', HttpStatus.NOT_FOUND); | ||
} | ||
|
||
let resourceUser = await this.getResourceUser({ | ||
resourceId: resource.id, | ||
userId: user.id, | ||
}); | ||
|
||
if (!resourceUser) { | ||
throw new HttpException('RESOURCE USER NOT FOUND', HttpStatus.NOT_FOUND); | ||
resourceUser = await this.createResourceUserRecord({ | ||
resourceId: resource.id, | ||
userId: user.id, | ||
}); | ||
} | ||
|
||
return formatResourceUserObject([{ ...resourceUser, resource }])[0]; | ||
} | ||
|
||
public async setResourceUserCompleted( | ||
user: UserEntity, | ||
{ storyblokId }: UpdateResourceUserDto, | ||
completed: boolean, | ||
) { | ||
const resource = await this.resourceService.getResourceByStoryblokId(storyblokId); | ||
|
||
if (!resource) { | ||
throw new HttpException( | ||
`Resource not found for storyblok id: ${storyblokId}`, | ||
HttpStatus.NOT_FOUND, | ||
); | ||
} | ||
|
||
const updatedResourceUser = { ...resourceUser, ...updateResourceUserDto }; | ||
let resourceUser = await this.getResourceUser({ | ||
resourceId: resource.id, | ||
userId: user.id, | ||
}); | ||
|
||
if (resourceUser) { | ||
await this.resourceUserRepository.save({ | ||
...resourceUser, | ||
completedAt: completed ? new Date() : null, | ||
}); | ||
} else { | ||
resourceUser = await this.createResourceUserRecord({ | ||
resourceId: resource.id, | ||
userId: user.id, | ||
}); | ||
} | ||
|
||
return this.resourceUserRepository.save(updatedResourceUser); | ||
return formatResourceUserObject([{ ...resourceUser, resource }])[0]; | ||
} | ||
} |
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,14 @@ | ||
import { RESOURCE_CATEGORIES, STORYBLOK_STORY_STATUS_ENUM } from 'src/utils/constants'; | ||
|
||
export interface IResource { | ||
id?: string; | ||
createdAt?: Date | string; | ||
updatedAt?: Date | string; | ||
name?: string; | ||
slug?: string; | ||
status?: STORYBLOK_STORY_STATUS_ENUM; | ||
storyblokId?: number; | ||
storyblokUuid?: string; | ||
category?: RESOURCE_CATEGORIES; | ||
completedAt?: Date | string; | ||
} |
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 was deleted.
Oops, something went wrong.
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.