Skip to content

Commit 349cbfc

Browse files
committed
Improve user information service
1 parent 22023ac commit 349cbfc

File tree

11 files changed

+100
-52
lines changed

11 files changed

+100
-52
lines changed

api/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ export * from './lib/index';
1010
const expressServer = express();
1111

1212
const createFunction = async (
13-
expressInstance: express.Express
13+
expressInstance: express.Express,
1414
): Promise<void> => {
1515
const app = await NestFactory.create(
1616
ApiModule,
1717
new ExpressAdapter(expressInstance),
1818
{
1919
cors: {
2020
origin: true,
21-
methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'],
21+
methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE', 'PATCH'],
2222
credentials: true,
2323
},
24-
}
24+
},
2525
);
2626
app.use(cookieParser());
2727
await app.init();

api/src/lib/user/user.controller.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,19 @@ export const EMAIL_REGEX =
2828
export class UserController {
2929
constructor(private userService: UserService) { }
3030

31-
@Get()
32-
async getUserInfo(
33-
@Param('username') username: string,
34-
@Req() request: Request,
35-
@Res() response: Response,
36-
): Promise<UserInfoResponse> {
37-
const user = await this.userService.findUserByUsername(username);
38-
39-
if (!user) {
40-
return { success: false, message: "Couldn't find the requested user" };
31+
@Get('info')
32+
async getUserInfo(@Req() request: Request): Promise<UserInfoResponse> {
33+
console.log(' 🚀 ~ user.controller.ts:33 → User info', request.user);
34+
if (!request.user) {
35+
return { success: false, message: 'Not logged in' };
4136
}
42-
43-
if (user.username !== request.user?.username) {
44-
response.status(401);
45-
return { success: false, message: "You cannot see this user's details" };
46-
}
47-
4837
return {
4938
success: true,
50-
message: 'User details retrieved',
39+
message: 'User info returned',
5140
user: {
52-
username: user.username,
53-
email: user.email,
54-
verified: user.verified,
41+
username: request.user.username,
42+
email: request.user.email,
43+
verified: request.user.verified,
5544
},
5645
};
5746
}

api/src/lib/user/user.module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ export class UserModule implements NestModule {
1616
configure(consumer: MiddlewareConsumer) {
1717
consumer.apply(AuthenticationMiddleware).forRoutes(
1818
{
19-
path: 'password',
19+
path: 'user/password',
2020
method: RequestMethod.PATCH,
2121
},
2222
{
23-
path: '',
23+
path: 'user/info',
2424
method: RequestMethod.GET,
2525
},
2626
);

api/src/lib/user/user.service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,13 @@ export class UserService implements OnModuleInit {
150150

151151
async checkCookie(secret: string): Promise<User | undefined> {
152152
if (!this.firebaseService) {
153+
console.error('  ~ user.service.ts:153 → No firebase service present');
153154
return undefined;
154155
}
155156

156157
const firestore = this.firebaseService.getFirestore();
157158
if (!firestore) {
159+
console.error('  ~ user.service.ts:153 → No firestore present');
158160
return undefined;
159161
}
160162

@@ -170,6 +172,10 @@ export class UserService implements OnModuleInit {
170172

171173
const cookie = query.docs[0].data() as Cookie;
172174
const user: User | undefined = (await cookie.userRef.get()).data() as User;
175+
console.log(
176+
' 🚀 ~ user.service.ts:175 → User associated with cookie: ',
177+
user,
178+
);
173179
if (!user.verified) {
174180
return undefined;
175181
}

app/src/app/app.component.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
22
import { TestBed, waitForAsync } from '@angular/core/testing';
33

44
import { AppComponent } from './app.component';
5-
import { NotificationService } from './notification.service';
65

76
describe('AppComponent', () => {
87
beforeEach(waitForAsync(() => {
98
TestBed.configureTestingModule({
10-
providers: [NotificationService],
119
declarations: [AppComponent],
1210
schemas: [CUSTOM_ELEMENTS_SCHEMA],
1311
}).compileComponents();

app/src/app/app.component.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import { Component } from '@angular/core';
2-
import { NotificationService } from './notification.service';
32

43
@Component({
54
selector: 'root',
65
templateUrl: 'app.component.html',
76
styleUrls: ['app.component.scss'],
87
})
98
export class AppComponent {
10-
constructor(private notificationService: NotificationService) {
11-
console.log(
12-
' 🚀 ~ app.component.ts:11 → Notification service',
13-
this.notificationService,
14-
);
15-
}
9+
constructor() { }
1610
}

app/src/app/app.module.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { AppRoutingModule } from './app-routing.module';
88
import { FormsModule } from '@angular/forms';
99
import { AuthModule } from './auth/auth.module';
1010
import { CommonModule } from '@angular/common';
11-
import { NotificationService } from './notification.service';
1211
import { StatusPageModule } from './status/status.module';
1312

1413
@NgModule({
@@ -23,10 +22,7 @@ import { StatusPageModule } from './status/status.module';
2322
AuthModule,
2423
IonicModule.forRoot(),
2524
],
26-
providers: [
27-
NotificationService,
28-
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
29-
],
25+
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
3026
bootstrap: [AppComponent],
3127
})
3228
export class AppModule { }

app/src/app/auth/auth.service.ts

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import {
44
HttpResponse,
55
} from '@angular/common/http';
66
import { Injectable } from '@angular/core';
7-
import { ApiResponse } from '@gatekeeper/api';
8-
import { Observable, catchError, map } from 'rxjs';
7+
import { ApiResponse, UserInfoResponse } from '@gatekeeper/api';
8+
import { Observable, catchError, map, of } from 'rxjs';
99
import { environment } from '../../environments/environment';
1010

1111
@Injectable()
@@ -14,13 +14,65 @@ export class AuthService {
1414
private currentUser?: string;
1515
constructor(private http: HttpClient) {
1616
this.loggedIn = true;
17+
this.http
18+
.get<UserInfoResponse>(`${environment.apiUrl}/user/info`, {
19+
withCredentials: true,
20+
observe: 'response',
21+
})
22+
.pipe(
23+
catchError((_err: HttpErrorResponse) => {
24+
this.loggedIn = false;
25+
return of(undefined);
26+
}),
27+
)
28+
.subscribe((data) => {
29+
if (data?.body?.success) {
30+
this.loggedIn = true;
31+
this.currentUser = data.body.user?.username;
32+
}
33+
});
1734
}
1835

1936
isLoggedIn(): boolean {
2037
return this.loggedIn;
2138
}
2239

40+
getUserInfo(): Observable<UserInfoResponse> {
41+
return this.http
42+
.get<UserInfoResponse>(`${environment.apiUrl}/user/info`, {
43+
withCredentials: true,
44+
observe: 'response',
45+
})
46+
.pipe(
47+
catchError((_err: HttpErrorResponse) => {
48+
return of(undefined);
49+
}),
50+
map((data) => {
51+
return data?.body || { success: false, message: 'Not logged in' };
52+
}),
53+
);
54+
}
55+
2356
getCurrentUser(): string | undefined {
57+
if (!this.currentUser) {
58+
this.http
59+
.get<UserInfoResponse>(`${environment.apiUrl}/user/info`, {
60+
withCredentials: true,
61+
observe: 'response',
62+
})
63+
.pipe(
64+
catchError((_err: HttpErrorResponse) => {
65+
this.loggedIn = false;
66+
return of(undefined);
67+
}),
68+
)
69+
.subscribe((data) => {
70+
if (data?.body?.success) {
71+
this.loggedIn = true;
72+
this.currentUser = data.body.user?.username;
73+
}
74+
});
75+
}
2476
return this.currentUser;
2577
}
2678

@@ -70,10 +122,10 @@ export class AuthService {
70122
email: string,
71123
password: string,
72124
): Observable<ApiResponse> {
73-
return this.http.post<ApiResponse>(
74-
`${environment.apiUrl}/user`,
75-
{ username, email, password },
76-
{ withCredentials: true },
77-
);
125+
return this.http.post<ApiResponse>(`${environment.apiUrl}/user`, {
126+
username,
127+
email,
128+
password,
129+
});
78130
}
79131
}

app/src/app/profile/changePassword/change-password.component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export class ChangePasswordComponent {
1717
currentPassword: string;
1818
newPassword: string;
1919
confirm: string;
20-
toastMessage: string = '';
21-
isToastOpen: boolean = false;
20+
toastMessage: string;
21+
isToastOpen: boolean;
2222

2323
constructor(
2424
private profileService: ProfileService,
@@ -28,6 +28,8 @@ export class ChangePasswordComponent {
2828
this.currentPassword = '';
2929
this.newPassword = '';
3030
this.confirm = '';
31+
this.toastMessage = '';
32+
this.isToastOpen = false;
3133
}
3234

3335
currentPasswordChange(event: Event) {

app/src/app/profile/profile.component.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { ProfilePageComponent } from './profile.component';
33
import { ProfileService } from './profile.service';
44
import { AuthService } from '../auth/auth.service';
55
import { IonicModule } from '@ionic/angular';
6+
import { HttpClientModule } from '@angular/common/http';
67

78
describe('ProfilePageComponent', () => {
89
beforeEach(waitForAsync(() => {
910
TestBed.configureTestingModule({
10-
imports: [IonicModule],
11+
imports: [IonicModule, HttpClientModule],
1112
declarations: [ProfilePageComponent],
1213
providers: [ProfileService, AuthService],
1314
}).compileComponents();

app/src/app/profile/profile.component.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1-
import { Component } from '@angular/core';
1+
import { Component, OnInit } from '@angular/core';
22
import { AuthService } from '../auth/auth.service';
33

44
@Component({
55
selector: 'profile-page',
66
templateUrl: 'profile.component.html',
77
styleUrls: ['profile.component.scss'],
88
})
9-
export class ProfilePageComponent {
9+
export class ProfilePageComponent implements OnInit {
1010
isModalOpen: boolean;
1111
username: string;
1212

1313
constructor(private authService: AuthService) {
1414
this.isModalOpen = false;
15-
this.username = this.authService.getCurrentUser() || 'Not logged in';
15+
this.username = 'Not logged in';
16+
}
17+
18+
ngOnInit() {
19+
this.authService.getUserInfo().subscribe((data) => {
20+
if (data.success) {
21+
this.username = data.user?.username || 'Not logged in';
22+
} else {
23+
console.log('Failed to query user profile');
24+
}
25+
});
1626
}
1727

1828
setModalOpen(state: boolean) {

0 commit comments

Comments
 (0)