diff --git a/src/backend/src/Controller/AuthController.php b/src/backend/src/Controller/AuthController.php index 602c203..98aaf38 100644 --- a/src/backend/src/Controller/AuthController.php +++ b/src/backend/src/Controller/AuthController.php @@ -6,12 +6,9 @@ use App\Entity\User; use App\Traits\JsonResponseTrait; use App\Repository\UserRepository; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; class AuthController extends AbstractController @@ -23,7 +20,7 @@ class AuthController extends AbstractController } #[Route('/api/register', methods: ["POST"], name: 'register')] - public function register(Request $request, UserPasswordEncoderInterface $encoder) + public function register(Request $request, UserPasswordHasherInterface $encoder) { $em = $this->getDoctrine()->getManager(); $name = $request->get('name'); @@ -41,7 +38,7 @@ class AuthController extends AbstractController } $user = new User(); - $user->setPassword($encoder->encodePassword($user, $password)); + $user->setPassword($encoder->hashPassword($user, $password)); $user->setEmail($email); $user->setName($name); $user->setSurname($surname); @@ -50,9 +47,20 @@ class AuthController extends AbstractController return $this->created($user); } - #[Route('/api/login', methods: ["POST"], name: 'login')] - public function login(Request $request, JWTTokenManagerInterface $JWTManager) + #[Route('/api/login', methods: ['POST'], name: 'login')] + public function login(JWTTokenManagerInterface $JWTManager) { + $user = new User(); return $this->ok(['token' => $JWTManager->create($user)]); } -} \ No newline at end of file + + #[Route('/api/user-check', methods: ['POST'])] + public function checkUser() { + $user = $this->getUser(); + if (!$user) { + return $this->unauthorized([]); + } + $user->generateAvatar(); + return $this->ok($user); + } +} diff --git a/src/backend/src/Entity/User.php b/src/backend/src/Entity/User.php index 1abda34..9046569 100644 --- a/src/backend/src/Entity/User.php +++ b/src/backend/src/Entity/User.php @@ -6,13 +6,14 @@ use Doctrine\ORM\Mapping as ORM; use App\Repository\UserRepository; use App\Entity\Abstraction\BaseEntity; use Symfony\Component\Security\Core\User\UserInterface; +use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; /** * @ORM\Entity(repositoryClass=UserRepository::class) * @ORM\Table(name="`user`") */ -class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUserInterface +class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUserInterface, JWTUserInterface { protected array $hidden = ['password', 'salt', 'userIdentifier', 'username']; @@ -64,6 +65,12 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse */ private $state; + public static function createFromPayload($username, array $payload) + { + $user = new User(); + return $user; + } + public function getId(): ?string { return $this->id; @@ -219,4 +226,10 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse return $this; } + + public function generateAvatar() { + if (!$this->avatar) { + $this->avatar = 'https://www.gravatar.com/avatar/' . md5($this->email) . '?s=514&d=robohash'; + } + } } diff --git a/src/backend/src/Traits/JsonResponseTrait.php b/src/backend/src/Traits/JsonResponseTrait.php index 57751c9..05d03d1 100644 --- a/src/backend/src/Traits/JsonResponseTrait.php +++ b/src/backend/src/Traits/JsonResponseTrait.php @@ -20,6 +20,10 @@ trait JsonResponseTrait { return $this->response([ 'error' => 'Not acceptable', 'data' => $data], $code, $headers); } + protected function unauthorized($data, $code = Response::HTTP_UNAUTHORIZED, $headers = []) { + return $this->response([ 'error' => 'Unauthorized', 'data' => $data], $code, $headers); + } + protected function response($data, $code = Response::HTTP_OK, $headers = []) { if ($data instanceof BaseEntity) { diff --git a/src/frontend/src/app/app.component.html b/src/frontend/src/app/app.component.html index aa96be6..93df4d0 100644 --- a/src/frontend/src/app/app.component.html +++ b/src/frontend/src/app/app.component.html @@ -34,10 +34,9 @@ -
-
+
{{ user.name }} {{ user.surname }}
@@ -53,7 +52,7 @@ {{ 'LANGUAGE.'+lang.toUpperCase() | translate }} - + {{ 'APP.THEME' | translate }} @@ -66,11 +65,10 @@
-
- + diff --git a/src/frontend/src/app/app.component.ts b/src/frontend/src/app/app.component.ts index 8a8b21f..87aea82 100644 --- a/src/frontend/src/app/app.component.ts +++ b/src/frontend/src/app/app.component.ts @@ -7,12 +7,14 @@ import { ThemeService } from './modules/shared/services/theme/theme.service'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { AuthService } from './modules/auth/services/auth/auth.service'; import { Router } from '@angular/router'; +import { UserModel } from './modules/auth/models/user.model'; enum SidebarOpenEnum { Default, Open, Closed, } + @Component({ selector: 'app-root', templateUrl: './app.component.html', @@ -31,11 +33,7 @@ export class AppComponent { themeControl = new FormControl(); langControl = new FormControl(); appRoutes = appRoutes; - user = { - name: 'Name', - surname: 'Surname', - avatar: 'https://www.gravatar.com/avatar/81b206a89f89d5b1123b87606075c6a8?s=514&d=robohash', - }; + user: UserModel; isSidebarHidden = false; dynamicToolbarComponents = []; @@ -43,13 +41,10 @@ export class AppComponent { switch (this.sidebarOpen) { case SidebarOpenEnum.Open: return true; - break; case SidebarOpenEnum.Closed: return false; - break; default: return this.defaultSidebarOpen; - break; } } @@ -65,6 +60,14 @@ export class AppComponent { this.configureThemeEvents(); this.configureLanguageEvents(); this.configureResizeEvents(); + this.configureUserEvents(); + } + + configureUserEvents() { + this.user = this.authService.getUser(); + this.authService.userChange.subscribe(user => { + this.user = user; + }); } configureSidebarEvents() { diff --git a/src/frontend/src/app/modules/auth/components/auth/auth.component.scss b/src/frontend/src/app/modules/auth/components/auth/auth.component.scss index 4e2de62..be1a28c 100644 --- a/src/frontend/src/app/modules/auth/components/auth/auth.component.scss +++ b/src/frontend/src/app/modules/auth/components/auth/auth.component.scss @@ -6,5 +6,4 @@ margin: 0px auto; margin-top: -150px; height: 200px; - border-radius: 6px; } \ No newline at end of file diff --git a/src/frontend/src/app/modules/auth/services/auth/auth.service.ts b/src/frontend/src/app/modules/auth/services/auth/auth.service.ts index f3e2bf4..8d32a41 100644 --- a/src/frontend/src/app/modules/auth/services/auth/auth.service.ts +++ b/src/frontend/src/app/modules/auth/services/auth/auth.service.ts @@ -1,19 +1,47 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; -import { BrowserStorageService } from 'src/app/modules/shared/services/browser-storage/browser-storage.service'; import { LoginModel } from '../../models/login.model'; import { RegisterModel } from '../../models/register.model'; import { TokenResponse } from '../../models/token.response'; import { UserModel } from '../../models/user.model'; import { AuthTokenService } from '../../../shared/services/auth/auth-token.service'; +import { Router } from '@angular/router'; @Injectable() export class AuthService { + + private static updateAgent: any; + private user: UserModel; + public userChange = new Subject(); + constructor( private http: HttpClient, private authTokenService: AuthTokenService, - ) { + private router: Router, + ) { + this.checkUser(); + this.userChange.subscribe(user => { + this.user = user; + }); + } + + getUser(): UserModel { + return this.user; + } + + checkUser() { + this.http.post('/api/user-check', {}).subscribe(user => { + this.userChange.next(user); + if (AuthService.updateAgent) { + clearTimeout(AuthService.updateAgent); + } + AuthService.updateAgent = setTimeout(() => { + this.checkUser(); + }, 2000) as any; + }, () => { + this.logout(); + }); } createAccount(data: RegisterModel): Observable { @@ -27,6 +55,7 @@ export class AuthService { password: data.password, }).subscribe(data => { this.authTokenService.setToken(data.token); + this.checkUser(); out.next(data); }); return out; @@ -34,5 +63,6 @@ export class AuthService { logout() { this.authTokenService.removeToken(); + this.router.navigate(['/auth']); } } diff --git a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html index a8a991b..017680c 100644 --- a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html +++ b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html @@ -1,3 +1,10 @@ -
- {{ 'ERROR.PAGE_NOT_FOUND' | translate }} -
\ No newline at end of file +
+
+
+ +
+ {{ 'ERROR.PAGE_NOT_FOUND' | translate }} +
+
+
+
diff --git a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss index e69de29..3b40699 100644 --- a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss +++ b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss @@ -0,0 +1,10 @@ +.primary-background{ + background-color: var(--toolbar-background); + height: 100px; +} +.content{ + margin: 0px auto; + margin-top: -100px; + height: 200px; + display: flex; +} \ No newline at end of file diff --git a/src/frontend/src/app/modules/shared/models/user.model.ts b/src/frontend/src/app/modules/shared/models/user.model.ts new file mode 100644 index 0000000..7ed8173 --- /dev/null +++ b/src/frontend/src/app/modules/shared/models/user.model.ts @@ -0,0 +1,9 @@ +export class User { + id: number; + email: string; + name: string; + surname: string; + avatar: string; + country: string; + state: string; +} \ No newline at end of file diff --git a/src/frontend/src/app/modules/shared/shared.module.ts b/src/frontend/src/app/modules/shared/shared.module.ts index 344df7e..97bf26b 100644 --- a/src/frontend/src/app/modules/shared/shared.module.ts +++ b/src/frontend/src/app/modules/shared/shared.module.ts @@ -4,6 +4,7 @@ import { NotFoundComponent } from './components/not-found/not-found.component'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { HttpLoaderFactory } from 'src/app/app.module'; import { HttpClient } from '@angular/common/http'; +import { MaterialModule } from '../material/material.module'; @NgModule({ declarations: [ @@ -11,6 +12,7 @@ import { HttpClient } from '@angular/common/http'; ], imports: [ CommonModule, + MaterialModule, TranslateModule.forRoot({ defaultLanguage: 'en', loader: {