diff options
Diffstat (limited to 'src')
38 files changed, 478 insertions, 302 deletions
diff --git a/src/DevHive.Angular/src/app/app-constants.module.ts b/src/DevHive.Angular/src/app/app-constants.module.ts index cbb1ec1..101ab44 100644 --- a/src/DevHive.Angular/src/app/app-constants.module.ts +++ b/src/DevHive.Angular/src/app/app-constants.module.ts @@ -13,4 +13,6 @@ export class AppConstants { public static PAGE_SIZE = 5; public static FALLBACK_PROFILE_ICON = 'assets/images/feed/profile-pic.png'; + + public static SESSION_TOKEN_KEY = 'UserCred'; } diff --git a/src/DevHive.Angular/src/app/app-routing.module.ts b/src/DevHive.Angular/src/app/app-routing.module.ts index c9a8c61..e4e3d63 100644 --- a/src/DevHive.Angular/src/app/app-routing.module.ts +++ b/src/DevHive.Angular/src/app/app-routing.module.ts @@ -4,8 +4,9 @@ import { FeedComponent } from './components/feed/feed.component'; import { LoginComponent } from './components/login/login.component'; import { RegisterComponent } from './components/register/register.component'; import { ProfileComponent } from './components/profile/profile.component'; -import {ProfileSettingsComponent} from './components/profile-settings/profile-settings.component'; -import {NotFoundComponent} from './components/not-found/not-found.component'; +import { ProfileSettingsComponent } from './components/profile-settings/profile-settings.component'; +import { NotFoundComponent } from './components/not-found/not-found.component'; +import { PostPageComponent } from './components/post-page/post-page.component'; const routes: Routes = [ { path: '', component: FeedComponent }, @@ -13,6 +14,7 @@ const routes: Routes = [ { path: 'register', component: RegisterComponent }, { path: 'profile/:username', component: ProfileComponent }, { path: 'profile/:username/settings', component: ProfileSettingsComponent }, + { path: 'post/:id', component: PostPageComponent }, { path: 'not-found', component: NotFoundComponent }, { path: '**', component: NotFoundComponent } ]; diff --git a/src/DevHive.Angular/src/app/app.module.ts b/src/DevHive.Angular/src/app/app.module.ts index 586064e..1867787 100644 --- a/src/DevHive.Angular/src/app/app.module.ts +++ b/src/DevHive.Angular/src/app/app.module.ts @@ -19,6 +19,7 @@ import { NotFoundComponent } from './components/not-found/not-found.component'; import { LoadingComponent } from './components/loading/loading.component'; import { ErrorBarComponent } from './components/error-bar/error-bar.component'; import { SuccessBarComponent } from './components/success-bar/success-bar.component'; +import { PostPageComponent } from './components/post-page/post-page.component'; @NgModule({ declarations: [ @@ -32,7 +33,8 @@ import { SuccessBarComponent } from './components/success-bar/success-bar.compon NotFoundComponent, LoadingComponent, ErrorBarComponent, - SuccessBarComponent + SuccessBarComponent, + PostPageComponent ], imports: [ BrowserModule, diff --git a/src/DevHive.Angular/src/app/components/error-bar/error-bar.component.ts b/src/DevHive.Angular/src/app/components/error-bar/error-bar.component.ts index c24448e..111bac8 100644 --- a/src/DevHive.Angular/src/app/components/error-bar/error-bar.component.ts +++ b/src/DevHive.Angular/src/app/components/error-bar/error-bar.component.ts @@ -1,6 +1,6 @@ -import {HttpErrorResponse} from '@angular/common/http'; +import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; -import {IApiError} from 'src/interfaces/api-error'; +import { IApiError } from 'src/interfaces/api-error'; @Component({ selector: 'app-error-bar', @@ -10,14 +10,20 @@ import {IApiError} from 'src/interfaces/api-error'; export class ErrorBarComponent implements OnInit { public errorMsg = ''; - constructor() { } + constructor() + { } ngOnInit(): void { this.hideError(); } showError(error: HttpErrorResponse): void { - const test: IApiError = { type: '', title: 'Error!', status: 0, traceId: '' }; + const test: IApiError = { + type: '', + title: 'Error!', + status: 0, + traceId: '' + }; Object.assign(test, error.error); this.errorMsg = test.title; } diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.css b/src/DevHive.Angular/src/app/components/feed/feed.component.css index f810e83..73e1f3e 100644 --- a/src/DevHive.Angular/src/app/components/feed/feed.component.css +++ b/src/DevHive.Angular/src/app/components/feed/feed.component.css @@ -75,6 +75,11 @@ /* Top bar */ +form { + width: 100%; + height: 100%; +} + #top-bar { display: flex; width: 98%; @@ -98,6 +103,7 @@ flex: 1; font-size: inherit; width: 100%; + height: 100%; margin: 0 auto; box-sizing: border-box; border: 2px solid var(--bg-color); diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.html b/src/DevHive.Angular/src/app/components/feed/feed.component.html index e3c6e83..1ec040b 100644 --- a/src/DevHive.Angular/src/app/components/feed/feed.component.html +++ b/src/DevHive.Angular/src/app/components/feed/feed.component.html @@ -17,7 +17,10 @@ <div id="feed-content"> <nav id="top-bar" class="rounded-border"> <img id="top-bar-profile-pic" class="round-image" [src]="user.imageUrl" alt="" (click)="goToProfile()"> - <input id="top-bar-create-post" type="text" placeholder="What's on your mind?"/> + <form [formGroup]="createPostFormGroup" (ngSubmit)="createPost()"> + <input id="top-bar-create-post" type="text" formControlName="newPostMessage" placeholder="What's on your mind?"/> + <input type="submit" style="display: none" /> <!-- You need this element, so when you press enter the request is sent --> + </form> <a id="top-bar-open-chat" href=""> <img src="assets/images/feed/chat-pic.png" alt=""/> </a> diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.ts b/src/DevHive.Angular/src/app/components/feed/feed.component.ts index f260fd4..f583078 100644 --- a/src/DevHive.Angular/src/app/components/feed/feed.component.ts +++ b/src/DevHive.Angular/src/app/components/feed/feed.component.ts @@ -1,12 +1,15 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { User } from 'src/models/identity/user'; import { UserService } from '../../services/user.service'; import { AppConstants } from 'src/app/app-constants.module'; -import {HttpErrorResponse} from '@angular/common/http'; -import {FeedService} from 'src/app/services/feed.service'; -import {Post} from 'src/models/post'; +import { HttpErrorResponse } from '@angular/common/http'; +import { FeedService } from 'src/app/services/feed.service'; +import { Post } from 'src/models/post'; +import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { PostService } from 'src/app/services/post.service'; +import { TokenService } from 'src/app/services/token.service'; @Component({ selector: 'app-feed', @@ -15,34 +18,44 @@ import {Post} from 'src/models/post'; }) export class FeedComponent implements OnInit { private _title = 'Feed'; - private _timeLoaded: string; + private _timeLoaded: string; // we send the time to the api as a string public dataArrived = false; public user: User; - public posts: Post[] = []; + public posts: Post[]; + public createPostFormGroup: FormGroup; - constructor(private _titleService: Title, private _router: Router, private _userService: UserService, private _feedService: FeedService) { + constructor(private _titleService: Title, private _fb: FormBuilder, private _router: Router, private _userService: UserService, private _feedService: FeedService, private _postService: PostService, private _tokenService: TokenService) { this._titleService.setTitle(this._title); } ngOnInit(): void { + this.posts = []; this.user = this._userService.getDefaultUser(); + const now = new Date(); now.setHours(now.getHours() + 2); // accounting for eastern european timezone this._timeLoaded = now.toISOString(); + this.createPostFormGroup = this._fb.group({ + newPostMessage: new FormControl('') + }); + if (sessionStorage.getItem('UserCred')) { this._userService.getUserFromSessionStorageRequest().subscribe( - (res: object) => this.loadFeed(res), - (err: HttpErrorResponse) => this.bailOnBadToken() + (res: object) => { + Object.assign(this.user, res); + this.loadFeed(); + }, + (err: HttpErrorResponse) => { + this.logout(); + } ); } else { this._router.navigate(['/login']); } } - private loadFeed(res: object): void { - Object.assign(this.user, res); - + private loadFeed(): void { this._feedService.getUserFeedFromSessionStorageRequest(1, this._timeLoaded, AppConstants.PAGE_SIZE).subscribe( (result: object) => { this.posts = Object.values(result)[0]; @@ -55,17 +68,9 @@ export class FeedComponent implements OnInit { } private finishUserLoading(): void { - if (this.user.imageUrl === '') { - this.user.imageUrl = AppConstants.FALLBACK_PROFILE_ICON; - } this.dataArrived = true; } - private bailOnBadToken(): void { - this._userService.logoutUserFromSessionStorage(); - this._router.navigate(['/login']); - } - goToProfile(): void { this._router.navigate(['/profile/' + this.user.userName]); } @@ -75,7 +80,17 @@ export class FeedComponent implements OnInit { } logout(): void { - this._userService.logoutUserFromSessionStorage(); + this._tokenService.logoutUserFromSessionStorage(); this._router.navigate(['/login']); } + + createPost(): void { + const postMessage = this.createPostFormGroup.get('newPostMessage')?.value; + + this._postService.createPostFromSessionStorageRequest(postMessage).subscribe( + (result: object) => { + this.goToProfile(); + } + ); + } } diff --git a/src/DevHive.Angular/src/app/components/loading/loading.component.ts b/src/DevHive.Angular/src/app/components/loading/loading.component.ts index 4dff0cd..e203484 100644 --- a/src/DevHive.Angular/src/app/components/loading/loading.component.ts +++ b/src/DevHive.Angular/src/app/components/loading/loading.component.ts @@ -7,9 +7,9 @@ import { Component, OnInit } from '@angular/core'; }) export class LoadingComponent implements OnInit { - constructor() { } + constructor() + { } ngOnInit(): void { } - } diff --git a/src/DevHive.Angular/src/app/components/login/login.component.ts b/src/DevHive.Angular/src/app/components/login/login.component.ts index c424060..6e285db 100644 --- a/src/DevHive.Angular/src/app/components/login/login.component.ts +++ b/src/DevHive.Angular/src/app/components/login/login.component.ts @@ -1,11 +1,11 @@ -import { Component, ErrorHandler, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { FormGroup, FormBuilder, Validators, FormControl, AbstractControl } from '@angular/forms'; import { Router } from '@angular/router'; import { Title } from '@angular/platform-browser'; import { UserService } from 'src/app/services/user.service'; -import {AppConstants} from 'src/app/app-constants.module'; -import {HttpErrorResponse, HttpResponse} from '@angular/common/http'; -import {ErrorBarComponent} from '../error-bar/error-bar.component'; +import { HttpErrorResponse } from '@angular/common/http'; +import { ErrorBarComponent } from '../error-bar/error-bar.component'; +import { TokenService } from 'src/app/services/token.service'; @Component({ selector: 'app-login', @@ -15,9 +15,9 @@ import {ErrorBarComponent} from '../error-bar/error-bar.component'; export class LoginComponent implements OnInit { @ViewChild(ErrorBarComponent) private _errorBar: ErrorBarComponent; private _title = 'Login'; - loginUserFormGroup: FormGroup; + public loginUserFormGroup: FormGroup; - constructor(private _titleService: Title, private _fb: FormBuilder, private _router: Router, private _userService: UserService) { + constructor(private _titleService: Title, private _fb: FormBuilder, private _router: Router, private _userService: UserService, private _tokenService: TokenService) { this._titleService.setTitle(this._title); } @@ -35,16 +35,16 @@ export class LoginComponent implements OnInit { onSubmit(): void { this._errorBar.hideError(); this._userService.loginUserRequest(this.loginUserFormGroup).subscribe( - res => this.finishLogin(res), - (err: HttpErrorResponse) => this._errorBar.showError(err) + res => { + this._tokenService.setUserTokenToSessionStorage(res); + this._router.navigate(['/']); + }, + (err: HttpErrorResponse) => { + this._errorBar.showError(err); + } ); } - private finishLogin(res: object): void { - this._userService.setUserTokenToSessionStorage(res); - this._router.navigate(['/']); - } - onRedirectRegister(): void { this._router.navigate(['/register']); } diff --git a/src/DevHive.Angular/src/app/components/not-found/not-found.component.ts b/src/DevHive.Angular/src/app/components/not-found/not-found.component.ts index 157fb97..89a230d 100644 --- a/src/DevHive.Angular/src/app/components/not-found/not-found.component.ts +++ b/src/DevHive.Angular/src/app/components/not-found/not-found.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import {Router} from '@angular/router'; +import { Router } from '@angular/router'; @Component({ selector: 'app-not-found', diff --git a/src/DevHive.Angular/src/app/components/post-page/post-page.component.css b/src/DevHive.Angular/src/app/components/post-page/post-page.component.css new file mode 100644 index 0000000..50adee5 --- /dev/null +++ b/src/DevHive.Angular/src/app/components/post-page/post-page.component.css @@ -0,0 +1,19 @@ +#content { + justify-content: flex-start !important; +} + +#content > * { + width: 100%; +} + +#back-btns { + width: 100%; + display: flex; +} + +.submit-btn { + flex: 1; + max-width: 98%; + margin: 0 auto; + margin-bottom: .5em; +} diff --git a/src/DevHive.Angular/src/app/components/post-page/post-page.component.html b/src/DevHive.Angular/src/app/components/post-page/post-page.component.html new file mode 100644 index 0000000..4f6f33d --- /dev/null +++ b/src/DevHive.Angular/src/app/components/post-page/post-page.component.html @@ -0,0 +1,6 @@ +<div id="content"> + <div id="back-btns"> + <button class="submit-btn" type="submit" (click)="backToFeed()">ᐊ Back to feed</button> + </div> + <app-post [paramId]="postId.toString()"></app-post> +<div> diff --git a/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts b/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts new file mode 100644 index 0000000..56e146d --- /dev/null +++ b/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { Guid } from 'guid-typescript'; + +@Component({ + selector: 'app-post-page', + templateUrl: './post-page.component.html', + styleUrls: ['./post-page.component.css'] +}) +export class PostPageComponent implements OnInit { + public postId: Guid; + + constructor(private _router: Router) + { } + + ngOnInit(): void { + this.postId = Guid.parse(this._router.url.substring(6)); + } + + backToFeed(): void { + this._router.navigate(['/']); + } +} diff --git a/src/DevHive.Angular/src/app/components/post/post.component.css b/src/DevHive.Angular/src/app/components/post/post.component.css index c3e3caa..1ae5d8f 100644 --- a/src/DevHive.Angular/src/app/components/post/post.component.css +++ b/src/DevHive.Angular/src/app/components/post/post.component.css @@ -47,6 +47,7 @@ hr { .message { margin: .3em 0; + word-break: break-all; } .timestamp { @@ -54,13 +55,18 @@ hr { color: gray; } +.message:hover, .timestamp:hover { + cursor: pointer; +} + /* Rating */ .rating { display: flex; flex-direction: column; align-items: center; - margin-right: -.1em; + min-height: 4.4em; + margin: auto -.1em auto 0; } .score { diff --git a/src/DevHive.Angular/src/app/components/post/post.component.html b/src/DevHive.Angular/src/app/components/post/post.component.html index 8fbda35..ea81bdf 100644 --- a/src/DevHive.Angular/src/app/components/post/post.component.html +++ b/src/DevHive.Angular/src/app/components/post/post.component.html @@ -1,3 +1,5 @@ +<app-loading *ngIf="!loaded"></app-loading> + <div class="post rounded-border" *ngIf="loaded"> <div class="content"> <div class="author" (click)="goToAuthorProfile()"> @@ -11,10 +13,10 @@ </div> </div> </div> - <div class="message"> + <div class="message" (click)="goToPostPage()"> {{ post.message }} </div> - <div class="timestamp"> + <div class="timestamp" (click)="goToPostPage()"> {{ timeCreated }} </div> </div> diff --git a/src/DevHive.Angular/src/app/components/post/post.component.ts b/src/DevHive.Angular/src/app/components/post/post.component.ts index 7a6b5c0..0842e3c 100644 --- a/src/DevHive.Angular/src/app/components/post/post.component.ts +++ b/src/DevHive.Angular/src/app/components/post/post.component.ts @@ -1,12 +1,10 @@ import { Component, Input, OnInit } from '@angular/core'; -import {Router} from '@angular/router'; +import { Router } from '@angular/router'; import { Guid } from 'guid-typescript'; -import {AppConstants} from 'src/app/app-constants.module'; -import {FeedService} from 'src/app/services/feed.service'; -import {PostService} from 'src/app/services/post.service'; -import {UserService} from 'src/app/services/user.service'; +import { PostService } from 'src/app/services/post.service'; +import { UserService } from 'src/app/services/user.service'; import { User } from 'src/models/identity/user'; -import {Post} from 'src/models/post'; +import { Post } from 'src/models/post'; @Component({ selector: 'app-post', @@ -14,15 +12,15 @@ import {Post} from 'src/models/post'; styleUrls: ['./post.component.css'], }) export class PostComponent implements OnInit { + public loaded = false; public user: User; public post: Post; public votesNumber: number; public timeCreated: string; - public loaded = false; @Input() paramId: string; constructor(private _postService: PostService, private _userService: UserService, private _router: Router) - {} + { } ngOnInit(): void { this.post = this._postService.getDefaultPost(); @@ -31,11 +29,12 @@ export class PostComponent implements OnInit { this._postService.getPostRequest(Guid.parse(this.paramId)).subscribe( (result: object) => { Object.assign(this.post, result); + this.votesNumber = 23; + this.timeCreated = new Date(this.post.timeCreated).toLocaleString('en-GB'); this.loadUser(); } ); - this.votesNumber = 23; } private loadUser(): void { @@ -50,4 +49,8 @@ export class PostComponent implements OnInit { goToAuthorProfile(): void { this._router.navigate(['/profile/' + this.user.userName]); } + + goToPostPage(): void { + this._router.navigate(['/post/' + this.post.postId]); + } } diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css index 2aecef5..83f66f1 100644 --- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css +++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css @@ -55,12 +55,6 @@ hr { flex-wrap: wrap; } -#all-languages > *, #all-technologies > * { - width: fit-content; - margin-top: .1em; - margin-bottom: .1em; -} - /* Buttons */ .edit-btn { diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html index 1b713d7..c38a6d7 100644 --- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html +++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html @@ -2,7 +2,7 @@ <div id="content" *ngIf="dataArrived"> <nav id="navigation"> - <button class="submit-btn" (click)="goBack()">ᐊ Back</button> + <button class="submit-btn" (click)="goToProfile()">ᐊ Back</button> <button class="submit-btn" (click)="logout()">Logout</button> </nav> <hr> diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts index e348b8b..769c1bb 100644 --- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts +++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts @@ -1,15 +1,17 @@ -import {Location} from '@angular/common'; -import {HttpErrorResponse} from '@angular/common/http'; +import { Location } from '@angular/common'; +import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit, ViewChild } from '@angular/core'; -import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; -import {Router} from '@angular/router'; -import {AppConstants} from 'src/app/app-constants.module'; -import {LanguageService} from 'src/app/services/language.service'; -import {UserService} from 'src/app/services/user.service'; -import {TechnologyService} from 'src/app/services/technology.service'; -import {Language, Technology, User} from 'src/models/identity/user'; -import {ErrorBarComponent} from '../error-bar/error-bar.component'; -import {SuccessBarComponent} from '../success-bar/success-bar.component'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { LanguageService } from 'src/app/services/language.service'; +import { UserService } from 'src/app/services/user.service'; +import { TechnologyService } from 'src/app/services/technology.service'; +import { User } from 'src/models/identity/user'; +import { ErrorBarComponent } from '../error-bar/error-bar.component'; +import { SuccessBarComponent } from '../success-bar/success-bar.component'; +import { Language } from 'src/models/language'; +import { Technology } from 'src/models/technology'; +import { TokenService } from 'src/app/services/token.service'; @Component({ selector: 'app-profile-settings', @@ -20,26 +22,34 @@ export class ProfileSettingsComponent implements OnInit { @ViewChild(ErrorBarComponent) private _errorBar: ErrorBarComponent; @ViewChild(SuccessBarComponent) private _successBar: SuccessBarComponent; private _urlUsername: string; - public updateUserFormGroup: FormGroup; public dataArrived = false; - public user: User; public deleteAccountConfirm = false; public showLanguages = false; - public availableLanguages: Language[] = []; public showTechnologies = false; - public availableTechnologies: Technology[] = []; + public updateUserFormGroup: FormGroup; + public user: User; + public availableLanguages: Language[]; + public availableTechnologies: Technology[]; - constructor(private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _fb: FormBuilder, private _location: Location) + constructor(private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _tokenService: TokenService, private _fb: FormBuilder, private _location: Location) { } ngOnInit(): void { this._urlUsername = this._router.url.substring(9); this._urlUsername = this._urlUsername.substring(0, this._urlUsername.length - 9); + this.user = this._userService.getDefaultUser(); + this.availableLanguages = []; + this.availableTechnologies = []; this._userService.getUserByUsernameRequest(this._urlUsername).subscribe( - (res: object) => this.finishUserLoading(res), - (err: HttpErrorResponse) => { this._router.navigate(['/not-found']); } + (res: object) => { + Object.assign(this.user, res); + this.finishUserLoading(); + }, + (err: HttpErrorResponse) => { + this._router.navigate(['/not-found']); + } ); this._languageService.getAllLanguagesWithSessionStorageRequest().subscribe( @@ -54,12 +64,7 @@ export class ProfileSettingsComponent implements OnInit { ); } - private finishUserLoading(res: object): void { - Object.assign(this.user, res); - if (this.user.imageUrl === '') { - this.user.imageUrl = AppConstants.FALLBACK_PROFILE_ICON; - } - + private finishUserLoading(): void { if (sessionStorage.getItem('UserCred')) { const userFromToken: User = this._userService.getDefaultUser(); @@ -75,7 +80,9 @@ export class ProfileSettingsComponent implements OnInit { this.goToProfile(); } }, - (err: HttpErrorResponse) => this.bailOnBadToken() + (err: HttpErrorResponse) => { + this.logout(); + } ); } else { @@ -119,11 +126,13 @@ export class ProfileSettingsComponent implements OnInit { technologies: new FormControl('') }); - this.getLanguagesForShowing() - .then(value => this.updateUserFormGroup.patchValue({ languageInput : value })); + this.getLanguagesForShowing().then(value => { + this.updateUserFormGroup.patchValue({ languageInput : value }); + }); - this.getTechnologiesForShowing() - .then(value => this.updateUserFormGroup.patchValue({ technologyInput : value })); + this.getTechnologiesForShowing().then(value => { + this.updateUserFormGroup.patchValue({ technologyInput : value }); + }); this.updateUserFormGroup.valueChanges.subscribe(() => { this._successBar?.hideMsg(); @@ -132,28 +141,21 @@ export class ProfileSettingsComponent implements OnInit { } private getLanguagesForShowing(): Promise<string> { - return new Promise(resolve => - this._languageService.getFullLanguagesFromIncomplete(this.user.languages) - .then(value => { - this.user.languages = value; - resolve(value.map(x => x.name).join(' ')); - }) - ); + return new Promise(resolve => { + this._languageService.getFullLanguagesFromIncomplete(this.user.languages).then(value => { + this.user.languages = value; + resolve(value.map(x => x.name).join(' ')); + }); + }); } private getTechnologiesForShowing(): Promise<string> { - return new Promise(resolve => - this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies) - .then(value => { - this.user.technologies = value; - resolve(value.map(x => x.name).join(' ')); - }) - ); - } - - private bailOnBadToken(): void { - this._userService.logoutUserFromSessionStorage(); - this._router.navigate(['/login']); + return new Promise(resolve => { + this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies).then(value => { + this.user.technologies = value; + resolve(value.map(x => x.name).join(' ')); + }); + }); } onSubmit(): void { @@ -163,9 +165,13 @@ export class ProfileSettingsComponent implements OnInit { this.patchLanguagesControl(); this.patchTechnologiesControl(); - this._userService.putUserFromSessionStorageRequest(this.updateUserFormGroup).subscribe( - res => this._successBar.showMsg('Profile updated successfully!'), - (err: HttpErrorResponse) => this._errorBar.showError(err) + this._userService.putUserFromSessionStorageRequest(this.updateUserFormGroup, this.user.roles, this.user.friends).subscribe( + res => { + this._successBar.showMsg('Profile updated successfully!'); + }, + (err: HttpErrorResponse) => { + this._errorBar.showError(err); + } ); } @@ -225,21 +231,12 @@ export class ProfileSettingsComponent implements OnInit { } } - goToProfile(): void { this._router.navigate([this._router.url.substring(0, this._router.url.length - 9)]); } - goBack(): void { - const currURL = this._location.path(); - this._location.back(); - if (this._location.path() === currURL) { - this.goToProfile(); - } - } - logout(): void { - this._userService.logoutUserFromSessionStorage(); + this._tokenService.logoutUserFromSessionStorage(); this.goToProfile(); } @@ -255,10 +252,11 @@ export class ProfileSettingsComponent implements OnInit { if (this.deleteAccountConfirm) { this._userService.deleteUserFromSessionStorageRequest().subscribe( (res: object) => { - this._userService.logoutUserFromSessionStorage(); - this._router.navigate(['/login']); + this.logout(); }, - (err: HttpErrorResponse) => console.log(err) + (err: HttpErrorResponse) => { + this._errorBar.showError(err); + } ); } else { diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.css b/src/DevHive.Angular/src/app/components/profile/profile.component.css index f312ebd..fb84af3 100644 --- a/src/DevHive.Angular/src/app/components/profile/profile.component.css +++ b/src/DevHive.Angular/src/app/components/profile/profile.component.css @@ -72,6 +72,7 @@ hr { width: 100%; display: flex; align-items: center; + flex-wrap: wrap; } /* Posts */ diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.html b/src/DevHive.Angular/src/app/components/profile/profile.component.html index ac0c07e..9cb4dd2 100644 --- a/src/DevHive.Angular/src/app/components/profile/profile.component.html +++ b/src/DevHive.Angular/src/app/components/profile/profile.component.html @@ -26,7 +26,7 @@ {{ lang.name }} </div> </div> - <div *ngIf="showNoLangMsg"> + <div *ngIf="user.languages.length === 0"> None </div> </div> @@ -37,7 +37,7 @@ {{ tech.name }} </div> </div> - <div *ngIf="showNoTechMsg"> + <div *ngIf="user.technologies.length === 0"> None </div> </div> diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.ts b/src/DevHive.Angular/src/app/components/profile/profile.component.ts index 7717505..5dd965e 100644 --- a/src/DevHive.Angular/src/app/components/profile/profile.component.ts +++ b/src/DevHive.Angular/src/app/components/profile/profile.component.ts @@ -3,12 +3,13 @@ import { Router } from '@angular/router'; import { UserService } from 'src/app/services/user.service'; import { User } from 'src/models/identity/user'; import { AppConstants } from 'src/app/app-constants.module'; -import {HttpErrorResponse} from '@angular/common/http'; -import {Location} from '@angular/common'; -import {LanguageService} from 'src/app/services/language.service'; -import {TechnologyService} from 'src/app/services/technology.service'; -import {Post} from 'src/models/post'; -import {FeedService} from 'src/app/services/feed.service'; +import { HttpErrorResponse } from '@angular/common/http'; +import { Location } from '@angular/common'; +import { LanguageService } from 'src/app/services/language.service'; +import { TechnologyService } from 'src/app/services/technology.service'; +import { Post } from 'src/models/post'; +import { FeedService } from 'src/app/services/feed.service'; +import { TokenService } from 'src/app/services/token.service'; @Component({ selector: 'app-profile', @@ -20,11 +21,9 @@ export class ProfileComponent implements OnInit { public loggedInUser = false; public dataArrived = false; public user: User; - public userPosts: Post[] = []; - public showNoLangMsg = false; - public showNoTechMsg = false; + public userPosts: Post[]; - constructor(private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _feedService: FeedService, private _location: Location) + constructor(private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _feedService: FeedService, private _location: Location, private _tokenService: TokenService) { } private setDefaultUser(): void { @@ -34,26 +33,28 @@ export class ProfileComponent implements OnInit { ngOnInit(): void { this._urlUsername = this._router.url.substring(9); this.user = this._userService.getDefaultUser(); + this.userPosts = []; this._userService.getUserByUsernameRequest(this._urlUsername).subscribe( - (res: object) => this.loadLanguages(res), - (err: HttpErrorResponse) => { this._router.navigate(['/not-found']); } + (res: object) => { + Object.assign(this.user, res); + this.loadLanguages(); + }, + (err: HttpErrorResponse) => { + this._router.navigate(['/not-found']); + } ); } - private loadLanguages(res: object): void { - Object.assign(this.user, res); - + private loadLanguages(): void { if (this.user.languages.length > 0) { // When user has languages, get their names and load technologies - this._languageService.getFullLanguagesFromIncomplete(this.user.languages) - .then(value => { - this.user.languages = value; - this.loadTechnologies(); - }); + this._languageService.getFullLanguagesFromIncomplete(this.user.languages).then(value => { + this.user.languages = value; + this.loadTechnologies(); + }); } else { - this.showNoLangMsg = true; this.loadTechnologies(); } } @@ -61,14 +62,12 @@ export class ProfileComponent implements OnInit { private loadTechnologies(): void { if (this.user.technologies.length > 0) { // When user has technologies, get their names and then load posts - this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies) - .then(value => { - this.user.technologies = value; - this.loadPosts(); - }); + this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies).then(value => { + this.user.technologies = value; + this.loadPosts(); + }); } else { - this.showNoTechMsg = true; this.loadPosts(); } } @@ -89,10 +88,6 @@ export class ProfileComponent implements OnInit { } private finishUserLoading(): void { - if (this.user.imageUrl === '') { - this.user.imageUrl = AppConstants.FALLBACK_PROFILE_ICON; - } - if (sessionStorage.getItem('UserCred')) { const userFromToken: User = this._userService.getDefaultUser(); @@ -105,7 +100,9 @@ export class ProfileComponent implements OnInit { } this.dataArrived = true; }, - (err: HttpErrorResponse) => this.bailOnBadToken() + (err: HttpErrorResponse) => { + this.logout(); + } ); } else { @@ -113,17 +110,8 @@ export class ProfileComponent implements OnInit { } } - private bailOnBadToken(): void { - this._userService.logoutUserFromSessionStorage(); - this._router.navigate(['/login']); - } - goBack(): void { - const currURL = this._location.path(); - this._location.back(); - if (this._location.path() === currURL) { - this._router.navigate(['/']); - } + this._router.navigate(['/']); } navigateToSettings(): void { @@ -131,7 +119,7 @@ export class ProfileComponent implements OnInit { } logout(): void { - this._userService.logoutUserFromSessionStorage(); + this._tokenService.logoutUserFromSessionStorage(); // Reload the page this._router.routeReuseStrategy.shouldReuseRoute = () => false; diff --git a/src/DevHive.Angular/src/app/components/register/register.component.ts b/src/DevHive.Angular/src/app/components/register/register.component.ts index 832d176..36eaa55 100644 --- a/src/DevHive.Angular/src/app/components/register/register.component.ts +++ b/src/DevHive.Angular/src/app/components/register/register.component.ts @@ -1,10 +1,11 @@ -import {HttpErrorResponse} from '@angular/common/http'; +import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit, ViewChild } from '@angular/core'; import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { Title } from '@angular/platform-browser'; import { Router } from '@angular/router'; +import { TokenService } from 'src/app/services/token.service'; import { UserService } from 'src/app/services/user.service'; -import {ErrorBarComponent} from '../error-bar/error-bar.component'; +import { ErrorBarComponent } from '../error-bar/error-bar.component'; @Component({ selector: 'app-register', @@ -16,7 +17,7 @@ export class RegisterComponent implements OnInit { private _title = 'Register'; public registerUserFormGroup: FormGroup; - constructor(private _titleService: Title, private _fb: FormBuilder, private _router: Router, private _userService: UserService) { + constructor(private _titleService: Title, private _fb: FormBuilder, private _router: Router, private _userService: UserService, private _tokenService: TokenService) { this._titleService.setTitle(this._title); } @@ -50,16 +51,15 @@ export class RegisterComponent implements OnInit { onSubmit(): void { this._userService.registerUserRequest(this.registerUserFormGroup).subscribe( - res => this.finishRegister(res), - (err: HttpErrorResponse) => this._errorBar.showError(err) + res => { + this._tokenService.setUserTokenToSessionStorage(res); + this._router.navigate(['/']); + }, + (err: HttpErrorResponse) => { + this._errorBar.showError(err); + } ); } - - private finishRegister(res: object): void { - this._userService.setUserTokenToSessionStorage(res); - this._router.navigate(['/']); - } - onRedirectLogin(): void { this._router.navigate(['/login']); } diff --git a/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts b/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts index f7db0e2..f7c7e54 100644 --- a/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts +++ b/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts @@ -8,7 +8,8 @@ import { Component, OnInit } from '@angular/core'; export class SuccessBarComponent implements OnInit { public successMsg = ''; - constructor() { } + constructor() + { } ngOnInit(): void { this.hideMsg(); diff --git a/src/DevHive.Angular/src/app/services/feed.service.ts b/src/DevHive.Angular/src/app/services/feed.service.ts index cb82bcd..d160f6d 100644 --- a/src/DevHive.Angular/src/app/services/feed.service.ts +++ b/src/DevHive.Angular/src/app/services/feed.service.ts @@ -1,24 +1,28 @@ -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Guid} from 'guid-typescript'; -import {Observable} from 'rxjs'; -import {IJWTPayload} from 'src/interfaces/jwt-payload'; -import {AppConstants} from '../app-constants.module'; -import jwt_decode from 'jwt-decode'; -import {IUserCredentials} from 'src/interfaces/user-credentials'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Guid } from 'guid-typescript'; +import { Observable } from 'rxjs'; +import { AppConstants } from '../app-constants.module'; +import { TokenService } from './token.service'; @Injectable({ providedIn: 'root' }) export class FeedService { - constructor(private http: HttpClient) { } + constructor(private _http: HttpClient, private _tokenService: TokenService) + { } + + /* Requests from session storage */ getUserFeedFromSessionStorageRequest(pageNumber: number, firstTimeIssued: string, pageSize: number): Observable<object> { - const jwt: IJWTPayload = { token: sessionStorage.getItem('UserCred') ?? '' }; - const userCred = jwt_decode<IUserCredentials>(jwt.token); - return this.getUserFeedRequest(userCred.ID, jwt.token, pageNumber, firstTimeIssued, pageSize); + const token = this._tokenService.getTokenFromSessionStorage(); + const userId = this._tokenService.getUserIdFromSessionStorageToken(); + + return this.getUserFeedRequest(userId, token, pageNumber, firstTimeIssued, pageSize); } + /* Feed requests */ + getUserFeedRequest(userId: Guid, authToken: string, pageNumber: number, firstTimeIssued: string, pageSize: number): Observable<object> { const body = { pageNumber: pageNumber, @@ -29,7 +33,7 @@ export class FeedService { params: new HttpParams().set('UserId', userId.toString()), headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) }; - return this.http.post(AppConstants.API_FEED_URL + '/GetPosts', body, options); + return this._http.post(AppConstants.API_FEED_URL + '/GetPosts', body, options); } getUserPostsRequest(userName: string, pageNumber: number, firstTimeIssued: string, pageSize: number): Observable<object> { @@ -41,6 +45,6 @@ export class FeedService { const options = { params: new HttpParams().set('UserName', userName) }; - return this.http.post(AppConstants.API_FEED_URL + '/GetUserPosts', body, options); + return this._http.post(AppConstants.API_FEED_URL + '/GetUserPosts', body, options); } } diff --git a/src/DevHive.Angular/src/app/services/language.service.ts b/src/DevHive.Angular/src/app/services/language.service.ts index d85f178..49be537 100644 --- a/src/DevHive.Angular/src/app/services/language.service.ts +++ b/src/DevHive.Angular/src/app/services/language.service.ts @@ -1,33 +1,40 @@ -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Guid} from 'guid-typescript'; -import {Observable} from 'rxjs'; -import {Language} from 'src/models/identity/user'; -import {AppConstants} from '../app-constants.module'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Guid } from 'guid-typescript'; +import { Observable } from 'rxjs'; +import { Language } from 'src/models/language'; +import { AppConstants } from '../app-constants.module'; +import { TokenService } from './token.service'; @Injectable({ providedIn: 'root' }) export class LanguageService { - constructor(private http: HttpClient) { } + constructor(private _http: HttpClient, private _tokenService: TokenService) + { } + + /* Requests from session storage */ + + getAllLanguagesWithSessionStorageRequest(): Observable<object> { + const token = this._tokenService.getTokenFromSessionStorage(); + + return this.getAllLanguagesRequest(token); + } + + /* Language requests */ getLanguageRequest(langId: Guid): Observable<object> { const options = { params: new HttpParams().set('Id', langId.toString()), }; - return this.http.get(AppConstants.API_LANGUAGE_URL, options); - } - - getAllLanguagesWithSessionStorageRequest(): Observable<object> { - const token = sessionStorage.getItem('UserCred') ?? ''; - return this.getAllLanguagesRequest(token); + return this._http.get(AppConstants.API_LANGUAGE_URL, options); } getAllLanguagesRequest(authToken: string): Observable<object> { const options = { headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) }; - return this.http.get(AppConstants.API_LANGUAGE_URL + '/GetLanguages', options); + return this._http.get(AppConstants.API_LANGUAGE_URL + '/GetLanguages', options); } getFullLanguagesFromIncomplete(givenLanguages: Language[]): Promise<Language[]> { diff --git a/src/DevHive.Angular/src/app/services/post.service.ts b/src/DevHive.Angular/src/app/services/post.service.ts index 4cd96bc..a35a323 100644 --- a/src/DevHive.Angular/src/app/services/post.service.ts +++ b/src/DevHive.Angular/src/app/services/post.service.ts @@ -1,25 +1,49 @@ -import {HttpClient, HttpParams} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Guid} from 'guid-typescript'; -import {Observable} from 'rxjs'; -import {Post} from 'src/models/post'; -import {AppConstants} from '../app-constants.module'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Guid } from 'guid-typescript'; +import { Observable } from 'rxjs'; +import { Post } from 'src/models/post'; +import { AppConstants } from '../app-constants.module'; +import { TokenService } from './token.service'; @Injectable({ providedIn: 'root' }) export class PostService { - constructor(private http: HttpClient) { } + constructor(private _http: HttpClient, private _tokenService: TokenService) + { } getDefaultPost(): Post { return new Post(Guid.createEmpty(), 'Gosho', 'Trapov', 'gosho_trapov', 'Your opinion on my idea?', new Date()); } + /* Requests from session storage */ + + createPostFromSessionStorageRequest(postMessage: string): Observable<object> { + const userId = this._tokenService.getUserIdFromSessionStorageToken(); + const token = this._tokenService.getTokenFromSessionStorage(); + + return this.createPostRequest(userId, token, postMessage); + } + + /* Post requests */ + + createPostRequest(userId: Guid, authToken: string, postMessage: string): Observable<object> { + const body = { + message: postMessage, + files: [] + }; + const options = { + params: new HttpParams().set('UserId', userId.toString()), + headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) + }; + return this._http.post(AppConstants.API_POST_URL, body, options); + } + getPostRequest(id: Guid): Observable<object> { const options = { params: new HttpParams().set('Id', id.toString()) }; - return this.http.get(AppConstants.API_POST_URL, options); + return this._http.get(AppConstants.API_POST_URL, options); } } - diff --git a/src/DevHive.Angular/src/app/services/technology.service.ts b/src/DevHive.Angular/src/app/services/technology.service.ts index 207303f..3d0829b 100644 --- a/src/DevHive.Angular/src/app/services/technology.service.ts +++ b/src/DevHive.Angular/src/app/services/technology.service.ts @@ -1,33 +1,40 @@ -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Guid} from 'guid-typescript'; -import {Observable} from 'rxjs'; -import {Technology} from 'src/models/identity/user'; -import {AppConstants} from '../app-constants.module'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Guid } from 'guid-typescript'; +import { Observable } from 'rxjs'; +import { Technology } from 'src/models/technology'; +import { AppConstants } from '../app-constants.module'; +import { TokenService } from './token.service'; @Injectable({ providedIn: 'root' }) export class TechnologyService { - constructor(private http: HttpClient) { } + constructor(private _http: HttpClient, private _tokenService: TokenService) + { } + + /* Requests from session storage */ + + getAllTechnologiesWithSessionStorageRequest(): Observable<object> { + const token = this._tokenService.getTokenFromSessionStorage(); + + return this.getAllTechnologiesRequest(token); + } + + /* Technology requests */ getTechnologyRequest(techId: Guid): Observable<object> { const options = { params: new HttpParams().set('Id', techId.toString()) }; - return this.http.get(AppConstants.API_TECHNOLOGY_URL, options); - } - - getAllTechnologiesWithSessionStorageRequest(): Observable<object> { - const token = sessionStorage.getItem('UserCred') ?? ''; - return this.getAllTechnologiesRequest(token); + return this._http.get(AppConstants.API_TECHNOLOGY_URL, options); } getAllTechnologiesRequest(authToken: string): Observable<object> { const options = { headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) }; - return this.http.get(AppConstants.API_TECHNOLOGY_URL + '/GetTechnologies', options); + return this._http.get(AppConstants.API_TECHNOLOGY_URL + '/GetTechnologies', options); } getFullTechnologiesFromIncomplete(givenTechnologies: Technology[]): Promise<Technology[]> { @@ -56,5 +63,4 @@ export class TechnologyService { } }); } - } diff --git a/src/DevHive.Angular/src/app/services/token.service.ts b/src/DevHive.Angular/src/app/services/token.service.ts new file mode 100644 index 0000000..8131228 --- /dev/null +++ b/src/DevHive.Angular/src/app/services/token.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { Guid } from 'guid-typescript'; +import jwt_decode from 'jwt-decode'; +import { IJWTPayload } from 'src/interfaces/jwt-payload'; +import { IUserCredentials } from 'src/interfaces/user-credentials'; +import { AppConstants } from '../app-constants.module'; + +@Injectable({ + providedIn: 'root' +}) +export class TokenService { + constructor() + { } + + /* Session storage */ + + setUserTokenToSessionStorage(response: object): void { + const token = JSON.stringify(response); + sessionStorage.setItem(AppConstants.SESSION_TOKEN_KEY, token.substr(10, token.length - 12)); + } + + getTokenFromSessionStorage(): string { + return sessionStorage.getItem(AppConstants.SESSION_TOKEN_KEY) ?? ''; + } + + getUserIdFromSessionStorageToken(): Guid { + const jwt: IJWTPayload = { + token: this.getTokenFromSessionStorage() + }; + const userCred = jwt_decode<IUserCredentials>(jwt.token); + + return userCred.ID; + } + + logoutUserFromSessionStorage(): void { + sessionStorage.removeItem(AppConstants.SESSION_TOKEN_KEY); + } +} diff --git a/src/DevHive.Angular/src/app/services/user.service.ts b/src/DevHive.Angular/src/app/services/user.service.ts index 6badf94..3bfc857 100644 --- a/src/DevHive.Angular/src/app/services/user.service.ts +++ b/src/DevHive.Angular/src/app/services/user.service.ts @@ -1,73 +1,59 @@ import { Injectable } from '@angular/core'; -import {Guid} from 'guid-typescript'; +import { Guid } from 'guid-typescript'; import { User } from '../../models/identity/user'; -import jwt_decode from 'jwt-decode'; -import { IJWTPayload } from '../../interfaces/jwt-payload'; -import { IUserCredentials } from '../../interfaces/user-credentials'; import { FormGroup } from '@angular/forms'; import { AppConstants } from 'src/app/app-constants.module'; -import {HttpClient, HttpErrorResponse, HttpHeaders, HttpParams} from '@angular/common/http'; -import {Observable} from 'rxjs'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { Role } from 'src/models/identity/role'; +import { Friend } from 'src/models/identity/friend'; +import { TokenService } from './token.service'; @Injectable({ providedIn: 'root' }) export class UserService { - constructor(private http: HttpClient) { } + constructor(private _http: HttpClient, private _tokenService: TokenService) + { } getDefaultUser(): User { - return new User(Guid.createEmpty(), 'gosho_trapov', 'Gosho', 'Trapov', 'gotra@bg.com', AppConstants.FALLBACK_PROFILE_ICON, new Array(), new Array()); + return new User(Guid.createEmpty(), 'gosho_trapov', 'Gosho', 'Trapov', 'gotra@bg.com', AppConstants.FALLBACK_PROFILE_ICON, [], [], [], []); } - getUserIdFromSessionStorageToken(): Guid { - const jwt: IJWTPayload = { token: sessionStorage.getItem('UserCred') ?? '' }; - const userCred = jwt_decode<IUserCredentials>(jwt.token); - return userCred.ID; - } - - setUserTokenToSessionStorage(response: object): void { - const token = JSON.stringify(response); - sessionStorage.setItem('UserCred', token.substr(10, token.length - 12)); - } + /* Requests from session storage */ getUserFromSessionStorageRequest(): Observable<object> { - // Get the token and userid from session storage - const jwt: IJWTPayload = { token: sessionStorage.getItem('UserCred') ?? '' }; - const userCred = jwt_decode<IUserCredentials>(jwt.token); + const userId = this._tokenService.getUserIdFromSessionStorageToken(); + const token = this._tokenService.getTokenFromSessionStorage(); - return this.getUserRequest(userCred.ID, jwt.token); + return this.getUserRequest(userId, token); } - putUserFromSessionStorageRequest(updateUserFormGroup: FormGroup): Observable<object> { - // Get the token and userid from session storage - const jwt: IJWTPayload = { token: sessionStorage.getItem('UserCred') ?? '' }; - const userCred = jwt_decode<IUserCredentials>(jwt.token); + putUserFromSessionStorageRequest(updateUserFormGroup: FormGroup, userRoles: Role[], userFriends: Friend[]): Observable<object> { + const userId = this._tokenService.getUserIdFromSessionStorageToken(); + const token = this._tokenService.getTokenFromSessionStorage(); - return this.putUserRequest(userCred.ID, jwt.token, updateUserFormGroup); + return this.putUserRequest(userId, token, updateUserFormGroup, userRoles, userFriends); } deleteUserFromSessionStorageRequest(): Observable<object> { - // Get the token and userid from session storage - const jwt: IJWTPayload = { token: sessionStorage.getItem('UserCred') ?? '' }; - const userCred = jwt_decode<IUserCredentials>(jwt.token); + const userId = this._tokenService.getUserIdFromSessionStorageToken(); + const token = this._tokenService.getTokenFromSessionStorage(); - return this.deleteUserRequest(userCred.ID, jwt.token); + return this.deleteUserRequest(userId, token); } - logoutUserFromSessionStorage(): void { - sessionStorage.removeItem('UserCred'); - } + /* User requests */ loginUserRequest(loginUserFormGroup: FormGroup): Observable<object> { const body = { UserName: loginUserFormGroup.get('username')?.value, Password: loginUserFormGroup.get('password')?.value - }; - return this.http.post(AppConstants.API_USER_LOGIN_URL, body); + }; + return this._http.post(AppConstants.API_USER_LOGIN_URL, body); } registerUserRequest(registerUserFormGroup: FormGroup): Observable<object> { - // TODO?: add a check for form data validity const body = { UserName: registerUserFormGroup.get('username')?.value, Email: registerUserFormGroup.get('email')?.value, @@ -75,7 +61,7 @@ export class UserService { LastName: registerUserFormGroup.get('lastName')?.value, Password: registerUserFormGroup.get('password')?.value }; - return this.http.post(AppConstants.API_USER_REGISTER_URL, body); + return this._http.post(AppConstants.API_USER_REGISTER_URL, body); } getUserRequest(userId: Guid, authToken: string): Observable<object> { @@ -83,26 +69,25 @@ export class UserService { params: new HttpParams().set('Id', userId.toString()), headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) }; - return this.http.get(AppConstants.API_USER_URL, options); + return this._http.get(AppConstants.API_USER_URL, options); } getUserByUsernameRequest(username: string): Observable<object> { const options = { params: new HttpParams().set('UserName', username), }; - return this.http.get(AppConstants.API_USER_URL + '/GetUser', options); + return this._http.get(AppConstants.API_USER_URL + '/GetUser', options); } - putUserRequest(userId: Guid, authToken: string, updateUserFormGroup: FormGroup): Observable<object> { + putUserRequest(userId: Guid, authToken: string, updateUserFormGroup: FormGroup, userRoles: Role[], userFriends: Friend[]): Observable<object> { const body = { UserName: updateUserFormGroup.get('username')?.value, Email: updateUserFormGroup.get('email')?.value, FirstName: updateUserFormGroup.get('firstName')?.value, LastName: updateUserFormGroup.get('lastName')?.value, Password: updateUserFormGroup.get('password')?.value, - // TODO: make the following fields dynamically selectable - Roles: [ { Name: 'User' } ], - Friends: [], + Roles: userRoles, + Friends: userFriends, Languages: updateUserFormGroup.get('languages')?.value, Technologies: updateUserFormGroup.get('technologies')?.value }; @@ -110,7 +95,7 @@ export class UserService { params: new HttpParams().set('Id', userId.toString()), headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) }; - return this.http.put(AppConstants.API_USER_URL, body, options); + return this._http.put(AppConstants.API_USER_URL, body, options); } deleteUserRequest(userId: Guid, authToken: string): Observable<object> { @@ -118,6 +103,6 @@ export class UserService { params: new HttpParams().set('Id', userId.toString()), headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) }; - return this.http.delete(AppConstants.API_USER_URL, options); + return this._http.delete(AppConstants.API_USER_URL, options); } } diff --git a/src/DevHive.Angular/src/models/identity/friend.ts b/src/DevHive.Angular/src/models/identity/friend.ts new file mode 100644 index 0000000..22290cd --- /dev/null +++ b/src/DevHive.Angular/src/models/identity/friend.ts @@ -0,0 +1,3 @@ +export class Friend { + public userName: string; +} diff --git a/src/DevHive.Angular/src/models/identity/role.ts b/src/DevHive.Angular/src/models/identity/role.ts new file mode 100644 index 0000000..132b0b0 --- /dev/null +++ b/src/DevHive.Angular/src/models/identity/role.ts @@ -0,0 +1,3 @@ +export class Role { + public name: string; +} diff --git a/src/DevHive.Angular/src/models/identity/user.ts b/src/DevHive.Angular/src/models/identity/user.ts index c92ed26..020a403 100644 --- a/src/DevHive.Angular/src/models/identity/user.ts +++ b/src/DevHive.Angular/src/models/identity/user.ts @@ -1,14 +1,8 @@ import { Guid } from 'guid-typescript'; - -export class Language { - public id: Guid; - public name: string; -} - -export class Technology { - public id: Guid; - public name: string; -} +import { Language } from '../language'; +import { Technology } from '../technology'; +import { Friend } from './friend'; +import { Role } from './role'; export class User { private _id : Guid; @@ -19,15 +13,19 @@ export class User { private _imageUrl : string; private _languages: Language[]; private _technologies: Technology[]; + private _roles: Role[]; + private _friends: Friend[]; - constructor(id: Guid, userName: string, firstName: string, lastName: string, email: string, imageUrl: string, languages: Language[], technologies: Technology[]) { + constructor(id: Guid, userName: string, firstName: string, lastName: string, email: string, imageUrl: string, languages: Language[], technologies: Technology[], roles: Role[], friends: Friend[]) { this.id = id; this.userName = userName; this.firstName = firstName; this.lastName = lastName; this.email = email; this.imageUrl = imageUrl; + this.languages = languages; this.technologies = technologies; + this.roles = roles; } public get id(): Guid { @@ -85,4 +83,18 @@ export class User { public set technologies(v: Technology[]) { this._technologies = v; } + + public get roles(): Role[] { + return this._roles; + } + public set roles(v: Role[]) { + this._roles = v; + } + + public get friends(): Friend[] { + return this._friends; + } + public set friends(v: Friend[]) { + this._friends = v; + } } diff --git a/src/DevHive.Angular/src/models/language.ts b/src/DevHive.Angular/src/models/language.ts new file mode 100644 index 0000000..e3aa61e --- /dev/null +++ b/src/DevHive.Angular/src/models/language.ts @@ -0,0 +1,6 @@ +import { Guid } from 'guid-typescript'; + +export class Language { + public id: Guid; + public name: string; +} diff --git a/src/DevHive.Angular/src/models/post.ts b/src/DevHive.Angular/src/models/post.ts index 2d7d79f..4c6ac20 100644 --- a/src/DevHive.Angular/src/models/post.ts +++ b/src/DevHive.Angular/src/models/post.ts @@ -1,4 +1,4 @@ -import {Guid} from 'guid-typescript'; +import { Guid } from 'guid-typescript'; export class Post { private _postId: Guid; diff --git a/src/DevHive.Angular/src/models/technology.ts b/src/DevHive.Angular/src/models/technology.ts new file mode 100644 index 0000000..1869d14 --- /dev/null +++ b/src/DevHive.Angular/src/models/technology.ts @@ -0,0 +1,6 @@ +import { Guid } from 'guid-typescript'; + +export class Technology { + public id: Guid; + public name: string; +} diff --git a/src/DevHive.Angular/src/styles.css b/src/DevHive.Angular/src/styles.css index aaa1bd5..2af47c6 100644 --- a/src/DevHive.Angular/src/styles.css +++ b/src/DevHive.Angular/src/styles.css @@ -77,7 +77,8 @@ input:focus, button:focus { border-radius: .4em; background-color: lightgrey; padding: .26em; - margin: 0 .2em; + margin: .1em .2em; + width: fit-content; } /* Inputs, the type found in login and register */ diff --git a/src/DevHive.Data/Repositories/FeedRepository.cs b/src/DevHive.Data/Repositories/FeedRepository.cs index d8170d0..304697d 100644 --- a/src/DevHive.Data/Repositories/FeedRepository.cs +++ b/src/DevHive.Data/Repositories/FeedRepository.cs @@ -25,14 +25,16 @@ namespace DevHive.Data.Repositories List<Post> posts = await this._context.Posts .Where(post => post.TimeCreated < firstRequestIssued) .Where(p => friendsIds.Contains(p.Creator.Id)) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) .ToListAsync(); // Ordering by descending can't happen in query, because it doesn't order it // completely correctly (example: in query these two times are ordered // like this: 2021-01-30T11:49:45, 2021-01-28T21:37:40.701244) - posts = posts.OrderByDescending(x => x.TimeCreated.ToFileTime()).ToList(); + posts = posts + .OrderByDescending(x => x.TimeCreated.ToFileTime()) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToList(); return posts; } @@ -41,12 +43,14 @@ namespace DevHive.Data.Repositories List<Post> posts = await this._context.Posts .Where(post => post.TimeCreated < firstRequestIssued) .Where(p => p.Creator.Id == user.Id) - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) .ToListAsync(); // Look at GetFriendsPosts on why this is done like this - posts = posts.OrderByDescending(x => x.TimeCreated.ToFileTime()).ToList(); + posts = posts + .OrderByDescending(x => x.TimeCreated.ToFileTime()) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToList(); return posts; } } |
