Skip to content

Commit

Permalink
Merge pull request #21 from katelovestocode/BE-20-connect-to-AWS
Browse files Browse the repository at this point in the history
BE-20-connect-to-aws
  • Loading branch information
Ivanus-Volodymyr authored Dec 21, 2023
2 parents 0f1b626 + f401aaa commit 51b24de
Show file tree
Hide file tree
Showing 24 changed files with 231 additions and 56 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ jobs:
script: |
set -x
cd app/backend-internship
git checkout develop
sudo chown ubuntu redis/data/dump.rdb
git stash save "Stashing changes to dump.rdb"
git pull origin develop
git checkout develop
git pull origin develop
echo "PORT=${{ secrets.PORT }}" > .env
echo "HOST=${{ secrets.HOST }}" >> .env
echo "NODE_ENV=${{ secrets.NODE_ENV }}" >> .env
Expand All @@ -44,6 +43,7 @@ jobs:
echo "AUTH0_ISSUER_URL=${{ secrets.AUTH0_ISSUER_URL }}" >> .env
echo "REDIS_URL=${{ secrets.REDIS_URL }}" >> .env
echo "AUTH0_JWKS_URL=${{ secrets.AUTH0_JWKS_URL }}" >> .env
docker-compose stop backend
docker-compose rm -f backend
sudo chmod -R 777 pgdata
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ lerna-debug.log*
!.vscode/extensions.json

.env
pgdata/
6 changes: 6 additions & 0 deletions db/typeorm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ export default new DataSource({
synchronize: false,
migrationsTableName: 'migrations',
logging: ['query', 'error'],
ssl: true,
extra: {
ssl: {
rejectUnauthorized: false,
}
}
})
18 changes: 9 additions & 9 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ services:
- DB_NAME=${DB_NAME}
- DB_PORT=${DB_PORT}

redis:
image: redis
ports:
- '6379:6379'
container_name: redis-cache
environment:
- REDIS_HOSTS=local:redis:6379
volumes:
- ./redis/data:/data
# redis:
# image: redis
# ports:
# - '6379:6379'
# container_name: redis-cache
# environment:
# - REDIS_HOSTS=local:redis:6379
# volumes:
# - ./redis/data:/data

volumes:
pgdata:
Binary file modified redis/data/dump.rdb
Binary file not shown.
2 changes: 1 addition & 1 deletion src/analytics/analytics.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class AnalyticsController {
return await this.analyticsService.getUserQuizAverages(+userId, +quizId)
}

// get list of all user's quiz attempts
// get list of all last user's quiz attempts
@Get('/users/:userId/quizzes')
@UseGuards(AuthGuard(['jwt', 'auth0']), UserValidGuard)
@HttpCode(HttpStatus.OK)
Expand Down
28 changes: 19 additions & 9 deletions src/analytics/analytics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class AnalyticsService {
}
}

// get list of all user's quiz attempts
// get list of all last user's quiz attempts
async getUserAllQuizAverages(userId: number): Promise<QuizzAverageResponse> {
try {
const user = await this.userRepository.findOne({
Expand All @@ -129,19 +129,29 @@ export class AnalyticsService {
throw new NotFoundException('User is not found')
}

const analytics = user.quizAttempts.map((quiz) => {
return {
userId: userId,
userName: quiz.user.name,
quizAttemptId: quiz.id,
quizAvarage: quiz.overallRatingAcrossSystem,
quizTime: quiz.timestamp,
const latestAttempts: { [quizId: number]: any } = {}

user.quizAttempts.forEach((attempt) => {
const quizId = attempt.quiz.id
if (
!latestAttempts[quizId] ||
attempt.timestamp > latestAttempts[quizId].quizTime
) {
latestAttempts[quizId] = {
userId: attempt.user.id,
userName: attempt.user.name,
quizAttemptId: attempt.id,
quizAvarage: attempt.averageScoreWithinCompany,
quizTime: attempt.timestamp,
}
}
})

const analytics = Object.values(latestAttempts)

return {
status_code: HttpStatus.OK,
result: `User average ratings in all quizzes`,
result: `List of all LAST users average quizz attempts`,
details: {
analytics: analytics,
},
Expand Down
1 change: 0 additions & 1 deletion src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ export class AuthService {
//refresh token
async refreshTokens(user: any): Promise<RefreshType> {
try {

const { id, email } = user

const findUser = await this.userService.getUserByEmail(email)
Expand Down
11 changes: 5 additions & 6 deletions src/auth/guards/refresh.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ export class RefresJwtGuard implements CanActivate {
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const req = context.switchToHttp().getRequest()
console.log(req.body.refreshToken, 'req')
try {
const user = this.jwtService.verify(
req.body.refreshToken['refreshToken'],
{
secret: process.env.REFRESH_SECRET_KEY,
})

const user = this.jwtService.verify(req.body.refreshToken, {
secret: process.env.REFRESH_SECRET_KEY,
})

req.user = user
return true
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/company/company.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ export class CompanyService {
)
}

company.members = company.members.filter((user) => user.id !== userId);
company.admins = company.admins.filter((admin) => admin.id !== userId);
company.members = company.members.filter((user) => user.id !== userId)
company.admins = company.admins.filter((admin) => admin.id !== userId)
const updated = await this.companyRepository.save(company)

return {
Expand Down
6 changes: 4 additions & 2 deletions src/company/guards/company-validation.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class CompanyValidGuard implements CanActivate {
try {
const company = await this.companyRepository.findOne({
where: { id: +companyId },
relations: ['owner'],
relations: ['owner', 'admins'],
})
const user = await this.userRepository.findOne({
where: { email: reqEmail },
Expand All @@ -46,7 +46,9 @@ export class CompanyValidGuard implements CanActivate {
throw new BadRequestException('User is not found')
}

if (company.owner.id !== user.id) {
const isAdmin = company.admins.some((admin) => admin.id === user.id)

if (!isAdmin && company.owner.id !== user.id) {
throw new UnauthorizedException(
'You can only update, delete and see your own companies',
)
Expand Down
7 changes: 7 additions & 0 deletions src/company/types/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { User } from 'src/user/entities/user.entity'
import { Company } from '../entities/company.entity'

export type AllCompaniesResponse = {
Expand Down Expand Up @@ -43,3 +44,9 @@ export enum RequestStatus {
Declined = 'declined',
Cancelled = 'cancelled',
}

export type CompaniesResponse = {
status_code: number
result: string
details: { list: User }
}
5 changes: 3 additions & 2 deletions src/questions/question.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { QuestionDto } from 'src/quizzes/dto/create-quiz.dto'
import { AuthGuard } from '@nestjs/passport'
import { AdminOrOwnerValidGuard } from 'src/company/guards/admin-validation.guard'
import { DeletedQuestionRes, QuestionResponse } from './types/types'
import { UpdateQuestionDto } from 'src/quizzes/dto/update-quiz.dto'

@Controller('questions')
export class QuestionController {
Expand Down Expand Up @@ -42,12 +43,12 @@ export class QuestionController {
async updateQuestionToQuiz(
@Param('quizId') quizId: string,
@Param('questionId') questionId: string,
@Body() createQuestionDto: QuestionDto,
@Body() updateQuestionDto: UpdateQuestionDto,
): Promise<QuestionResponse> {
return await this.questionService.updateOneQuestionToQuiz(
+quizId,
+questionId,
createQuestionDto,
updateQuestionDto,
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/questions/question.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { JwtModule } from '@nestjs/jwt'
Question,
Notification,
]),
JwtModule
JwtModule,
],
controllers: [QuestionController],
providers: [QuestionService, NotificationsService, EventsGateway],
Expand Down
36 changes: 36 additions & 0 deletions src/questions/question.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BadRequestException,
HttpStatus,
Injectable,
InternalServerErrorException,
Expand Down Expand Up @@ -58,6 +59,24 @@ export class QuestionService {
throw new NotFoundException('Quiz is not found')
}

if (createQuestionDto.answers) {
if (
new Set(createQuestionDto.answers).size !==
createQuestionDto.answers.length
) {
throw new BadRequestException('Answers must be unique')
}

if (
createQuestionDto.correctAnswer &&
!createQuestionDto.answers.includes(createQuestionDto.correctAnswer)
) {
throw new BadRequestException(
'Correct answer must be one of the provided answers',
)
}
}

const newQuestion = this.questionRepository.create({
question,
answers,
Expand Down Expand Up @@ -94,6 +113,23 @@ export class QuestionService {
throw new NotFoundException('Question is not found')
}

if (updateQuestionDto.answers) {
if (
new Set(updateQuestionDto.answers).size !==
updateQuestionDto.answers.length
) {
throw new BadRequestException('Answers must be unique')
}

if (
updateQuestionDto.correctAnswer &&
!updateQuestionDto.answers.includes(updateQuestionDto.correctAnswer)
) {
throw new BadRequestException(
'Correct answer must be one of the provided answers',
)
}
}
existingQuestion.question = updateQuestionDto.question
existingQuestion.answers = updateQuestionDto.answers
existingQuestion.correctAnswer = updateQuestionDto.correctAnswer
Expand Down
5 changes: 4 additions & 1 deletion src/quiz_attempts/entities/quiz_attempt.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ export class QuizAttempt {
@ManyToOne(() => User, (user) => user.quizAttempts)
user: User

@ManyToOne(() => Quiz, (quiz) => quiz.quizAttempts)
@ManyToOne(() => Quiz, (quiz) => quiz.quizAttempts, {
cascade: true,
onDelete: 'CASCADE',
})
quiz: Quiz

@ManyToOne(() => Company, (company) => company.quizAttempts)
Expand Down
13 changes: 12 additions & 1 deletion src/quiz_attempts/quiz_attempt.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import {
Post,
Body,
UseInterceptors,
Get,
} from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'
import { UserValidGuard } from 'src/user/guards/validation.guard'
import { CreateQuizAttemptDto } from './dto/create-quiz_attempt.dto'
import { QuizAttemptService } from './quiz_attempt.service'
import { QuizAttemptRes } from './types/types'
import { FilteredQuizAttemptsType, QuizAttemptRes } from './types/types'
import { CacheInterceptor } from '@nestjs/cache-manager'

@Controller('')
Expand All @@ -35,4 +36,14 @@ export class QuizAttemptController {
createQuizAttemptDto,
)
}

// all user's quiz attempts
@Get('/users/:userId/quizzes/attempts')
@UseGuards(AuthGuard(['jwt', 'auth0']), UserValidGuard)
@HttpCode(HttpStatus.OK)
async userGetsQuizAttempts(
@Param('userId') userId: string,
): Promise<FilteredQuizAttemptsType> {
return await this.quizAttemptService.userGetsAllQuizAttempts(+userId)
}
}
Loading

0 comments on commit 51b24de

Please sign in to comment.