Skip to content

Commit 8ff8cba

Browse files
authored
fix(profile): v2 (#110)
* fix(profile): fix profile posts ordering * fix(profile): add reply context to liked and media posts * fix(auth): fix confirm password response status codes * feat(profile): add posts counters to user * feat(profile): add user posts counts in profile response * feat(profile): add email to profile response * fix(profile): add reposts count to profile
1 parent 0c67a5a commit 8ff8cba

File tree

5 files changed

+57
-8
lines changed

5 files changed

+57
-8
lines changed

src/auth/auth.controller.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,9 @@ export class AuthController {
660660
@ApiOperation(confirm_password_swagger.operation)
661661
@ApiBody({ type: ConfirmPasswordDto })
662662
@ApiOkResponse(confirm_password_swagger.responses.success)
663-
@ApiUnauthorizedErrorResponse(ERROR_MESSAGES.WRONG_PASSWORD)
664-
@ApiUnauthorizedErrorResponse(ERROR_MESSAGES.SOCIAL_LOGIN_REQUIRED)
663+
@ApiUnauthorizedErrorResponse(ERROR_MESSAGES.INVALID_OR_EXPIRED_TOKEN)
664+
@ApiForbiddenErrorResponse(ERROR_MESSAGES.WRONG_PASSWORD)
665+
@ApiConflictErrorResponse(ERROR_MESSAGES.ACCOUNT_HAS_NO_PASSWORD)
665666
@ApiNotFoundErrorResponse(ERROR_MESSAGES.USER_NOT_FOUND)
666667
@ResponseMessage(SUCCESS_MESSAGES.PASSWORD_CONFIRMED)
667668
@Post('confirm-password')

src/auth/auth.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,9 +1086,9 @@ export class AuthService {
10861086
confirm_password_dto.password,
10871087
user.password
10881088
);
1089-
if (!is_password_valid) throw new UnauthorizedException(ERROR_MESSAGES.WRONG_PASSWORD);
1089+
if (!is_password_valid) throw new ForbiddenException(ERROR_MESSAGES.WRONG_PASSWORD);
10901090
} else {
1091-
throw new UnauthorizedException(ERROR_MESSAGES.SOCIAL_LOGIN_REQUIRED);
1091+
throw new ConflictException(ERROR_MESSAGES.ACCOUNT_HAS_NO_PASSWORD);
10921092
}
10931093

10941094
return { valid: true };

src/constants/swagger-messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const ERROR_MESSAGES = {
1717
PHONE_NUMBER_NOT_FOUND: 'Phone number not found',
1818
USERNAME_NOT_FOUND: 'Username not found',
1919
USERNAME_ALREADY_TAKEN: 'Username is already taken',
20+
ACCOUNT_HAS_NO_PASSWORD: 'Account does not have a password set',
2021

2122
// OAuth completion
2223
INVALID_OAUTH_SESSION_TOKEN: 'Invalid OAuth session token',

src/user/dto/user-profile.dto.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ export class UserProfileDto {
55
@Expose()
66
user_id: string;
77

8+
@Expose()
9+
email?: string;
10+
811
@Expose()
912
name: string;
1013

@@ -42,4 +45,16 @@ export class UserProfileDto {
4245
return Number(source) || 0;
4346
})
4447
following_count: number;
48+
49+
@Expose()
50+
num_posts: number;
51+
52+
@Expose()
53+
num_replies: number;
54+
55+
@Expose()
56+
num_media: number;
57+
58+
@Expose()
59+
num_likes?: number;
4560
}

src/user/user.repository.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,16 @@ export class UserRepository extends Repository<User> {
6363
}
6464

6565
async getMyProfile(current_user_id: string): Promise<UserProfileDto | null> {
66-
const profile = await this.buildProfileQuery(
67-
current_user_id,
68-
'id'
69-
).getRawOne<UserProfileDto>();
66+
const query = this.buildProfileQuery(current_user_id, 'id');
67+
query.addSelect('user.email AS email');
68+
query.addSelect((sub_query) => {
69+
return sub_query
70+
.select('COUNT(*)', 'count')
71+
.from('tweet_likes', 'tl')
72+
.where('tl.user_id = user.id');
73+
}, 'num_likes');
74+
75+
const profile = await query.getRawOne<UserProfileDto>();
7076
return profile ?? null;
7177
}
7278

@@ -126,6 +132,32 @@ export class UserRepository extends Repository<User> {
126132
'user.following AS following_count',
127133
]);
128134

135+
query.addSelect((sub_query) => {
136+
return sub_query
137+
.select('COUNT(*)', 'count')
138+
.from('tweets', 't')
139+
.where('t.user_id = user.id')
140+
.andWhere("t.type = 'reply'")
141+
.andWhere('t.deleted_at IS NULL');
142+
}, 'num_replies');
143+
144+
query.addSelect(
145+
`(
146+
(SELECT COUNT(*) FROM tweets t WHERE t.user_id = user.id AND t.type != 'reply' AND t.deleted_at IS NULL) +
147+
(SELECT COUNT(*) FROM tweet_reposts r WHERE r.user_id = user.id)
148+
)`,
149+
'num_posts'
150+
);
151+
152+
query.addSelect((sub_query) => {
153+
return sub_query
154+
.select('COUNT(*)', 'count')
155+
.from('tweets', 't')
156+
.where('t.user_id = user.id')
157+
.andWhere('(array_length(t.images, 1) > 0 OR array_length(t.videos, 1) > 0)')
158+
.andWhere('t.deleted_at IS NULL');
159+
}, 'num_media');
160+
129161
if (identifier_type === 'id') {
130162
query.where('user.id = :identifier', { identifier });
131163
} else {

0 commit comments

Comments
 (0)