Skip to content

Commit

Permalink
Circular dependency detected is fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
Szotkowski committed Sep 21, 2023
1 parent 1e01144 commit d7dae81
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 79 deletions.
121 changes: 63 additions & 58 deletions src/controllers/user-instruction.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class UserInstructionController {
@repository(StepRepository) public stepRepository: StepRepository,
@repository(UserRepository)
protected progressRepository: ProgressRepository,
) {}
) { }

@authenticate('jwt')
@post('/users/{id}/instructions/{instructionId}', {
Expand Down Expand Up @@ -466,6 +466,68 @@ export class UserInstructionController {
return true;
}

@authenticate('jwt')
@patch('/authorizate-for-premium-instruction/{instructionId}/{userId}', {
responses: {
'200': {
description: 'Authorize user for premium instructions',
content: {
'application/json': {
schema: {
type: 'boolean',
},
},
},
},
},
})
async authorizeUserToPremiumInstruction(
@requestBody({
content: {
'application/json': {
schema: {
type: 'object',
properties: {
key: {type: 'string'},
},
required: ['key'],
},
},
},
})
request: {
key: string;
},
@param.query.number('instructionId') instructionId: number,
@param.query.number('userId') userId: number,
): Promise<boolean> {
const user = await this.userRepository.findById(this.user.id);
if (!user) {
throw new HttpErrors.NotFound('User not found');
}
const instructionKey =
process.env.INSTRUCTION_KEY_PREMIUM_PERMISSIONS ?? '';
const keyMatch = await this.hasher.comparePassword(
request.key,
instructionKey,
);
if (!keyMatch) {
throw new HttpErrors.Unauthorized('Invalid password');
}
const instruction =
await this.instructionRepository.findById(instructionId);
instruction.premiumUserIds = instruction.premiumUserIds ?? [];
if (instruction.premiumUserIds.includes(userId)) {
instruction.premiumUserIds = instruction.premiumUserIds.filter(
id => id !== userId,
);
} else {
instruction.premiumUserIds.push(userId);
}
await this.instructionRepository.updateById(instructionId, instruction);
return true;
}

@get('/public-instructions', {
responses: {
'200': {
Expand Down Expand Up @@ -630,63 +692,6 @@ export class UserInstructionController {
return data;
}

@patch('/authorizate-for-premium-instruction/{instructionId}/{userId}', {
responses: {
'200': {
description: 'Authorize user for premium instructions',
content: {
'application/json': {
schema: {
type: 'boolean',
},
},
},
},
},
})
async authorizeUserToPremiumInstruction(
@requestBody({
content: {
'application/json': {
schema: {
type: 'object',
properties: {
key: {type: 'string'},
},
required: ['key'],
},
},
},
})
request: {
key: string;
},
@param.query.number('instructionId') instructionId: number,
@param.query.number('userId') userId: number,
): Promise<boolean> {
const instructionKey =
process.env.INSTRUCTION_KEY_PREMIUM_PERMISSIONS ?? '';
const keyMatch = await this.hasher.comparePassword(
request.key,
instructionKey,
);
if (!keyMatch) {
throw new HttpErrors.Unauthorized('Invalid password');
}
const instruction =
await this.instructionRepository.findById(instructionId);
instruction.premiumUserIds = instruction.premiumUserIds ?? [];
if (instruction.premiumUserIds.includes(userId)) {
instruction.premiumUserIds = instruction.premiumUserIds.filter(
id => id !== userId,
);
} else {
instruction.premiumUserIds.push(userId);
}
await this.instructionRepository.updateById(instructionId, instruction);
return true;
}

private validateInstructionOwnership(instruction: Instruction): void {
if (Number(instruction.userId) !== Number(this.user.id)) {
throw new HttpErrors.Forbidden(
Expand Down
112 changes: 102 additions & 10 deletions src/controllers/user-link.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,23 @@ export class UserLinkController {
@repository(UserRepository) public userRepository: UserRepository,
@repository(UserLinkRepository)
public userLinkRepository: UserLinkRepository,
) {}
) { }

@authenticate('jwt')
@post('/users/{id}/follow/{followeeId}')
@post('/users/{id}/follow/{followeeId}', {
responses: {
'200': {
description: 'Follow User',
content: {
'application/json': {
schema: {
type: 'boolean',
},
},
},
},
},
})
async followUser(
@param.path.number('followeeId') followeeId: number,
): Promise<boolean> {
Expand All @@ -39,7 +52,20 @@ export class UserLinkController {
}

@authenticate('jwt')
@del('/users/{id}/unfollow/{followeeId}')
@del('/users/{id}/unfollow/{followeeId}', {
responses: {
'200': {
description: 'Unfollow User',
content: {
'application/json': {
schema: {
type: 'boolean',
},
},
},
},
},
})
async unfollowUser(
@param.path.number('followeeId') followeeId: number,
): Promise<boolean> {
Expand All @@ -63,12 +89,30 @@ export class UserLinkController {
return true;
}

@get('/users/{id}/followers')
@get('/users/{userId}/followers', {
responses: {
'200': {
description: 'Get followers',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
id: {type: 'number'},
username: {type: 'string'},
link: {type: 'string'},
},
},
},
},
},
},
})
async getFollowers(
@param.path.number('id') userId: number,
@param.path.number('userId') userId: number,
@param.query.number('limit') limit: number = 10,
@param.query.number('offset') offset: number = 0,
): Promise<User[]> {
): Promise<Partial<User[]>> {
const userLinks = await this.userLinkRepository.find({
where: {
followeeId: userId,
Expand All @@ -81,16 +125,49 @@ export class UserLinkController {
where: {
id: {inq: followerIds},
},
fields: {
email: false,
passwordHash: false,
wrappedDEK: false,
initializationVector: false,
kekSalt: false,
language: false,
darkmode: false,
emailVerified: false,
date: false,
nick: false,
bio: false,
deleteHash: false,
favorites: false,
},
});
return followers;
}

@get('/users/{id}/following')
async getFollowing(
@param.path.number('id') userId: number,
@get('/users/{userId}/followees', {
responses: {
'200': {
description: 'Get followees',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
id: {type: 'number'},
username: {type: 'string'},
link: {type: 'string'},
},
},
},
},
},
},
})
async getFollowees(
@param.path.number('userId') userId: number,
@param.query.number('limit') limit: number = 10,
@param.query.number('offset') offset: number = 0,
): Promise<User[]> {
): Promise<Partial<User[]>> {
const userLinks = await this.userLinkRepository.find({
where: {
followerId: userId,
Expand All @@ -103,6 +180,21 @@ export class UserLinkController {
where: {
id: {inq: followeeIds},
},
fields: {
email: false,
passwordHash: false,
wrappedDEK: false,
initializationVector: false,
kekSalt: false,
language: false,
darkmode: false,
emailVerified: false,
date: false,
nick: false,
bio: false,
deleteHash: false,
favorites: false,
},
});
return following;
}
Expand Down
12 changes: 7 additions & 5 deletions src/controllers/user-progress.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {authenticate} from '@loopback/authentication';
import {inject} from '@loopback/core';
import {
JWTService
} from '@loopback/authentication-jwt';
import {inject} from '@loopback/context';
import {repository} from '@loopback/repository';
import {
HttpErrors,
Expand All @@ -8,16 +11,15 @@ import {
param,
patch,
post,
requestBody,
requestBody
} from '@loopback/rest';
import {SecurityBindings, UserProfile} from '@loopback/security';
import {Progress, ProgressRelations} from '../models';
import {
InstructionRepository,
ProgressRepository,
UserRepository,
UserRepository
} from '../repositories';
import {JWTService} from '../services';

export class UserProgressController {
constructor(
Expand Down Expand Up @@ -176,7 +178,7 @@ export class UserProgressController {
}

@authenticate('jwt')
@get('/users/{id}/progress/{instructionId}', {
@get('/users/{id}/progresses/{instructionId}', {
responses: {
'200': {
description: 'Progress model instance',
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ export class UserController {
return usernamesAndLinks;
}

@get('/user-detail/{id}', {
@get('/user-detail/{userId}', {
responses: {
'200': {
description: 'Get user detail',
Expand Down Expand Up @@ -910,7 +910,7 @@ export class UserController {
},
},
})
async getUserDetail(@param.query.number('id') userId: number): Promise<{
async getUserDetail(@param.query.number('userId') userId: number): Promise<{
user: Omit<
User,
| 'email'
Expand Down
6 changes: 2 additions & 4 deletions src/services/jwt-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {TokenObject} from '@loopback/authentication-jwt';
import {inject} from '@loopback/core';
import {repository} from '@loopback/repository';
import {HttpErrors} from '@loopback/rest';
import {securityId, UserProfile} from '@loopback/security';
import {UserProfile, securityId} from '@loopback/security';
import {promisify} from 'util';
import {
UserRepository
Expand All @@ -27,8 +27,6 @@ export class JWTService implements TokenService {
private jwtExpiresIn: string,
@inject('services.user.service')
public userService: MyUserService,
@inject('services.jwt.service')
public jwtService: JWTService,
@repository(UserRepository) protected userRepository: UserRepository,
) { }

Expand Down Expand Up @@ -96,7 +94,7 @@ export class JWTService implements TokenService {
const userProfile: UserProfile =
this.userService.convertToUserProfile(user);
// create a JSON Web Token based on the user profile
const token = await this.jwtService.generateToken(userProfile);
const token = await this.generateToken(userProfile);
return {
accessToken: token,
};
Expand Down

0 comments on commit d7dae81

Please sign in to comment.