diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 7c45da00f72626aa25250a412ee63294fad344ad..956e36935086cc699d93be09575e136358f1ad62 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -1,13 +1,12 @@ <div class="navbar"> - <a class="logo" href="/">SELLPOINT</a> + <span class="logo" (click)="navigate('/')">SellPoint</span> <nav> - <a href="/">/</a> - <a href="/annonse">/annonse</a> - <a href="/annonse/ny">/annonse/ny</a> - <a href="/register">/register</a> - <a href="/login">/login</a> - <a href="/profile">/profile</a> - <a href="/logout">/logout</a> + <span (click)="navigate('/annonse')">Annonser</span> + <span (click)="navigate('/annonse/ny')">Lag annonse</span> + <span *ngIf="!user.getUserId" (click)="navigate('/register')">Registrer</span> + <span *ngIf="!user.getUserId" (click)="navigate('/login')">Logg inn</span> + <span *ngIf="user.getUserId" (click)="navigate('/profile')">Profil</span> + <span *ngIf="user.getUserId" (click)="logout()">Logg ut</span> </nav> </div> <div class="splash"> @@ -23,11 +22,10 @@ <h2>Lorem Ipsum</h2> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <div class="buttons"> - <a href="/register" class="btn">Register deg!</a> - <a href="javascript:void(0)" class="btn pink">Les mer</a> + <button (click)="navigate('/register')" class="btn">Registrer deg!</button> + <button (click)="navigate('/')" class="btn pink">Les mer</button> </div> </div> - </div> </div> diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss index 882c3fe9814051f453e801534144489b8abfcf6e..56ae8a30bdf418842d49d6276d871a9fc32043e5 100644 --- a/client/src/app/app.component.scss +++ b/client/src/app/app.component.scss @@ -1,21 +1,26 @@ div.navbar { - background-color: #666; + background-color: #fff; display: flex; justify-content: space-between; align-items: center; - height: 70px; + height: 62px; + font-family: 'Josefin Sans', sans-serif; + padding-top: 8px; - a.logo { + span.logo { padding: 10px; - background-color: white; width: 200px; margin-left: 10px; + font-size: 40px; + font-weight: bold; + cursor: pointer; } nav { - a{ + span{ padding: 10px; margin: 10px; - background-color: white; + cursor: pointer; + font-size: 25px; } } } @@ -31,13 +36,10 @@ div.splash { overflow: hidden; color: #ffffff; font-family: 'Inter', sans-serif; - a { + button { color: #ffffff; text-decoration: none; } - a:visited { - color: #ffffff; - } div { position: relative; } @@ -80,7 +82,7 @@ div.splash { text-align: center; justify-content: flex-end; } - a.btn { + button.btn { background: #13D05E; width: 200px; margin: 10px 0 10px 10px; @@ -88,8 +90,10 @@ div.splash { box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 4px 4px rgba(0, 0, 0, 0.25); font-family: 'Josefin Sans', sans-serif; font-size: 20px; + border: none; + cursor: pointer; } - a.pink { + button.pink { background: #FFA1A1; } diff --git a/client/src/app/app.component.spec.ts b/client/src/app/app.component.spec.ts index b4db530463749df9f01471a6a79affc07d6d7532..31481afd669b0a973ef45ad0a85216c686f26ab7 100644 --- a/client/src/app/app.component.spec.ts +++ b/client/src/app/app.component.spec.ts @@ -1,3 +1,4 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { AppComponent } from './app.component'; @@ -6,7 +7,8 @@ describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ - RouterTestingModule + RouterTestingModule, + HttpClientTestingModule ], declarations: [ AppComponent diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index cc061ccd82009ac4a6add0a0df0b8e701e1c8d42..df5c4fffee878f9140253eb60a68f9767651399d 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,10 +1,33 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { Subscription } from 'rxjs'; +import { AuthService } from './authentication/auth.service'; +import { User } from './models/user.model'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent { +export class AppComponent implements OnInit { title: string = 'client'; + user: User; + userSubscription: Subscription; + + constructor(private authService: AuthService, private router: Router){} + + ngOnInit() { + this.user = this.authService.getCurrentUser(false); + this.userSubscription = this.authService.userObservable.subscribe(user => { + this.user = user; + }); + } + + navigate(url) { + this.router.navigateByUrl(url); + } + + logout() { + this.authService.logout(); + } } diff --git a/client/src/app/authentication/auth.module.ts b/client/src/app/authentication/auth.module.ts index d2e4fae6f86c813833e6f24066c50b4076a0d599..65c0542d9e9769feb7f03bde0ffe940dc89599ab 100644 --- a/client/src/app/authentication/auth.module.ts +++ b/client/src/app/authentication/auth.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { SharedModule } from '../shared/shared.module'; diff --git a/client/src/app/authentication/auth.service.ts b/client/src/app/authentication/auth.service.ts index cab69f3b5dea1554e09e0501f3922d7a09356a23..bdc964aad92b6d4e7de8f3fd95ad7bca753e347e 100644 --- a/client/src/app/authentication/auth.service.ts +++ b/client/src/app/authentication/auth.service.ts @@ -1,8 +1,10 @@ -import { HttpClient, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { User } from '../models/user.model'; import { tap, shareReplay } from 'rxjs/operators'; import { Router } from '@angular/router'; +import { UserService } from '../users/user.service'; +import { Subject } from 'rxjs'; interface IUserLogin { username: string; @@ -16,7 +18,21 @@ export class AuthService { loginUrl = "api/auth/login"; registrationUrl = "api/auth/register"; - constructor(private http: HttpClient, private router: Router) { } + userObservable: Subject<User> = new Subject<User>(); + + constructor(private http: HttpClient, private router: Router, private userService: UserService) { } + + getCurrentUser(route=true): User{ + // Check for token expiration + if (this.checkTokenExpiration(route)) { // redirects to "/" if token is expired + // Get user data from JWT token + const token = localStorage.getItem('token'); + const user_data = JSON.parse(atob(token.split(".")[1])).data[0]; + + return new User(user_data); + } + return new User(); + } /** * Logins an user, if given correct combination of username and password. @@ -41,19 +57,21 @@ export class AuthService { private login_user(body: IUserLogin) { // Pipes output to setSession function if a valid user is returned return this.http.post(this.loginUrl, body).pipe( - tap(res =>this.setSession(res)), - shareReplay()); + tap(res =>this.setSession(res)), + shareReplay() + ); } + // Set authentication token on localStorage if a valid user is received private setSession(authResult) { - console.log(authResult); localStorage.setItem('token', authResult.token); + this.userObservable.next(this.getCurrentUser()); } /** * Checks validity of token, redirects to homepage and removes it if it is expired */ - checkTokenExpiration() { + checkTokenExpiration(route) { const token = localStorage.getItem("token"); if (token) { const {iat, exp} = JSON.parse(atob(token?.split(".")[1])); @@ -64,26 +82,31 @@ export class AuthService { // Expired token if (now < issued || now >= expires) { this.logout(); - this.router.navigateByUrl("/"); + if (route) { + this.router.navigate(["/login"], {replaceUrl: true}); + } return false } return true; } } - this.router.navigateByUrl("/") + if (route) { + this.router.navigate(["/login"], {replaceUrl: true}); + } return false } /** - * Logout an user and redirects to the homepage + * Logout a user and redirects to the homepage */ logout() { localStorage.removeItem("token"); - this.router.navigateByUrl("/") + this.router.navigateByUrl("/"); + this.userObservable.next(new User()); } /** - * Register an user, if not duplicate, add to database. + * Register a user, if not duplicate, add to database. */ registerUser(user: User): Promise<string> { return new Promise<string>( diff --git a/client/src/app/models/post.model.ts b/client/src/app/models/post.model.ts index fcf5e849bd889d4fa77683b0569df936e20a88bd..7678903ebbae78fe5386c16add316bf655191fc5 100644 --- a/client/src/app/models/post.model.ts +++ b/client/src/app/models/post.model.ts @@ -6,7 +6,7 @@ export class Post implements Deserializable, Serializable { private title: string; private description: string; private timestamp: Date; - private owner: string; + private owner: number; private imageUrl: string; private price: number; private categoryid: number; @@ -83,7 +83,7 @@ export class Post implements Deserializable, Serializable { return this.owner; } - set setOwner(owner: string) { + set setOwner(owner: number) { this.owner = owner; } diff --git a/client/src/app/models/user.model.ts b/client/src/app/models/user.model.ts index 8bfe6639f25fa844f4ddaa3a1c504709421543b0..e4990d6ae007c9087ecd3eb4186eb3e9390c8267 100644 --- a/client/src/app/models/user.model.ts +++ b/client/src/app/models/user.model.ts @@ -22,7 +22,6 @@ export class User implements Deserializable, Serializable { deserialize(input: Object): this { Object.assign(this, input); - console.log(this); return this; } diff --git a/client/src/app/posts/post-details/post-details.component.html b/client/src/app/posts/post-details/post-details.component.html index ba284316a22ead9b04fbb999c8110b21f67c13aa..40857f7ce3a7ee7184384d6e93767369b387b482 100644 --- a/client/src/app/posts/post-details/post-details.component.html +++ b/client/src/app/posts/post-details/post-details.component.html @@ -7,5 +7,7 @@ <p>Publisert: {{post.getTimestamp}}</p> <p>Eier: {{post.getOwner}}</p> -<app-button text="Rediger annonse" (click)="editPost()"></app-button> -<app-button text="Slett annonse" (click)="deletePost()"></app-button> +<div *ngIf="userId == post.getOwner"> + <app-button text="Rediger annonse" (click)="editPost()"></app-button> + <app-button text="Slett annonse" (click)="deletePost()"></app-button> +</div> diff --git a/client/src/app/posts/post-details/post-details.component.spec.ts b/client/src/app/posts/post-details/post-details.component.spec.ts index dd08767ab534fe61aad83da494d6cfd33f4e6b32..a2ab8bf1d8b402dab5886a209ca5bd2721619df2 100644 --- a/client/src/app/posts/post-details/post-details.component.spec.ts +++ b/client/src/app/posts/post-details/post-details.component.spec.ts @@ -2,7 +2,9 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { AuthService } from 'src/app/authentication/auth.service'; import { Post } from 'src/app/models/post.model'; +import { User } from 'src/app/models/user.model'; import { SharedModule } from 'src/app/shared/shared.module'; import { PostListComponent } from '../post-list/post-list.component'; import { PostService } from '../post.service'; @@ -12,9 +14,19 @@ import { PostDetailsComponent } from './post-details.component'; describe('PostDetailsComponent', () => { let component: PostDetailsComponent; let fixture: ComponentFixture<PostDetailsComponent>; - let mockPostService; + let mockPostService, mockAuthService; beforeEach(async () => { + // AuthService mock setup + mockAuthService = jasmine.createSpyObj(['getCurrentUser']); + mockAuthService.getCurrentUser.and.returnValue(new User({ + userId: 4, + username: "tester", + email: "test@test.com", + password: "1234", + create_time: 513498 + })); + // PostService mock setup mockPostService = jasmine.createSpyObj(['getPost', 'deletePost']); mockPostService.getPost.and.returnValue( @@ -25,7 +37,7 @@ describe('PostDetailsComponent', () => { title: "Test", description: "TestDescription", timestamp: 23947298, - owner: "user", + owner: 4, imageUrl: null, price: 49, categoryid: 2 @@ -50,7 +62,8 @@ describe('PostDetailsComponent', () => { ], providers: [ { provide: ActivatedRoute, useValue: { snapshot: {params: {id: 5}}}}, - { provide: PostService, useValue: mockPostService } + { provide: PostService, useValue: mockPostService }, + { provide: AuthService, useValue: mockAuthService } ] }) .compileComponents(); @@ -68,30 +81,32 @@ describe('PostDetailsComponent', () => { it('should get post with id from url parameter', async () => { // Waits for ngOnInit and checks that we get post - expect(component.post).not.toBeNull(); + await fixture.whenStable(); + expect(mockPostService.getPost).toHaveBeenCalledWith(5); + expect(component.post).toEqual(new Post({ + id: 5, + title: "Test", + description: "TestDescription", + timestamp: 23947298, + owner: 4, + imageUrl: null, + price: 49, + categoryid: 2 + })); + }); - fixture.whenStable().then(() => { - expect(mockPostService.getPost).toHaveBeenCalledWith(5); - expect(component.post).toEqual(new Post({ - id: 5, - title: "Test", - description: "TestDescription", - timestamp: 23947298, - owner: "user", - imageUrl: null, - price: 49, - categoryid: 2 - })); - }); + it('should get current user', async () => { + // Waits for ngOnInit and checks that we get post + await fixture.whenStable(); + + expect(mockAuthService.getCurrentUser).toHaveBeenCalledWith(false); + expect(component.userId).toBe(4); }); it('should delete post with id', async () => { // Waits for ngOnInit and checks that we can delete post - expect(component.post).not.toBeNull(); - - fixture.whenStable().then(() => { - component.deletePost(); - expect(mockPostService.deletePost).toHaveBeenCalledWith(5); - }); + await fixture.whenStable(); + component.deletePost(); + expect(mockPostService.deletePost).toHaveBeenCalledWith(5); }); }); diff --git a/client/src/app/posts/post-details/post-details.component.ts b/client/src/app/posts/post-details/post-details.component.ts index 3de9e4d32cfdba4092e59ac8427030c074166eca..efa7fbe43e87f10d721028749c5cd7d78f142194 100644 --- a/client/src/app/posts/post-details/post-details.component.ts +++ b/client/src/app/posts/post-details/post-details.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Post } from 'src/app/models/post.model'; import { PostService } from '../post.service'; import { ActivatedRoute, Router } from '@angular/router' +import { AuthService } from 'src/app/authentication/auth.service'; @Component({ selector: 'app-post-details', @@ -11,10 +12,14 @@ import { ActivatedRoute, Router } from '@angular/router' export class PostDetailsComponent implements OnInit { post: Post = new Post(); + userId: number = 0; - constructor(private postService: PostService, private activatedRoute: ActivatedRoute, private router: Router) { } + constructor(private postService: PostService, private activatedRoute: ActivatedRoute, private router: Router, private authService: AuthService) { } ngOnInit(): void { + // Gets ID from current user + this.userId = this.authService.getCurrentUser(false).getUserId; + // Gets id parameter from URL const id = this.activatedRoute.snapshot.params["id"]; @@ -25,6 +30,7 @@ export class PostDetailsComponent implements OnInit { console.log(error); }); } + /** * Moves to edit page */ @@ -36,11 +42,14 @@ export class PostDetailsComponent implements OnInit { * Deletes post in database and navigates to post list */ deletePost() { - this.postService.deletePost(this.post.getId).then(data => { - console.log("Successfully deleted post: " + this.post.getId); - this.router.navigateByUrl("/annonse"); - }).catch(error => { - console.log(error); - }); + // Check if we are the owner of the post + if (this.userId == this.post.getOwner) { + this.postService.deletePost(this.post.getId).then(data => { + console.log("Successfully deleted post: " + this.post.getId); + this.router.navigateByUrl("/annonse"); + }).catch(error => { + console.log(error); + }); + } } } diff --git a/client/src/app/posts/post-form/post-form.component.spec.ts b/client/src/app/posts/post-form/post-form.component.spec.ts index b16d0c1d0f8cf6a09db3e50c254b9fac775f73d3..adfab335d54f814cd3a1609288effaa2c22d1f0f 100644 --- a/client/src/app/posts/post-form/post-form.component.spec.ts +++ b/client/src/app/posts/post-form/post-form.component.spec.ts @@ -3,8 +3,11 @@ import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { AuthService } from 'src/app/authentication/auth.service'; import { Category } from 'src/app/models/category.model'; +import { User } from 'src/app/models/user.model'; import { SharedModule } from 'src/app/shared/shared.module'; +import { UserLoginFormComponent } from 'src/app/users/user-login-form/user-login-form.component'; import { PostListComponent } from '../post-list/post-list.component'; import { PostService } from '../post.service'; @@ -14,9 +17,19 @@ describe('PostFormComponent', () => { let component: PostFormComponent; let fixture: ComponentFixture<PostFormComponent>; let router: Router; - let mockPostService; + let mockPostService, mockAuthService; beforeEach(async () => { + // AuthService mock setup + mockAuthService = jasmine.createSpyObj(['getCurrentUser']); + mockAuthService.getCurrentUser.and.returnValue(new User({ + userId: 4, + username: "tester", + email: "test@test.com", + password: "1234", + create_time: 513498 + })); + // PostService mock setup mockPostService = jasmine.createSpyObj(['getAllCategories', 'addPost', 'deletePost']); mockPostService.getAllCategories.and.returnValue( @@ -45,10 +58,14 @@ describe('PostFormComponent', () => { FormsModule, SharedModule, RouterTestingModule.withRoutes([ - { path: 'annonse', component: PostListComponent} + { path: 'annonse', component: PostListComponent}, + { path: 'login', component: UserLoginFormComponent} ]) ], - providers: [ { provide: PostService, useValue: mockPostService } ] + providers: [ + { provide: PostService, useValue: mockPostService }, + { provide: AuthService, useValue: mockAuthService } + ] }) .compileComponents(); }); @@ -61,16 +78,20 @@ describe('PostFormComponent', () => { router = TestBed.inject(Router); }); - it('should create and get all categories', async () => { - expect(component).toBeTruthy(); + it('should get current user', async () => { + // Waits for ngOnInit and checks that we get categories + await fixture.whenStable(); + expect(mockAuthService.getCurrentUser).toHaveBeenCalled(); + expect(component.currentUser.getUserId).toBe(4); + }); + it('should get all categories', async () => { // Waits for ngOnInit and checks that we get categories - fixture.whenStable().then(() => { - expect(mockPostService.getAllCategories).toHaveBeenCalled(); - expect(component.categories.length).toBe(2); - expect(component.categories[0].getCategoryId).toBe(1); - expect(component.categories[1].getName).toBe("Bil"); - }); + await fixture.whenStable(); + expect(mockPostService.getAllCategories).toHaveBeenCalled(); + expect(component.categories.length).toBe(2); + expect(component.categories[0].getCategoryId).toBe(1); + expect(component.categories[1].getName).toBe("Bil"); }); it('should validate form', () => { @@ -126,21 +147,17 @@ describe('PostFormComponent', () => { it('should delete post with id', async () => { component.id = 5; - expect(component.id).toBe(5); // Waits for ngOnInit and checks that we can delete post - fixture.whenStable().then(() => { - component.deletePost(); - expect(mockPostService.deletePost).toHaveBeenCalledWith(5); - }); + await fixture.whenStable(); + component.deletePost(); + expect(mockPostService.deletePost).toHaveBeenCalledWith(5); }); it('should not delete new post', async () => { // Waits for ngOnInit and checks that we can delete post - expect(component.id).toBe(0); - fixture.whenStable().then(() => { - component.deletePost(); - expect(mockPostService.deletePost).not.toHaveBeenCalledWith(5); - }); + await fixture.whenStable(); + component.deletePost(); + expect(mockPostService.deletePost).not.toHaveBeenCalledWith(5); }); }); diff --git a/client/src/app/posts/post-form/post-form.component.ts b/client/src/app/posts/post-form/post-form.component.ts index 4fcf05a15115a372616c5ebe720264b1ff6620b7..3baa3d0e0cb95ef4fe185ac2b0b26ae456f0ee83 100644 --- a/client/src/app/posts/post-form/post-form.component.ts +++ b/client/src/app/posts/post-form/post-form.component.ts @@ -1,7 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; +import { AuthService } from 'src/app/authentication/auth.service'; import { Category } from 'src/app/models/category.model'; import { Post } from 'src/app/models/post.model'; +import { User } from 'src/app/models/user.model'; import { PostService } from '../post.service'; @Component({ @@ -24,9 +26,17 @@ export class PostFormComponent implements OnInit { categories: Array<Category>; - constructor(private postService: PostService, private router: Router, private activatedRoute: ActivatedRoute) { } + currentUser: User; + + constructor(private postService: PostService, private router: Router, private activatedRoute: ActivatedRoute, private authService: AuthService) { } ngOnInit() { + this.currentUser = this.authService.getCurrentUser(); + + if (!this.currentUser) { + this.router.navigate(["/login"], {replaceUrl: true}); + } + const id = this.activatedRoute.snapshot.params["id"]; if (id) { this.id = id; @@ -39,6 +49,10 @@ export class PostFormComponent implements OnInit { this.categoryid = post.getCategory; this.imageUrl = post.getImageUrl; + if (post.getOwner != this.currentUser.getUserId) { + this.router.navigateByUrl("/"); + } + this.showImage(this.imageUrl); }).catch(error => { console.log(error); @@ -49,7 +63,7 @@ export class PostFormComponent implements OnInit { this.postService.getAllCategories().then(categories => { this.categories = categories; }).catch (error => { - console.log("Error adding catrgories:" + error); + console.log("Error adding categories:" + error); }); } @@ -91,7 +105,7 @@ export class PostFormComponent implements OnInit { title: this.title, description: this.description, timestamp: new Date(), - owner: "admin", + owner: this.currentUser.getUserId, imageUrl: this.imageUrl, price: this.price, categoryid: this.categoryid diff --git a/client/src/app/posts/post-thumbnail/post-thumbnail.component.html b/client/src/app/posts/post-thumbnail/post-thumbnail.component.html index 5dc53d6c2b01a049a1cc19fcadd92df48e20c2fa..a2998dfba1f55fc3a3c7e8b8e7a295169e00943a 100644 --- a/client/src/app/posts/post-thumbnail/post-thumbnail.component.html +++ b/client/src/app/posts/post-thumbnail/post-thumbnail.component.html @@ -1,3 +1,3 @@ <div class="postthumb"> - <a href="javascript:void(0)"(click)="goToPost()">{{post.getTitle}}</a> + <a href="javascript:void(0)" (click)="goToPost()">{{post.getTitle}}</a> </div> diff --git a/client/src/app/shared/password-input/password-input.component.spec.ts b/client/src/app/shared/password-input/password-input.component.spec.ts index e1a583ebf97f377951e4c45c6a18ffa72574a073..14edd4419af19cd4ffc03d0edc00d4a547cb04d7 100644 --- a/client/src/app/shared/password-input/password-input.component.spec.ts +++ b/client/src/app/shared/password-input/password-input.component.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; +import { SharedModule } from '../shared.module'; import { PasswordInputComponent } from './password-input.component'; @@ -10,7 +11,7 @@ describe('PasswordInputComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ PasswordInputComponent ], - imports: [ FormsModule ] + imports: [ SharedModule, FormsModule ] }) .compileComponents(); }); diff --git a/client/src/app/users/user-login-form/user-login-form.component.ts b/client/src/app/users/user-login-form/user-login-form.component.ts index 3f4cefddfdbaf340b8a983de899ed4a6b96b50cf..d1ea4fb98b19aff787cb9ce037e593b2a0a161c3 100644 --- a/client/src/app/users/user-login-form/user-login-form.component.ts +++ b/client/src/app/users/user-login-form/user-login-form.component.ts @@ -18,6 +18,9 @@ export class UserLoginFormComponent implements OnInit { constructor(private userService: UserService, private authService: AuthService, private router: Router) { } ngOnInit(): void { + if (this.authService.getCurrentUser(false).getUserId) { + this.router.navigate(["/"], {replaceUrl: true}); + } } /** @@ -49,7 +52,6 @@ export class UserLoginFormComponent implements OnInit { // Logins the user this.authService.login(request).then(status => { - console.log("User login1: " + JSON.stringify(status)); this.router.navigateByUrl("/"); }).catch(error => { console.log("Error user login: " + error); diff --git a/client/src/app/users/user-logout/user-logout.component.html b/client/src/app/users/user-logout/user-logout.component.html deleted file mode 100644 index c19d0971c67a067b2253f0a76550669e5c4311ec..0000000000000000000000000000000000000000 --- a/client/src/app/users/user-logout/user-logout.component.html +++ /dev/null @@ -1 +0,0 @@ -<p>user-logout works!</p> diff --git a/client/src/app/users/user-logout/user-logout.component.scss b/client/src/app/users/user-logout/user-logout.component.scss deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/client/src/app/users/user-logout/user-logout.component.spec.ts b/client/src/app/users/user-logout/user-logout.component.spec.ts deleted file mode 100644 index 393de0aba04833b41f4e838b04e147da36718221..0000000000000000000000000000000000000000 --- a/client/src/app/users/user-logout/user-logout.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { UserLogoutComponent } from './user-logout.component'; - -describe('UserLogoutComponent', () => { - let component: UserLogoutComponent; - let fixture: ComponentFixture<UserLogoutComponent>; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ UserLogoutComponent ], - imports: [ HttpClientTestingModule, RouterTestingModule ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(UserLogoutComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/users/user-logout/user-logout.component.ts b/client/src/app/users/user-logout/user-logout.component.ts deleted file mode 100644 index e0e21b871ad106ef807fa87bb53859732ead5416..0000000000000000000000000000000000000000 --- a/client/src/app/users/user-logout/user-logout.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { AuthService } from 'src/app/authentication/auth.service'; - -@Component({ - selector: 'app-user-logout', - templateUrl: './user-logout.component.html', - styleUrls: ['./user-logout.component.scss'] -}) -export class UserLogoutComponent implements OnInit { - - constructor(private authService: AuthService) { } - - ngOnInit(): void { - this.authService.logout(); - } - -} diff --git a/client/src/app/users/user-profile/user-profile.component.spec.ts b/client/src/app/users/user-profile/user-profile.component.spec.ts index 4855ff37655c5f682abfbb90e35fed5219aa1484..3cc34bfe7937ceaea07988e2bed0029d17671949 100644 --- a/client/src/app/users/user-profile/user-profile.component.spec.ts +++ b/client/src/app/users/user-profile/user-profile.component.spec.ts @@ -1,17 +1,40 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; +import { AuthService } from 'src/app/authentication/auth.service'; +import { User } from 'src/app/models/user.model'; +import { UserLoginFormComponent } from '../user-login-form/user-login-form.component'; import { UserProfileComponent } from './user-profile.component'; describe('UserProfileComponent', () => { let component: UserProfileComponent; let fixture: ComponentFixture<UserProfileComponent>; + let mockAuthService; beforeEach(async () => { + // AuthService mock setup + mockAuthService = jasmine.createSpyObj(['getCurrentUser']); + mockAuthService.getCurrentUser.and.returnValue(new User({ + userId: 4, + username: "tester", + email: "test@test.com", + password: "1234", + create_time: 513498 + })); + + await TestBed.configureTestingModule({ declarations: [ UserProfileComponent ], - imports: [ HttpClientTestingModule, RouterTestingModule ] + imports: [ + HttpClientTestingModule, + RouterTestingModule.withRoutes([ + { path: 'login', component: UserLoginFormComponent} + ]) + ], + providers: [ + { provide: AuthService, useValue: mockAuthService } + ] }) .compileComponents(); }); @@ -25,4 +48,16 @@ describe('UserProfileComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should get current user', async () => { + await fixture.whenStable(); + expect(mockAuthService.getCurrentUser).toHaveBeenCalled(); + expect(component.user).toEqual(new User({ + userId: 4, + username: "tester", + email: "test@test.com", + password: "1234", + create_time: 513498 + })); + }); }); diff --git a/client/src/app/users/user-profile/user-profile.component.ts b/client/src/app/users/user-profile/user-profile.component.ts index ce10985b22048f6d0771c07ff0d54e02b6cde92d..5ba47faffcd241a344e888f5772820e7021fc541 100644 --- a/client/src/app/users/user-profile/user-profile.component.ts +++ b/client/src/app/users/user-profile/user-profile.component.ts @@ -13,22 +13,9 @@ import { UserService } from '../user.service'; export class UserProfileComponent implements OnInit { user: User = new User(); - constructor(private userService: UserService, private authService: AuthService, private router: Router) { } + constructor(private authService: AuthService, private router: Router) { } ngOnInit(): void { - // Check for token expiration - if (this.authService.checkTokenExpiration()) { // redirects to "/" if token is expired - // Get user data from JWT token - const token = localStorage.getItem('token'); - const user_data = JSON.parse(atob(token.split(".")[1])).data[0]; - - // Gets all user information and displays them in the component - this.userService.getUser(user_data.userId).then(user => { - this.user = user; - }).catch (error => { - console.log("Error getting user: " + error); - }); - } - + this.user = this.authService.getCurrentUser(); } } diff --git a/client/src/app/users/user.module.ts b/client/src/app/users/user.module.ts index 8d807898a3f435871ea9d79e61364c14e08e585c..2ad1ce5d3cf6b35ee0aad1576a0d7427df7c5115 100644 --- a/client/src/app/users/user.module.ts +++ b/client/src/app/users/user.module.ts @@ -5,16 +5,13 @@ import { FormsModule } from '@angular/forms'; import { UserRegistrationFormComponent } from './user-registration-form/user-registration-form.component'; import { UserProfileComponent } from './user-profile/user-profile.component'; import { UserLoginFormComponent } from './user-login-form/user-login-form.component'; -import { UserLogoutComponent } from './user-logout/user-logout.component'; - @NgModule({ declarations: [ UserRegistrationFormComponent, UserProfileComponent, - UserLoginFormComponent, - UserLogoutComponent + UserLoginFormComponent ], imports: [ CommonModule, diff --git a/server/src/models/post.ts b/server/src/models/post.ts index ad301aa6174e8eda398dd9cbf3b4b539f52e060b..f4038f8b47f04fc9decbba8abff1f8d2c0188cdd 100644 --- a/server/src/models/post.ts +++ b/server/src/models/post.ts @@ -4,7 +4,7 @@ interface IPost { description: string; price: string; timestamp: number; - owner: string; + owner: number; categoryid: number; imageUrl: string; }