Skip to content

Commit

Permalink
feat(service): added user and admin services
Browse files Browse the repository at this point in the history
* add auth guard and fix login

* add auth guard and fix login

* feat(auth-service): fetch permissions

* fix(login): fix bug in login and permissions

* fix(login): fix bug in auth guard

* feat(service): add user service - not completed

* feat(admin-service): add services for manage users

* fix(service): fix some missed imports

* fix(test): fix bug in test
  • Loading branch information
asAlwaysZahra authored Aug 20, 2024
1 parent 9d267b2 commit eb30611
Show file tree
Hide file tree
Showing 13 changed files with 266 additions and 28 deletions.
2 changes: 2 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { LoginComponent } from './user/components/login/login.component';
import { DashboardComponent } from './user/components/dashboard/dashboard.component';
import { MainPageComponent } from './user/components/dashboard/main-page/main-page.component';
import { ManageAccountComponent } from './user/components/dashboard/manage-account/manage-account.component';
import { AuthGuard } from './user/guards/auth.guard';
import { DataAnalysisComponent } from './graph/data-analysis/data-analysis.component';
import { ManageUsersComponent } from './user/components/dashboard/manage-users/manage-users.component';

Expand All @@ -13,6 +14,7 @@ const routes: Routes = [
path: 'dashboard',
component: DashboardComponent,
title: 'StarData | Dashboard',
canActivate: [AuthGuard],
children: [
{
path: '',
Expand Down
4 changes: 2 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { AppComponent } from './app.component';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { UserModule } from './user/user.module';
import { SharedModule } from './shared/shared.module';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { GraphModule } from './graph/graph.module';

@NgModule({
Expand All @@ -17,7 +17,7 @@ import { GraphModule } from './graph/graph.module';
SharedModule,
GraphModule,
],
providers: [provideAnimationsAsync(), provideHttpClient()],
providers: [provideAnimationsAsync(), provideHttpClient(withFetch())],
bootstrap: [AppComponent],
})
export class AppModule {}
15 changes: 12 additions & 3 deletions src/app/user/components/login/login.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<h2 class="logo-text">StarData</h2>
</div>
<h2>Login</h2>
<form (ngSubmit)="onSubmit()">
<form>
<mat-form-field appearance="fill" class="form-field">
<mat-label>Username</mat-label>
<input [(ngModel)]="username" matInput name="userName" />
Expand All @@ -33,8 +33,17 @@ <h2>Login</h2>
<mat-checkbox [(ngModel)]="checked" name="rememberMe"
>Remember me</mat-checkbox
>
<button type="submit" mat-flat-button [disabled]="isLoading">
@if(isLoading){ Logging in... }@else { Login }
<button
type="submit"
mat-flat-button
[disabled]="isLoading"
(click)="loginClick()"
>
@if (isLoading) {
Logging in...
} @else {
Login
}
</button>
<p class="forget">
<span>Forget password?</span>
Expand Down
9 changes: 5 additions & 4 deletions src/app/user/components/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
} from '@angular/core';
import { Data, DataSet, Edge, Network, Node, Options } from 'vis';
import { AuthService } from '../../services/auth/auth.service';
import { LoginRequest } from '../../services/auth/auth.model';
import { Router } from '@angular/router';
import { LoginRequest } from '../../models/User';
import { ThemeService } from '../../../shared/services/theme.service';

@Component({
Expand Down Expand Up @@ -48,7 +48,7 @@ export class LoginComponent implements AfterViewInit {
});
}

onSubmit() {
loginClick() {
this.isLoading = true;
const loginRequest: LoginRequest = {
username: this.username,
Expand All @@ -57,11 +57,12 @@ export class LoginComponent implements AfterViewInit {
};
this.authService.login(loginRequest).subscribe({
next: () => {
this.isLoading = false;
this.router.navigate(['/dashboard']);
},
error: () => {
error: (error) => {
this.isLoading = false;
console.log('error');
console.error('Login failed', error);
},
});
}
Expand Down
17 changes: 17 additions & 0 deletions src/app/user/guards/auth.guard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TestBed } from '@angular/core/testing';
import { CanActivateFn } from '@angular/router';

import { authGuard } from './auth.guard';

describe('authGuard', () => {
const executeGuard: CanActivateFn = (...guardParameters) =>
TestBed.runInInjectionContext(() => authGuard(...guardParameters));

beforeEach(() => {
TestBed.configureTestingModule({});
});

it('should be created', () => {
expect(executeGuard).toBeTruthy();
});
});
46 changes: 46 additions & 0 deletions src/app/user/guards/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateFn, Router } from '@angular/router';
import { catchError, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthService } from '../services/auth/auth.service';

export const authGuard: CanActivateFn = (route, state) => {
if (route && state) return true;
return true;
};

@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router,
) {}

canActivate(): Observable<boolean> {
return this.authService.getPermissions().pipe(
map((permissions) => {
if (permissions.permission !== '') {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}),
catchError(() => {
this.router.navigate(['/login']);
return [false];
}),
);
// return this.authService.isLoggedIn$.pipe(
// map((isLoggedIn) => {
// if (!isLoggedIn) {
// this.router.navigate(['/login']);
// return false;
// }
// return true;
// }),
// );
}
}
55 changes: 55 additions & 0 deletions src/app/user/models/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export interface User {
firstName: string;
lastName: string;
imageURL: string;
}

export interface LoginRequest {
username: string;
password: string;
rememberMe: boolean;
}

export interface LoginResponse {
firstName: string;
lastName: string;
imageURL: string | null;
}

export interface UserPermissions {
username: string;
firstName: string;
lastName: string;
permission: string;
}

export interface RegisterRequest {
username: string;
password: string;
confirmPassword: string;
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
roleName: string;
}

export interface RegisterResponse {
username: string;
password: string;
confirmPassword: string;
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
roleName: string;
}

export interface UpdateUserRequest {
username: string;
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
roleName: string;
}
16 changes: 16 additions & 0 deletions src/app/user/services/admin/admin.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { AdminService } from './admin.service';

describe('AdminService', () => {
let service: AdminService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AdminService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
34 changes: 34 additions & 0 deletions src/app/user/services/admin/admin.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { RegisterRequest, UpdateUserRequest } from '../../models/User';

@Injectable({
providedIn: 'root',
})
export class AdminService {
private apiUrl = 'https://localhost:44322/api/Admin';

constructor(private http: HttpClient) {}

createUser(request: RegisterRequest) {
return this.http.post(`${this.apiUrl}/register`, request);
}

getUsers(limit = 10, page = 1) {
return this.http.get(
`${this.apiUrl}/GetUsersPagination?limit=${limit}&page=${page}`,
);
}

deleteUser(id: string) {
return this.http.delete(`${this.apiUrl}/DeleteUser?id=${id}`);
}

updateUser(id: string, request: UpdateUserRequest) {
return this.http.put(`${this.apiUrl}/UpdateUser?id=${id}`, request);
}

firstAdmin() {
return this.http.get(`${this.apiUrl}/firstAdmin`);
}
}
12 changes: 0 additions & 12 deletions src/app/user/services/auth/auth.model.ts

This file was deleted.

35 changes: 28 additions & 7 deletions src/app/user/services/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, Subject, tap } from 'rxjs';
import { LoginRequest, LoginResponse } from './auth.model';
import {
LoginRequest,
LoginResponse,
UserPermissions,
} from '../../models/User';

@Injectable({
providedIn: 'root',
})
export class AuthService {
private apiUrl = 'http://localhost:5000/api/User';
private apiUrl = 'https://localhost:44322/api/User';

private userData = new Subject<unknown>();
private userData = new Subject<LoginResponse>();
private isLoggedIn = new BehaviorSubject<boolean>(false);
private permissions = new Subject<UserPermissions>();

isLoggedIn$ = this.isLoggedIn.asObservable();
userData$ = this.userData.asObservable();
permissions$ = this.permissions.asObservable();

constructor(private http: HttpClient) {}

login(loginRequest: LoginRequest): Observable<LoginResponse> {
return this.http
.post<LoginResponse>(this.apiUrl + '/login', loginRequest)
.post<LoginResponse>(this.apiUrl + '/login', loginRequest, {
withCredentials: true,
})
.pipe(
tap((response) => {
this.userData.next(response);
this.isLoggedIn.next(true);
})
}),
);
}

getUserData() {
// return this.userData$;
getPermissions() {
return this.http
.get<UserPermissions>(this.apiUrl + '/permissions', {
withCredentials: true,
})
.pipe(
tap((response) => {
if (response.username == null) this.isLoggedIn.next(false);
else {
this.isLoggedIn.next(true);
this.permissions.next(response);
console.log(response);
}
}),
);
}
}
16 changes: 16 additions & 0 deletions src/app/user/services/user/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { UserService } from './user.service';

describe('UserService', () => {
let service: UserService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UserService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
33 changes: 33 additions & 0 deletions src/app/user/services/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
providedIn: 'root',
})
export class UserService {
private apiUrl = 'https://localhost:44322/api/User';

constructor(private http: HttpClient) {}

// getUsers(): Observable<User[]> {
// return this.http.get<User[]>(`${this.apiUrl}`, { withCredentials: true });
// }
//
// getUserById(id: number): Observable<User> {
// return this.http.get<User>(`${this.apiUrl}/${id}`, {
// withCredentials: true,
// });
// }
//
// updateUser(id: number, user: User): Observable<User> {
// return this.http.put<User>(`${this.apiUrl}/${id}`, user, {
// withCredentials: true,
// });
// }
//
// deleteUser(id: number): Observable<void> {
// return this.http.delete<void>(`${this.apiUrl}/${id}`, {
// withCredentials: true,
// });
// }
}

0 comments on commit eb30611

Please sign in to comment.