Compare commits
7 Commits
dev
...
6-update-d
Author | SHA1 | Date |
---|---|---|
Sieciech | a9d1b94ff4 | |
Sieciech | caae76fbfe | |
Sieciech | 29fcb81928 | |
Sieciech | 4e3cdba411 | |
Sieciech | ba3ec47c67 | |
Sieciech | 42af60cfc8 | |
Sieciech | d00f9489aa |
|
@ -30,36 +30,6 @@
|
||||||
"xdebugSettings": {
|
"xdebugSettings": {
|
||||||
"max_children": 100,
|
"max_children": 100,
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PHP 8.0 CLI",
|
|
||||||
"type": "php",
|
|
||||||
"request": "launch",
|
|
||||||
"pathMappings": {
|
|
||||||
"/web/backend": "${workspaceFolder}\\src\\backend"
|
|
||||||
},
|
|
||||||
"skipFiles": [
|
|
||||||
"${workspaceFolder}/src/backend/vendor/",
|
|
||||||
"/web/backend/vendor/"
|
|
||||||
],
|
|
||||||
"port": 7781,
|
|
||||||
"hostname": "127.0.0.1",
|
|
||||||
"xdebugSettings": {
|
|
||||||
"max_children": 100,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PHP 8.0 CLI with vendor",
|
|
||||||
"type": "php",
|
|
||||||
"request": "launch",
|
|
||||||
"pathMappings": {
|
|
||||||
"/web/backend": "${workspaceFolder}\\src\\backend"
|
|
||||||
},
|
|
||||||
"port": 7781,
|
|
||||||
"hostname": "127.0.0.1",
|
|
||||||
"xdebugSettings": {
|
|
||||||
"max_children": 100,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
|
|
||||||
environment {
|
|
||||||
DatabaseUrl = sh(returnStdout: true, script: 'bash /var/lib/jenkins/variables/CureNet/var.sh ${BRANCH_NAME} DatabaseUrl').trim()
|
|
||||||
ProjectPath = sh(returnStdout: true, script: 'bash /var/lib/jenkins/variables/CureNet/var.sh ${BRANCH_NAME} ProjectPath').trim()
|
|
||||||
DatabaseUrlTesting = sh(returnStdout: true, script: 'bash /var/lib/jenkins/variables/CureNet/var.sh master DatabaseUrl').trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Pull') {
|
|
||||||
steps {
|
|
||||||
git(url: 'http://git.fufle.net/Community/CureNet.git', branch: '${BRANCH_NAME}', credentialsId: '799188a2-c281-4e4c-b78f-c82132ea792b', poll: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Approve') {
|
|
||||||
steps {
|
|
||||||
echo "http://git.fufle.net/Community/CureNet/commit/${env.GIT_COMMIT}"
|
|
||||||
script {
|
|
||||||
if (env.BRANCH_NAME == "prod") {
|
|
||||||
echo "http://git.fufle.net/Community/CureNet/compare/prod...staging"
|
|
||||||
input(message: 'Deploy to production?', id: 'A', ok: 'Yes', submitter: 'deploy', submitterParameter: 'a')
|
|
||||||
}
|
|
||||||
if (env.BRANCH_NAME == "staging") {
|
|
||||||
echo "http://git.fufle.net/Community/CureNet/compare/staging...beta"
|
|
||||||
input(message: 'Deploy to staging instance?', id: 'A', ok: 'Yes', submitter: 'deploy', submitterParameter: 'a')
|
|
||||||
}
|
|
||||||
if (env.BRANCH_NAME == "beta") {
|
|
||||||
echo "http://git.fufle.net/Community/CureNet/compare/beta...dev"
|
|
||||||
input(message: 'Deploy to beta instance?', id: 'A', ok: 'Yes', submitter: 'deploy', submitterParameter: 'a')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Install') {
|
|
||||||
parallel {
|
|
||||||
stage('Frontend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/frontend') {
|
|
||||||
sh 'sed -i "s/-1001/${BUILD_ID}/g" src/environments/*.ts'
|
|
||||||
sh 'Timestamp=`php8.0 -r "echo time();"` && sed -i "s/-1002/${Timestamp}/g" src/environments/*.ts'
|
|
||||||
sh 'npm ci'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Backend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/backend') {
|
|
||||||
sh 'php8.0 /usr/local/bin/composer install'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Configure for tests') {
|
|
||||||
parallel {
|
|
||||||
stage('Frontend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/frontend') {
|
|
||||||
sh 'echo skip'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Backend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/backend') {
|
|
||||||
sh 'APP_SECRET=`php8.0 -r "echo md5(\\"branch=${BRANCH_NAME};\\");"` && sed -i "s/APP_SECRET=.*/APP_SECRET=${APP_SECRET}/g" .env'
|
|
||||||
sh '''sed -i 's/DATABASE_URL=.*/DATABASE_URL=${DatabaseUrlTesting}/g' .env.test'''
|
|
||||||
sh 'php8.0 /usr/local/bin/composer dump-env test'
|
|
||||||
sh 'php8.0 bin/console doctrine:schema:update --force';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Test') {
|
|
||||||
parallel {
|
|
||||||
stage('Frontend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/frontend') {
|
|
||||||
sh 'ng lint'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Backend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/backend') {
|
|
||||||
sh 'php8.0 vendor/bin/phpunit'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Configure') {
|
|
||||||
parallel {
|
|
||||||
stage('Frontend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/frontend') {
|
|
||||||
sh 'echo skip'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Backend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/backend') {
|
|
||||||
sh '''APP_SECRET=`php8.0 -r "echo md5(\\"branch=${BRANCH_NAME};\\");"` && sed -i 's/APP_SECRET=.*/APP_SECRET=${APP_SECRET}/g' .env'''
|
|
||||||
sh '''sed -i 's/DATABASE_URL=.*/DATABASE_URL=${DatabaseUrl}/g' .env.dev'''
|
|
||||||
sh 'php8.0 /usr/local/bin/composer dump-env dev'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Build') {
|
|
||||||
parallel {
|
|
||||||
stage('Frontend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/frontend') {
|
|
||||||
sh 'ng b -c production'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Backend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/backend') {
|
|
||||||
sh 'echo skip'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Deploy') {
|
|
||||||
when {
|
|
||||||
anyOf {
|
|
||||||
branch 'master'
|
|
||||||
branch 'staging'
|
|
||||||
branch 'beta'
|
|
||||||
branch 'dev'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
parallel {
|
|
||||||
stage('Frontend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/frontend') {
|
|
||||||
sh 'ssh web@fufle.net touch ${ProjectPath}/frontend/REMOVEME'
|
|
||||||
sh 'ssh web@fufle.net rm -rf ${ProjectPath}/frontend/*'
|
|
||||||
sh 'scp -r dist/* web@fufle.net:${ProjectPath}/frontend/'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Backend') {
|
|
||||||
steps {
|
|
||||||
dir(path: 'src/backend') {
|
|
||||||
sh 'ssh web@fufle.net touch ${ProjectPath}/backend/REMOVEME'
|
|
||||||
sh 'ssh web@fufle.net rm -rf ${ProjectPath}/backend/*'
|
|
||||||
sh 'scp -r ./* web@fufle.net:${ProjectPath}/backend/'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,7 @@ We also encourage doctors and specialists to join the community, they will have
|
||||||
### Disease analysis
|
### Disease analysis
|
||||||
We want users to have access to the log of their disease where they can enter how it is progressing. On this basis, together with specialists, we will be able to find some common features for new diseases and predict as many negative symptoms as possible in order to be able to prevent them as much as possible.
|
We want users to have access to the log of their disease where they can enter how it is progressing. On this basis, together with specialists, we will be able to find some common features for new diseases and predict as many negative symptoms as possible in order to be able to prevent them as much as possible.
|
||||||
|
|
||||||
[Technical documentation](./src/#technical-documentation)
|
[Technical documentation](./src/#c#technical-documentation)
|
||||||
|
|
||||||
# Polski
|
# Polski
|
||||||
## Czym jest CureNet?
|
## Czym jest CureNet?
|
||||||
|
@ -28,5 +28,5 @@ Zachęcamy także lekarzy i specjalistów, aby dołączyli do społeczności, b
|
||||||
### Analiza chorób
|
### Analiza chorób
|
||||||
Chcemy, aby użytkownicy mieli dostęp do dziennika swojej choroby, gdzie będą mogli wprowadzać jak ona przebiega. Na tej podstawie wraz ze specjalistami będziemy w stanie znaleźć pewne wsólne cechy dla nowych chorób i przewidzieć jak najwięcej negatywnych symptomów, aby móc im jak najlepiej zapobiec.
|
Chcemy, aby użytkownicy mieli dostęp do dziennika swojej choroby, gdzie będą mogli wprowadzać jak ona przebiega. Na tej podstawie wraz ze specjalistami będziemy w stanie znaleźć pewne wsólne cechy dla nowych chorób i przewidzieć jak najwięcej negatywnych symptomów, aby móc im jak najlepiej zapobiec.
|
||||||
|
|
||||||
[Dokumentacja techniczna](./src/#technical-documentation)
|
[Dokumentacja techniczna](./src/#c#technical-documentation)
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ VOLUME /web/backend/vendor
|
||||||
VOLUME /web/backend/var
|
VOLUME /web/backend/var
|
||||||
VOLUME /web/frontend/node_modules
|
VOLUME /web/frontend/node_modules
|
||||||
|
|
||||||
EXPOSE 7700 7780 7781 49153
|
EXPOSE 7700 7780 7781
|
||||||
|
|
||||||
STOPSIGNAL SIGQUIT
|
STOPSIGNAL SIGQUIT
|
||||||
|
|
||||||
|
|
|
@ -4,22 +4,19 @@ services:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- 7700:7700
|
- 7700:7700
|
||||||
- 49153:49153
|
|
||||||
expose:
|
expose:
|
||||||
- 7780:7780
|
- 7780:7780
|
||||||
- 7781:7781
|
- 7781:7781
|
||||||
volumes:
|
volumes:
|
||||||
- .:/web/config
|
- .:/web/config
|
||||||
- ../src/backend:/web/backend:cached
|
- ../src/backend:/web/backend:cached
|
||||||
- type: bind
|
- ../src/frontend:/web/frontend:cached
|
||||||
target: /web/frontend
|
|
||||||
source: ../src/frontend
|
|
||||||
volume:
|
|
||||||
nocopy: true
|
|
||||||
- ./logs:/var/log
|
- ./logs:/var/log
|
||||||
- vendor:/web/backend/vendor
|
- vendor:/web/backend/vendor
|
||||||
- var:/web/backend/var
|
- var:/web/backend/var
|
||||||
|
- nodemodules:/web/frontend/node_modules
|
||||||
volumes:
|
volumes:
|
||||||
nodemodules:
|
nodemodules:
|
||||||
vendor:
|
vendor:
|
||||||
var:
|
var:
|
||||||
|
nodemodules:
|
|
@ -1 +0,0 @@
|
||||||
docker.exe compose -p curenet exec app bash -c 'cd /web && bash'
|
|
|
@ -1,14 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "> Configure cache"
|
|
||||||
mkdir -p /tmp/app/vendor
|
|
||||||
ln -s /tmp/app/vendor /web/backend/vendor
|
|
||||||
|
|
||||||
echo "> Configure user"
|
|
||||||
useradd developer
|
|
||||||
chown developer:developer /web/frontend -R
|
|
||||||
chown developer:developer /web/backend -R
|
|
||||||
|
|
||||||
echo "> Configure logs"
|
echo "> Configure logs"
|
||||||
mkdir -p /var/log/{apache2,nginx,pgadmin,postgresql}
|
mkdir -p /var/log/{apache2,nginx,pgadmin,postgresql}
|
||||||
chown postgres:adm /var/log/postgresql -R
|
chown postgres:adm /var/log/postgresql -R
|
||||||
|
@ -45,14 +36,10 @@ echo "> Configure symfony"
|
||||||
cd /web/backend
|
cd /web/backend
|
||||||
composer install
|
composer install
|
||||||
php bin/console doctrine:schema:update --force
|
php bin/console doctrine:schema:update --force
|
||||||
php php bin/console lexik:jwt:generate-keypair --skip-if-exists
|
|
||||||
|
|
||||||
echo "> Configure angular"
|
echo "> Configure angular"
|
||||||
cd /web/frontend
|
cd /web/frontend
|
||||||
time su developer -c 'npm ci'
|
npm ci
|
||||||
|
|
||||||
echo "> Starting angular"
|
echo "> Starting angular"
|
||||||
su developer -c 'ng serve --disable-host-check --host 0.0.0.0 --poll'
|
ng serve
|
||||||
|
|
||||||
echo "> Waiting"
|
|
||||||
sleep Infinity
|
|
||||||
|
|
|
@ -30,9 +30,3 @@ APP_SECRET=0fc8d6b67b9f1100b3eb3e3c80d36fda
|
||||||
# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
|
# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
|
||||||
DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
|
DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
|
||||||
###< doctrine/doctrine-bundle ###
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
||||||
###> lexik/jwt-authentication-bundle ###
|
|
||||||
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
|
|
||||||
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
|
|
||||||
JWT_PASSPHRASE=8270442e040a48fd42967bf1690d5dba
|
|
||||||
###< lexik/jwt-authentication-bundle ###
|
|
||||||
|
|
|
@ -4,4 +4,3 @@ APP_SECRET='$ecretf0rt3st'
|
||||||
SYMFONY_DEPRECATIONS_HELPER=999999
|
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||||
PANTHER_APP_ENV=panther
|
PANTHER_APP_ENV=panther
|
||||||
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
|
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
|
||||||
DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
|
|
||||||
|
|
|
@ -18,7 +18,3 @@
|
||||||
/phpunit.xml
|
/phpunit.xml
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
###< phpunit/phpunit ###
|
###< phpunit/phpunit ###
|
||||||
|
|
||||||
###> lexik/jwt-authentication-bundle ###
|
|
||||||
/config/jwt/*.pem
|
|
||||||
###< lexik/jwt-authentication-bundle ###
|
|
||||||
|
|
|
@ -12,10 +12,8 @@
|
||||||
"doctrine/doctrine-bundle": "^2.4",
|
"doctrine/doctrine-bundle": "^2.4",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.1",
|
"doctrine/doctrine-migrations-bundle": "^3.1",
|
||||||
"doctrine/orm": "^2.9",
|
"doctrine/orm": "^2.9",
|
||||||
"lexik/jwt-authentication-bundle": "^2.12",
|
|
||||||
"phpdocumentor/reflection-docblock": "^5.2",
|
"phpdocumentor/reflection-docblock": "^5.2",
|
||||||
"sensio/framework-extra-bundle": "^6.1",
|
"sensio/framework-extra-bundle": "^6.1",
|
||||||
"symfony-bundles/json-request-bundle": "^4.0",
|
|
||||||
"symfony/asset": "5.3.*",
|
"symfony/asset": "5.3.*",
|
||||||
"symfony/console": "5.3.*",
|
"symfony/console": "5.3.*",
|
||||||
"symfony/dotenv": "5.3.*",
|
"symfony/dotenv": "5.3.*",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,6 +12,4 @@ return [
|
||||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||||
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
|
|
||||||
SymfonyBundles\JsonRequestBundle\JsonRequestBundle::class => ['all' => true],
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
lexik_jwt_authentication:
|
|
||||||
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
|
|
||||||
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
|
|
||||||
pass_phrase: '%env(JWT_PASSPHRASE)%'
|
|
|
@ -13,29 +13,17 @@ security:
|
||||||
app_user_provider:
|
app_user_provider:
|
||||||
entity:
|
entity:
|
||||||
class: App\Entity\User
|
class: App\Entity\User
|
||||||
property: email
|
property: id
|
||||||
# used to reload user from session & other features (e.g. switch_user)
|
# used to reload user from session & other features (e.g. switch_user)
|
||||||
# used to reload user from session & other features (e.g. switch_user)
|
# used to reload user from session & other features (e.g. switch_user)
|
||||||
firewalls:
|
firewalls:
|
||||||
login:
|
|
||||||
pattern: ^/api/login
|
|
||||||
stateless: true
|
|
||||||
json_login:
|
|
||||||
check_path: /api/login
|
|
||||||
success_handler: lexik_jwt_authentication.handler.authentication_success
|
|
||||||
failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
|
||||||
api:
|
|
||||||
pattern: ^/api
|
|
||||||
stateless: true
|
|
||||||
guard:
|
|
||||||
authenticators:
|
|
||||||
- lexik_jwt_authentication.jwt_token_authenticator
|
|
||||||
dev:
|
dev:
|
||||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||||
security: false
|
security: false
|
||||||
main:
|
main:
|
||||||
lazy: true
|
lazy: true
|
||||||
provider: app_user_provider
|
provider: app_user_provider
|
||||||
|
|
||||||
# activate different ways to authenticate
|
# activate different ways to authenticate
|
||||||
# https://symfony.com/doc/current/security.html#firewalls-authentication
|
# https://symfony.com/doc/current/security.html#firewalls-authentication
|
||||||
|
|
||||||
|
@ -47,6 +35,3 @@ security:
|
||||||
access_control:
|
access_control:
|
||||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||||
# - { path: ^/profile, roles: ROLE_USER }
|
# - { path: ^/profile, roles: ROLE_USER }
|
||||||
# - { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
|
||||||
# - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
|
||||||
# - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
|
|
|
@ -1,3 +0,0 @@
|
||||||
cd ../../docker
|
|
||||||
docker.exe compose -p curenet exec app bash -c 'cd /web/backend && bash'
|
|
||||||
cd src/backend
|
|
|
@ -1,66 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
use App\Entity\User;
|
|
||||||
use App\Traits\JsonResponseTrait;
|
|
||||||
use App\Repository\UserRepository;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|
||||||
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
|
|
||||||
|
|
||||||
class AuthController extends AbstractController
|
|
||||||
{
|
|
||||||
use JsonResponseTrait;
|
|
||||||
|
|
||||||
public function __construct(private UserRepository $userRepository) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/api/register', methods: ["POST"], name: 'register')]
|
|
||||||
public function register(Request $request, UserPasswordHasherInterface $encoder)
|
|
||||||
{
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
$name = $request->get('name');
|
|
||||||
$surname = $request->get('surname');
|
|
||||||
$password = $request->get('password');
|
|
||||||
$email = $request->get('email');
|
|
||||||
|
|
||||||
if (empty($name) || empty($password) || empty($email)){
|
|
||||||
return $this->notAcceptable("Invalid Username or Password or Email");
|
|
||||||
}
|
|
||||||
|
|
||||||
$existing = $this->userRepository->findByEmail($email);
|
|
||||||
if ($existing) {
|
|
||||||
return $this->notAcceptable("User email exists");
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = new User();
|
|
||||||
$user->setPassword($encoder->hashPassword($user, $password));
|
|
||||||
$user->setEmail($email);
|
|
||||||
$user->setName($name);
|
|
||||||
$user->setSurname($surname);
|
|
||||||
$em->persist($user);
|
|
||||||
$em->flush();
|
|
||||||
return $this->created($user);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/api/login', methods: ['POST'], name: 'login')]
|
|
||||||
public function login(JWTTokenManagerInterface $JWTManager)
|
|
||||||
{
|
|
||||||
$user = new User();
|
|
||||||
return $this->ok(['token' => $JWTManager->create($user)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/api/user-check', methods: ['POST'])]
|
|
||||||
public function checkUser() {
|
|
||||||
$user = $this->getUser();
|
|
||||||
if (!$user) {
|
|
||||||
return $this->unauthorized([]);
|
|
||||||
}
|
|
||||||
$user->generateAvatar();
|
|
||||||
return $this->ok($user);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity\Abstraction;
|
|
||||||
|
|
||||||
use ReflectionClass;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
|
||||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
|
||||||
|
|
||||||
class BaseEntity {
|
|
||||||
protected array $hidden = [];
|
|
||||||
protected array $map = [];
|
|
||||||
private array $systemParams = ['hidden', 'map', 'systemParams'];
|
|
||||||
public function toArray() {
|
|
||||||
$output = [];
|
|
||||||
$normalizers = [new ObjectNormalizer()];
|
|
||||||
$serializer = new Serializer($normalizers);
|
|
||||||
$array = $serializer->normalize($this, null);
|
|
||||||
|
|
||||||
$hidden = array_merge($this->hidden, $this->systemParams);
|
|
||||||
foreach ($array as $key => $value) {
|
|
||||||
if (in_array($key, $hidden)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isset($this->map[$key])) {
|
|
||||||
$key = $this->map[$key];
|
|
||||||
}
|
|
||||||
$output[$key] = $value;
|
|
||||||
}
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,21 +2,17 @@
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\Entity\Abstraction\BaseEntity;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
|
||||||
use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface;
|
|
||||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity(repositoryClass=UserRepository::class)
|
* @ORM\Entity(repositoryClass=UserRepository::class)
|
||||||
* @ORM\Table(name="`user`")
|
* @ORM\Table(name="`user`")
|
||||||
*/
|
*/
|
||||||
class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUserInterface, JWTUserInterface
|
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||||
{
|
{
|
||||||
protected array $hidden = ['password', 'salt', 'userIdentifier', 'username'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue
|
* @ORM\GeneratedValue
|
||||||
|
@ -33,44 +29,38 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
|
||||||
* @var string The hashed password
|
* @var string The hashed password
|
||||||
* @ORM\Column(type="string")
|
* @ORM\Column(type="string")
|
||||||
*/
|
*/
|
||||||
private $password;
|
private $password;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=255)
|
* @ORM\Column(type="string", length=255)
|
||||||
*/
|
*/
|
||||||
private $email;
|
private $email;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=255)
|
* @ORM\Column(type="string", length=255)
|
||||||
*/
|
*/
|
||||||
private $name;
|
private $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=255)
|
* @ORM\Column(type="string", length=255)
|
||||||
*/
|
*/
|
||||||
private $surname;
|
private $surname;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=255, nullable=true)
|
* @ORM\Column(type="string", length=255, nullable=true)
|
||||||
*/
|
*/
|
||||||
private $avatar;
|
private $avatar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=3, nullable=true)
|
* @ORM\Column(type="string", length=3, nullable=true)
|
||||||
*/
|
*/
|
||||||
private $country;
|
private $country;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=10, nullable=true)
|
* @ORM\Column(type="string", length=10, nullable=true)
|
||||||
*/
|
*/
|
||||||
private $state;
|
private $state;
|
||||||
|
|
||||||
public static function createFromPayload($username, array $payload)
|
|
||||||
{
|
|
||||||
$user = new User();
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?string
|
public function getId(): ?string
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
|
@ -90,7 +80,7 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
|
||||||
*/
|
*/
|
||||||
public function getUserIdentifier(): string
|
public function getUserIdentifier(): string
|
||||||
{
|
{
|
||||||
return (string) $this->email;
|
return (string) $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,7 +88,7 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
|
||||||
*/
|
*/
|
||||||
public function getUsername(): string
|
public function getUsername(): string
|
||||||
{
|
{
|
||||||
return (string) $this->email;
|
return (string) $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,83 +143,77 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
|
||||||
{
|
{
|
||||||
// If you store any temporary, sensitive data on the user, clear it here
|
// If you store any temporary, sensitive data on the user, clear it here
|
||||||
// $this->plainPassword = null;
|
// $this->plainPassword = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmail(): ?string
|
public function getEmail(): ?string
|
||||||
{
|
{
|
||||||
return $this->email;
|
return $this->email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEmail(string $email): self
|
public function setEmail(string $email): self
|
||||||
{
|
{
|
||||||
$this->email = $email;
|
$this->email = $email;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName(): ?string
|
public function getName(): ?string
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName(string $name): self
|
public function setName(string $name): self
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSurname(): ?string
|
public function getSurname(): ?string
|
||||||
{
|
{
|
||||||
return $this->surname;
|
return $this->surname;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSurname(string $surname): self
|
public function setSurname(string $surname): self
|
||||||
{
|
{
|
||||||
$this->surname = $surname;
|
$this->surname = $surname;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAvatar(): ?string
|
public function getAvatar(): ?string
|
||||||
{
|
{
|
||||||
return $this->avatar;
|
return $this->avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setAvatar(?string $avatar): self
|
public function setAvatar(?string $avatar): self
|
||||||
{
|
{
|
||||||
$this->avatar = $avatar;
|
$this->avatar = $avatar;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCountry(): ?string
|
public function getCountry(): ?string
|
||||||
{
|
{
|
||||||
return $this->country;
|
return $this->country;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCountry(?string $country): self
|
public function setCountry(?string $country): self
|
||||||
{
|
{
|
||||||
$this->country = $country;
|
$this->country = $country;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getState(): ?string
|
public function getState(): ?string
|
||||||
{
|
{
|
||||||
return $this->state;
|
return $this->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setState(?string $state): self
|
public function setState(?string $state): self
|
||||||
{
|
{
|
||||||
$this->state = $state;
|
$this->state = $state;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
|
||||||
|
|
||||||
public function generateAvatar() {
|
|
||||||
if (!$this->avatar) {
|
|
||||||
$this->avatar = 'https://www.gravatar.com/avatar/' . md5($this->email) . '?s=514&d=robohash';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,20 +36,6 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
|
||||||
$this->_em->flush();
|
$this->_em->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return User[] Returns an array of User objects
|
|
||||||
*/
|
|
||||||
public function findByEmail($value)
|
|
||||||
{
|
|
||||||
return $this->createQueryBuilder('u')
|
|
||||||
->andWhere('u.email = :val')
|
|
||||||
->setParameter('val', $value)
|
|
||||||
->setMaxResults(1)
|
|
||||||
->getQuery()
|
|
||||||
->getOneOrNullResult()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * @return User[] Returns an array of User objects
|
// * @return User[] Returns an array of User objects
|
||||||
// */
|
// */
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Traits;
|
|
||||||
|
|
||||||
use App\Entity\Abstraction\BaseEntity;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
||||||
|
|
||||||
trait JsonResponseTrait {
|
|
||||||
protected function ok($data, $code = Response::HTTP_OK, $headers = []) {
|
|
||||||
return $this->response($data, $code, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function created($data, $code = Response::HTTP_CREATED, $headers = []) {
|
|
||||||
return $this->response($data, $code, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function notAcceptable($data, $code = Response::HTTP_NOT_ACCEPTABLE, $headers = []) {
|
|
||||||
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) {
|
|
||||||
$data = $data->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse($data, $code, $headers);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -91,33 +91,12 @@
|
||||||
"laminas/laminas-code": {
|
"laminas/laminas-code": {
|
||||||
"version": "4.4.2"
|
"version": "4.4.2"
|
||||||
},
|
},
|
||||||
"lcobucci/clock": {
|
|
||||||
"version": "2.0.0"
|
|
||||||
},
|
|
||||||
"lcobucci/jwt": {
|
|
||||||
"version": "4.1.4"
|
|
||||||
},
|
|
||||||
"lexik/jwt-authentication-bundle": {
|
|
||||||
"version": "2.5",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "master",
|
|
||||||
"version": "2.5",
|
|
||||||
"ref": "5b2157bcd5778166a5696e42f552ad36529a07a6"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/lexik_jwt_authentication.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"monolog/monolog": {
|
"monolog/monolog": {
|
||||||
"version": "2.3.1"
|
"version": "2.3.1"
|
||||||
},
|
},
|
||||||
"myclabs/deep-copy": {
|
"myclabs/deep-copy": {
|
||||||
"version": "1.10.2"
|
"version": "1.10.2"
|
||||||
},
|
},
|
||||||
"namshi/jose": {
|
|
||||||
"version": "7.2.3"
|
|
||||||
},
|
|
||||||
"nikic/php-parser": {
|
"nikic/php-parser": {
|
||||||
"version": "v4.12.0"
|
"version": "v4.12.0"
|
||||||
},
|
},
|
||||||
|
@ -243,9 +222,6 @@
|
||||||
"config/packages/sensio_framework_extra.yaml"
|
"config/packages/sensio_framework_extra.yaml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"symfony-bundles/json-request-bundle": {
|
|
||||||
"version": "4.0.5"
|
|
||||||
},
|
|
||||||
"symfony/asset": {
|
"symfony/asset": {
|
||||||
"version": "v5.3.2"
|
"version": "v5.3.2"
|
||||||
},
|
},
|
||||||
|
@ -466,9 +442,6 @@
|
||||||
"symfony/polyfill-mbstring": {
|
"symfony/polyfill-mbstring": {
|
||||||
"version": "v1.23.0"
|
"version": "v1.23.0"
|
||||||
},
|
},
|
||||||
"symfony/polyfill-php56": {
|
|
||||||
"version": "v1.20.0"
|
|
||||||
},
|
|
||||||
"symfony/polyfill-php73": {
|
"symfony/polyfill-php73": {
|
||||||
"version": "v1.23.0"
|
"version": "v1.23.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -48,17 +48,7 @@
|
||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.scss",
|
"src/styles.scss"
|
||||||
{
|
|
||||||
"input": "src/app/styles/light.scss",
|
|
||||||
"bundleName": "light",
|
|
||||||
"inject": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"input": "src/app/styles/dark.scss",
|
|
||||||
"bundleName": "dark",
|
|
||||||
"inject": false
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
"vendorChunk": true,
|
"vendorChunk": true,
|
||||||
|
|
|
@ -291,23 +291,6 @@
|
||||||
"tslib": "^2.2.0"
|
"tslib": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/cdk": {
|
|
||||||
"version": "12.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-12.1.3.tgz",
|
|
||||||
"integrity": "sha512-uCWHk/PjddNJsdrmexasphWGbf4kYtYyhUCSd4HEBrIDjYz166MTVSr3FHgn/s8/tlVou7uTnaEZM+ILWoe2iQ==",
|
|
||||||
"requires": {
|
|
||||||
"parse5": "^5.0.0",
|
|
||||||
"tslib": "^2.2.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"parse5": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@angular/cli": {
|
"@angular/cli": {
|
||||||
"version": "12.1.3",
|
"version": "12.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-12.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-12.1.3.tgz",
|
||||||
|
@ -508,14 +491,6 @@
|
||||||
"tslib": "^2.2.0"
|
"tslib": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/material": {
|
|
||||||
"version": "12.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@angular/material/-/material-12.1.3.tgz",
|
|
||||||
"integrity": "sha512-ekkg3MDEN133NhcE0du7a69lFAIFyvK6Va+YRTxYQE0BCNVMTWXtGbOXZLovDMjgo1xdXwrEJrMRBeYo+FIttA==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@angular/platform-browser": {
|
"@angular/platform-browser": {
|
||||||
"version": "12.1.3",
|
"version": "12.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.1.3.tgz",
|
||||||
|
@ -1715,14 +1690,6 @@
|
||||||
"schema-utils": "^2.7.0"
|
"schema-utils": "^2.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ng-stack/forms": {
|
|
||||||
"version": "2.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ng-stack/forms/-/forms-2.4.0.tgz",
|
|
||||||
"integrity": "sha512-Czo4ZbzEcTSAQ8yS4d0PzYMeB8GidOz1ABZhUjwnZiLaNOY2gnIdpQEIqE+GjIVOyusGEjQ/psLneBj8gE2EjQ==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@ngtools/webpack": {
|
"@ngtools/webpack": {
|
||||||
"version": "12.1.3",
|
"version": "12.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-12.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-12.1.3.tgz",
|
||||||
|
@ -1732,22 +1699,6 @@
|
||||||
"enhanced-resolve": "5.8.2"
|
"enhanced-resolve": "5.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ngx-translate/core": {
|
|
||||||
"version": "13.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-13.0.0.tgz",
|
|
||||||
"integrity": "sha512-+tzEp8wlqEnw0Gc7jtVRAJ6RteUjXw6JJR4O65KlnxOmJrCGPI0xjV/lKRnQeU0w4i96PQs/jtpL921Wrb7PWg==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@ngx-translate/http-loader": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-LCekn6qCbeXWlhESCxU1rAbZz33WzDG0lI7Ig0pYC1o5YxJWrkU9y3Y4tNi+jakQ7R6YhTR2D3ox6APxDtA0wA==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@nodelib/fs.scandir": {
|
"@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
|
@ -2774,16 +2725,6 @@
|
||||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"bindings": {
|
|
||||||
"version": "1.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
|
||||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"file-uri-to-path": "1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
|
@ -2878,11 +2819,6 @@
|
||||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"bootstrap": {
|
|
||||||
"version": "5.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.2.tgz",
|
|
||||||
"integrity": "sha512-1Ge963tyEQWJJ+8qtXFU6wgmAVj9gweEjibUdbmcCEYsn38tVwRk8107rk2vzt6cfQcRr3SlZ8aQBqaD8aqf+Q=="
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
@ -5042,13 +4978,6 @@
|
||||||
"escape-string-regexp": "^1.0.5"
|
"escape-string-regexp": "^1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"file-uri-to-path": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"fill-range": {
|
"fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
@ -5146,11 +5075,6 @@
|
||||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"font-awesome": {
|
|
||||||
"version": "4.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
|
|
||||||
"integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
|
|
||||||
},
|
|
||||||
"for-in": {
|
"for-in": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||||
|
@ -7506,13 +7430,6 @@
|
||||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
|
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"nan": {
|
|
||||||
"version": "2.14.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
|
|
||||||
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.1.23",
|
"version": "3.1.23",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||||
|
@ -12682,11 +12599,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true
|
||||||
"requires": {
|
|
||||||
"bindings": "^1.5.0",
|
|
||||||
"nan": "^2.12.1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
|
|
|
@ -12,20 +12,13 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "~12.1.3",
|
"@angular/animations": "~12.1.3",
|
||||||
"@angular/cdk": "^12.1.3",
|
|
||||||
"@angular/common": "~12.1.3",
|
"@angular/common": "~12.1.3",
|
||||||
"@angular/compiler": "~12.1.3",
|
"@angular/compiler": "~12.1.3",
|
||||||
"@angular/core": "~12.1.3",
|
"@angular/core": "~12.1.3",
|
||||||
"@angular/forms": "~12.1.3",
|
"@angular/forms": "~12.1.3",
|
||||||
"@angular/material": "^12.1.3",
|
|
||||||
"@angular/platform-browser": "~12.1.3",
|
"@angular/platform-browser": "~12.1.3",
|
||||||
"@angular/platform-browser-dynamic": "~12.1.3",
|
"@angular/platform-browser-dynamic": "~12.1.3",
|
||||||
"@angular/router": "~12.1.3",
|
"@angular/router": "~12.1.3",
|
||||||
"@ng-stack/forms": "^2.4.0",
|
|
||||||
"@ngx-translate/core": "^13.0.0",
|
|
||||||
"@ngx-translate/http-loader": "^6.0.0",
|
|
||||||
"bootstrap": "^5.0.2",
|
|
||||||
"font-awesome": "^4.7.0",
|
|
||||||
"rxjs": "~6.5.5",
|
"rxjs": "~6.5.5",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"zone.js": "~0.11.4"
|
"zone.js": "~0.11.4"
|
||||||
|
@ -34,9 +27,9 @@
|
||||||
"@angular-devkit/build-angular": "~12.1.3",
|
"@angular-devkit/build-angular": "~12.1.3",
|
||||||
"@angular/cli": "~12.1.3",
|
"@angular/cli": "~12.1.3",
|
||||||
"@angular/compiler-cli": "~12.1.3",
|
"@angular/compiler-cli": "~12.1.3",
|
||||||
|
"@types/node": "^12.11.1",
|
||||||
"@types/jasmine": "~3.6.0",
|
"@types/jasmine": "~3.6.0",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"@types/node": "^12.11.1",
|
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.6.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
cd ../../docker
|
|
||||||
docker.exe compose -p curenet exec app bash -c 'cd /web/frontend && bash'
|
|
||||||
cd ../src/frontend
|
|
|
@ -1,134 +1,10 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Route, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
import { AuthGuard } from './modules/auth/services/auth/auth.guard';
|
|
||||||
import { NotFoundComponent } from './modules/shared/components/not-found/not-found.component';
|
const routes: Routes = [];
|
||||||
|
|
||||||
interface AppMenuEntry {
|
@NgModule({
|
||||||
label: string;
|
imports: [RouterModule.forRoot(routes)],
|
||||||
icon: string;
|
exports: [RouterModule]
|
||||||
path?: string;
|
})
|
||||||
matchExact?: boolean;
|
export class AppRoutingModule { }
|
||||||
level?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AppRoute extends Route {
|
|
||||||
menuEntries?: AppMenuEntry[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const appRoutes: AppRoute[] = [
|
|
||||||
{
|
|
||||||
path: 'auth',
|
|
||||||
loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.HOME',
|
|
||||||
icon: 'fa fa-home',
|
|
||||||
matchExact: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'profile',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.PROFILE',
|
|
||||||
icon: 'fa fa-user',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'community',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.COMMUNITY',
|
|
||||||
icon: 'fa fa-users',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'questions',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.QUESTIONS',
|
|
||||||
icon: 'fa fa-question',
|
|
||||||
level: 1,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'messages',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.MESSAGES',
|
|
||||||
icon: 'fa fa-comments',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tests',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.TESTS',
|
|
||||||
icon: 'fa fa-heartbeat',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'research',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.RESEARCH',
|
|
||||||
icon: 'fa fa-flask',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'admin',
|
|
||||||
loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule),
|
|
||||||
menuEntries: [
|
|
||||||
{
|
|
||||||
label: 'MENU.ADMIN',
|
|
||||||
icon: 'fa fa-id-card',
|
|
||||||
matchExact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'admin/users',
|
|
||||||
label: 'MENU.USERS',
|
|
||||||
icon: 'fa fa-users',
|
|
||||||
level: 1,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
canActivate: [ AuthGuard, ],
|
|
||||||
canActivateChild: [ AuthGuard, ],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forRoot(appRoutes)],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class AppRoutingModule { }
|
|
||||||
|
|
|
@ -1,79 +1 @@
|
||||||
|
<router-outlet></router-outlet>
|
||||||
<ng-template #toolbar>
|
|
||||||
<mat-toolbar class="toolbar-background">
|
|
||||||
<button mat-icon-button (click)="toggleSidebar()" *ngIf="!isSidebarHidden">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</button>
|
|
||||||
<span>{{ 'APP.NAME' | translate }}</span>
|
|
||||||
<span class="flex-grow-1"></span>
|
|
||||||
<div>
|
|
||||||
<div *ngFor="let component of dynamicToolbarComponents">
|
|
||||||
<ng-container [ngComponentOutlet]="component"></ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-toolbar>
|
|
||||||
</ng-template>
|
|
||||||
<ng-container *ngIf="!isMobile">
|
|
||||||
<ng-container *ngTemplateOutlet="toolbar"></ng-container>
|
|
||||||
</ng-container>
|
|
||||||
<mat-drawer-container class="flex-grow-1">
|
|
||||||
<mat-drawer [mode]="sidebarMode" [opened]="isSidebarOpen" (openedChange)="onSidebarOpenedChange($event)" *ngIf="!isSidebarHidden">
|
|
||||||
<div class="menu">
|
|
||||||
<div>
|
|
||||||
<ng-container *ngFor="let route of appRoutes">
|
|
||||||
<ng-container *ngIf="route.menuEntries">
|
|
||||||
<div
|
|
||||||
*ngFor="let menu of route.menuEntries"
|
|
||||||
class="menu-item"
|
|
||||||
[attr.style]="menu.level ? 'margin-left: '+(menu.level * 20)+'px' : ''"
|
|
||||||
[routerLink]="menu.path ? menu.path : route.path"
|
|
||||||
routerLinkActive="active"
|
|
||||||
[routerLinkActiveOptions]="{exact: menu.matchExact}">
|
|
||||||
<i [class]="menu.icon" [title]="menu.label | translate"></i>
|
|
||||||
<span>{{ menu.label | translate }}</span>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="d-flex user-box" *ngIf="user">
|
|
||||||
<div class="avatar" [style.background-image]="url(user.avatar)"></div>
|
|
||||||
<div class="d-flex align-items-center flex-grow-1 p-2">{{ user.name }} {{ user.surname }}</div>
|
|
||||||
<div class="user-menu-container">
|
|
||||||
<div class="user-menu">
|
|
||||||
<button mat-icon-button [matMenuTriggerFor]="usermenu">
|
|
||||||
<i class="fa fa-cog"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<mat-menu #usermenu="matMenu" yPosition="above" xPosition="before" class="w-220">
|
|
||||||
<mat-form-field class="w-100 px-3">
|
|
||||||
<mat-label>{{ 'APP.LANGUAGE' | translate }}</mat-label>
|
|
||||||
<mat-select [formControl]="langControl">
|
|
||||||
<mat-option *ngFor="let lang of langs" [value]="lang">{{ 'LANGUAGE.'+lang.toUpperCase() | translate }}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field class="w-100 px-3">
|
|
||||||
<mat-label>{{ 'APP.THEME' | translate }}</mat-label>
|
|
||||||
<mat-select [formControl]="themeControl">
|
|
||||||
<mat-option *ngFor="let theme of themes" [value]="theme">{{ 'THEME.'+theme.toUpperCase() | translate }}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<button mat-menu-item (click)="logout()">
|
|
||||||
Wyloguj
|
|
||||||
</button>
|
|
||||||
</mat-menu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-drawer>
|
|
||||||
|
|
||||||
<ng-container *ngIf="isMobile">
|
|
||||||
<ng-container *ngTemplateOutlet="toolbar"></ng-container>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<div class="example-sidenav-content">
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
</div>
|
|
||||||
</mat-drawer-container>
|
|
|
@ -1,91 +0,0 @@
|
||||||
$sidebar-width: 250px;
|
|
||||||
:host{
|
|
||||||
position: fixed;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.menu{
|
|
||||||
width: $sidebar-width;
|
|
||||||
flex-grow: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
> :first-child{
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
> * {
|
|
||||||
width: $sidebar-width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.avatar{
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: rgba(0,0,0, 0.25);
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
.menu-item{
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 10px;
|
|
||||||
transition-duration: 400ms !important;
|
|
||||||
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important;
|
|
||||||
transition-property: all !important;
|
|
||||||
&:after{
|
|
||||||
display: block;
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0px;
|
|
||||||
width: 3px;
|
|
||||||
height: 0%;
|
|
||||||
background: var(--primary-color);
|
|
||||||
transition-duration: 400ms !important;
|
|
||||||
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important;
|
|
||||||
transition-property: all !important;
|
|
||||||
}
|
|
||||||
&.active{
|
|
||||||
&:after{
|
|
||||||
top: 0%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-right: 10px;
|
|
||||||
transition: all 0.4s ease;
|
|
||||||
}
|
|
||||||
span{
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-grow: 1;
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.user-box{
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
.user-menu-container{
|
|
||||||
width: 46px;
|
|
||||||
.user-menu{
|
|
||||||
position: absolute;
|
|
||||||
bottom: 6px;
|
|
||||||
right: 6px;
|
|
||||||
height: 48px;
|
|
||||||
width: 46px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,162 +1,10 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormControl } from '@angular/forms';
|
|
||||||
import { appRoutes } from './app-routing.module';
|
@Component({
|
||||||
import { AppService, WindowSize } from './modules/shared/services/app/app.service';
|
selector: 'app-root',
|
||||||
import { BrowserStorageService } from './modules/shared/services/browser-storage/browser-storage.service';
|
templateUrl: './app.component.html',
|
||||||
import { ThemeService } from './modules/shared/services/theme/theme.service';
|
styleUrls: ['./app.component.scss']
|
||||||
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
|
})
|
||||||
import { AuthService } from './modules/auth/services/auth/auth.service';
|
export class AppComponent {
|
||||||
import { Router } from '@angular/router';
|
title = 'CureNet';
|
||||||
import { UserModel } from './modules/auth/models/user.model';
|
}
|
||||||
|
|
||||||
enum SidebarOpenEnum {
|
|
||||||
Default,
|
|
||||||
Open,
|
|
||||||
Closed,
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-root',
|
|
||||||
templateUrl: './app.component.html',
|
|
||||||
styleUrls: ['./app.component.scss']
|
|
||||||
})
|
|
||||||
export class AppComponent {
|
|
||||||
isMobile = true;
|
|
||||||
title = 'CureNet';
|
|
||||||
sidebarOpen = SidebarOpenEnum.Default;
|
|
||||||
sidebarMode = 'over';
|
|
||||||
defaultSidebarOpen = false;
|
|
||||||
lang: string;
|
|
||||||
theme: string;
|
|
||||||
langs: string[] = [];
|
|
||||||
themes: string[] = [];
|
|
||||||
themeControl = new FormControl();
|
|
||||||
langControl = new FormControl();
|
|
||||||
appRoutes = appRoutes;
|
|
||||||
user: UserModel;
|
|
||||||
isSidebarHidden = false;
|
|
||||||
dynamicToolbarComponents = [];
|
|
||||||
|
|
||||||
get isSidebarOpen(): boolean {
|
|
||||||
switch (this.sidebarOpen) {
|
|
||||||
case SidebarOpenEnum.Open:
|
|
||||||
return true;
|
|
||||||
case SidebarOpenEnum.Closed:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return this.defaultSidebarOpen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private appService: AppService,
|
|
||||||
private themeService: ThemeService,
|
|
||||||
private browserStorageService: BrowserStorageService,
|
|
||||||
private sanitizer: DomSanitizer,
|
|
||||||
private authService: AuthService,
|
|
||||||
private router: Router,
|
|
||||||
) {
|
|
||||||
this.configureSidebarEvents();
|
|
||||||
this.configureThemeEvents();
|
|
||||||
this.configureLanguageEvents();
|
|
||||||
this.configureResizeEvents();
|
|
||||||
this.configureUserEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
configureUserEvents(): void {
|
|
||||||
this.user = this.authService.getUser();
|
|
||||||
this.authService.userChange.subscribe(user => {
|
|
||||||
this.user = user;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
configureSidebarEvents(): void {
|
|
||||||
this.isSidebarHidden = this.appService.getSidebarHidden();
|
|
||||||
this.appService.sidebarHiddenChange.subscribe(hidden => {
|
|
||||||
this.isSidebarHidden = hidden;
|
|
||||||
});
|
|
||||||
const sidebarUserPrefference = this.browserStorageService.getItem('sidebar.open');
|
|
||||||
if (sidebarUserPrefference !== null) {
|
|
||||||
this.sidebarOpen = sidebarUserPrefference;
|
|
||||||
}
|
|
||||||
this.appService.dynamicToolbarComponentsChange.subscribe(components => {
|
|
||||||
this.dynamicToolbarComponents = components;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
configureThemeEvents(): void {
|
|
||||||
this.themes = this.themeService.getThemes();
|
|
||||||
this.themeControl.valueChanges.subscribe(theme => {
|
|
||||||
this.themeService.setTheme(theme);
|
|
||||||
});
|
|
||||||
this.onThemeChanged(this.themeService.getTheme());
|
|
||||||
this.themeService.themeChange.subscribe(theme => {
|
|
||||||
this.onThemeChanged(theme);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
configureLanguageEvents(): void {
|
|
||||||
this.langs = this.appService.getLangs();
|
|
||||||
this.lang = this.appService.getLang();
|
|
||||||
|
|
||||||
this.appService.changeLang(this.lang);
|
|
||||||
this.langControl.valueChanges.subscribe(lang => {
|
|
||||||
this.appService.changeLang(lang);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.onLangChanged(this.appService.getLang());
|
|
||||||
this.appService.langChange.subscribe(lang => {
|
|
||||||
this.onLangChanged(lang);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
configureResizeEvents(): void {
|
|
||||||
this.onResize(this.appService.size);
|
|
||||||
this.appService.sizeChange.subscribe(size => {
|
|
||||||
this.onResize(size);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onThemeChanged(theme: string): void {
|
|
||||||
if (theme === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.theme = theme;
|
|
||||||
this.themeControl.setValue(theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
onResize(size: WindowSize): void {
|
|
||||||
if (size === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.isMobile = size.isMobile;
|
|
||||||
this.defaultSidebarOpen = !size.isMobile;
|
|
||||||
this.sidebarMode = this.isMobile ? 'over' : 'side';
|
|
||||||
}
|
|
||||||
|
|
||||||
onLangChanged(lang: string): void {
|
|
||||||
if (lang === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.lang = lang;
|
|
||||||
this.langControl.setValue(lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSidebar(): void {
|
|
||||||
this.sidebarOpen = this.isSidebarOpen ? SidebarOpenEnum.Closed : SidebarOpenEnum.Open;
|
|
||||||
this.browserStorageService.setItem('sidebar.open', this.sidebarOpen);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSidebarOpenedChange(opened: boolean): void {
|
|
||||||
this.sidebarOpen = opened ? SidebarOpenEnum.Open : SidebarOpenEnum.Closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
url(url: string): SafeStyle {
|
|
||||||
return this.sanitizer.bypassSecurityTrustStyle(`url('${url}')`);
|
|
||||||
}
|
|
||||||
|
|
||||||
logout(): void {
|
|
||||||
this.authService.logout();
|
|
||||||
this.router.navigateByUrl('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,53 +1,18 @@
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
||||||
import { MaterialModule } from './modules/material/material.module';
|
@NgModule({
|
||||||
import { AppService } from './modules/shared/services/app/app.service';
|
declarations: [
|
||||||
import { ThemeService } from './modules/shared/services/theme/theme.service';
|
AppComponent
|
||||||
import { BrowserStorageService } from './modules/shared/services/browser-storage/browser-storage.service';
|
],
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
imports: [
|
||||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
BrowserModule,
|
||||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
AppRoutingModule
|
||||||
import { TokenInterceptor } from './modules/shared/interceptors/token/token.interceptor';
|
],
|
||||||
import { AuthTokenService } from './modules/shared/services/auth/auth-token.service';
|
providers: [],
|
||||||
import { AuthService } from './modules/auth/services/auth/auth.service';
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
export class AppModule { }
|
||||||
return new TranslateHttpLoader(http, '/assets/lang/', '.json');
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
|
||||||
AppComponent,
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
AppRoutingModule,
|
|
||||||
BrowserAnimationsModule,
|
|
||||||
MaterialModule,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
HttpClientModule,
|
|
||||||
TranslateModule.forRoot({
|
|
||||||
defaultLanguage: 'en',
|
|
||||||
loader: {
|
|
||||||
provide: TranslateLoader,
|
|
||||||
useFactory: HttpLoaderFactory,
|
|
||||||
deps: [HttpClient]
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
AppService,
|
|
||||||
ThemeService,
|
|
||||||
BrowserStorageService,
|
|
||||||
AuthTokenService,
|
|
||||||
AuthService,
|
|
||||||
{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }
|
|
||||||
],
|
|
||||||
bootstrap: [AppComponent]
|
|
||||||
})
|
|
||||||
export class AppModule { }
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { RouterModule, Route } from '@angular/router';
|
|
||||||
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
|
|
||||||
import { UsersComponent } from './components/users/users.component';
|
|
||||||
|
|
||||||
const routes: Route[] = [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
component: NotFoundComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'users',
|
|
||||||
component: UsersComponent,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forChild(routes)],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class AdminRoutingModule { }
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
|
|
||||||
import { AdminRoutingModule } from './admin-routing.module';
|
|
||||||
import { SharedModule } from '../shared/shared.module';
|
|
||||||
import { UsersComponent } from './components/users/users.component';
|
|
||||||
import { AdminUserService } from './services/admin-user/admin-user.service';
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
|
||||||
UsersComponent
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
AdminRoutingModule,
|
|
||||||
SharedModule,
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
AdminUserService,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class AdminModule { }
|
|
|
@ -1 +0,0 @@
|
||||||
<p>users works!</p>
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { AdminUserService } from '../../services/admin-user/admin-user.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-users',
|
|
||||||
templateUrl: './users.component.html',
|
|
||||||
styleUrls: ['./users.component.scss']
|
|
||||||
})
|
|
||||||
export class UsersComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private adminUserService: AdminUserService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.adminUserService.getUsers().subscribe(() => {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { UserModel } from 'src/app/modules/auth/models/user.model';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AdminUserService {
|
|
||||||
|
|
||||||
constructor(private http: HttpClient) { }
|
|
||||||
|
|
||||||
getUsers(): Observable<UserModel[]> {
|
|
||||||
return this.http.get<UserModel[]>('/api/admin/users');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { RouterModule, Route } from '@angular/router';
|
|
||||||
import { AuthComponent } from './components/auth/auth.component';
|
|
||||||
import { AuthTabEnum } from './enums/auth-tab.enum';
|
|
||||||
|
|
||||||
const routes: Route[] = [
|
|
||||||
{
|
|
||||||
path: AuthTabEnum.Login,
|
|
||||||
component: AuthComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: AuthTabEnum.Register,
|
|
||||||
component: AuthComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: AuthTabEnum.RestorePassword,
|
|
||||||
component: AuthComponent,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: '**',
|
|
||||||
redirectTo: 'login',
|
|
||||||
},
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forChild(routes)],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class AuthRoutingModule { }
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
|
|
||||||
import { AuthRoutingModule } from './auth-routing.module';
|
|
||||||
import { AuthComponent } from './components/auth/auth.component';
|
|
||||||
import { ThemeSwitcherComponent } from './components/theme-switcher/theme-switcher.component';
|
|
||||||
import { MaterialModule } from '../material/material.module';
|
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { AuthService } from './services/auth/auth.service';
|
|
||||||
import { NgStackFormsModule } from '@ng-stack/forms';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
|
||||||
AuthComponent,
|
|
||||||
ThemeSwitcherComponent,
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
AuthRoutingModule,
|
|
||||||
MaterialModule,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
NgStackFormsModule,
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
AuthService,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class AuthModule { }
|
|
|
@ -1,66 +0,0 @@
|
||||||
<div class="primary-background toolbar-background"></div>
|
|
||||||
<div class="col-11 col-lg-7 col-xl-5 p-3 content">
|
|
||||||
<mat-card class="px-0">
|
|
||||||
|
|
||||||
<mat-tab-group mat-align-tabs="center" [selectedIndex]="selectedIndex" (selectedIndexChange)="selectedIndexChange($event)">
|
|
||||||
<mat-tab label="Logowanie">
|
|
||||||
<div [formGroup]="loginForm" class="row align-items-center p-4 m-0">
|
|
||||||
<div class="col-12 col-md-4" required>Email</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Adres email</mat-label>
|
|
||||||
<input formControlName="email" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="col-12 col-md-4" required>Hasło</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Hasło</mat-label>
|
|
||||||
<input formControlName="password" type="password" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="text-end">
|
|
||||||
<button mat-button (click)="selectedIndexChange(getSelectedIndex(AuthTabEnum.RestorePassword))">Odzyskaj hasło</button>
|
|
||||||
<button mat-flat-button color="primary" (click)="login()">Zaloguj</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-tab>
|
|
||||||
<mat-tab label="Rejestracja">
|
|
||||||
<div [formGroup]="registerForm" class="row align-items-center p-4 m-0">
|
|
||||||
<div class="col-12 col-md-4" required>Imię</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Imię</mat-label>
|
|
||||||
<input formControlName="name" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="col-12 col-md-4">Nazwisko</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Nazwisko</mat-label>
|
|
||||||
<input formControlName="surname" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="col-12 col-md-4" required>Email</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Adres email</mat-label>
|
|
||||||
<input formControlName="email" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="col-12 col-md-4" required>Hasło</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Hasło</mat-label>
|
|
||||||
<input formControlName="password" type="password" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="text-end">
|
|
||||||
<button mat-flat-button color="primary" (click)="register()">Zarejestruj</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-tab>
|
|
||||||
<mat-tab label="Odzyskiwanie hasła" *ngIf="selectedIndex === 2">
|
|
||||||
<div [formGroup]="restoreForm" class="row align-items-center p-4 m-0">
|
|
||||||
<div class="col-12 col-md-4" required>Email</div>
|
|
||||||
<mat-form-field class="col-12 col-md-8">
|
|
||||||
<mat-label>Adres email</mat-label>
|
|
||||||
<input formControlName="email" matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="text-end">
|
|
||||||
<button mat-button (click)="selectedIndexChange(getSelectedIndex(AuthTabEnum.Login))">Anuluj</button>
|
|
||||||
<button mat-flat-button color="primary">Odzyskaj hasło</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-tab>
|
|
||||||
</mat-tab-group>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
|
@ -1,9 +0,0 @@
|
||||||
.primary-background{
|
|
||||||
background-color: var(--toolbar-background);
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
.content{
|
|
||||||
margin: 0px auto;
|
|
||||||
margin-top: -150px;
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
import { Location } from '@angular/common';
|
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
||||||
import { ActivatedRoute, Router, UrlSegment } from '@angular/router';
|
|
||||||
import { FormBuilder, FormGroup } from '@ng-stack/forms';
|
|
||||||
import { AppService } from 'src/app/modules/shared/services/app/app.service';
|
|
||||||
import { AuthTabEnum } from '../../enums/auth-tab.enum';
|
|
||||||
import { LoginModel } from '../../models/login.model';
|
|
||||||
import { RegisterModel } from '../../models/register.model';
|
|
||||||
import { RestoreModel } from '../../models/restore.model';
|
|
||||||
import { AuthService } from '../../services/auth/auth.service';
|
|
||||||
import { ThemeSwitcherComponent } from '../theme-switcher/theme-switcher.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-auth',
|
|
||||||
templateUrl: './auth.component.html',
|
|
||||||
styleUrls: ['./auth.component.scss']
|
|
||||||
})
|
|
||||||
export class AuthComponent implements OnInit, OnDestroy {
|
|
||||||
|
|
||||||
registerForm: FormGroup<RegisterModel>;
|
|
||||||
loginForm: FormGroup<LoginModel>;
|
|
||||||
restoreForm: FormGroup<RestoreModel>;
|
|
||||||
tab: AuthTabEnum;
|
|
||||||
selectedIndex: number;
|
|
||||||
defaultTab = AuthTabEnum.Login;
|
|
||||||
tabIndexes = [
|
|
||||||
AuthTabEnum.Login,
|
|
||||||
AuthTabEnum.Register,
|
|
||||||
AuthTabEnum.RestorePassword,
|
|
||||||
];
|
|
||||||
showRestore = false;
|
|
||||||
AuthTabEnum = AuthTabEnum;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private appService: AppService,
|
|
||||||
private authService: AuthService,
|
|
||||||
private activatedRoute: ActivatedRoute,
|
|
||||||
private router: Router,
|
|
||||||
private location: Location,
|
|
||||||
formBuilder: FormBuilder,
|
|
||||||
) {
|
|
||||||
this.registerForm = formBuilder.group<RegisterModel>({
|
|
||||||
name: 'Name',
|
|
||||||
surname: 'Surname',
|
|
||||||
email: 'email@test.com',
|
|
||||||
password: 'password',
|
|
||||||
});
|
|
||||||
this.loginForm = formBuilder.group<LoginModel>({
|
|
||||||
email: 'email@test.com',
|
|
||||||
password: 'password',
|
|
||||||
});
|
|
||||||
this.restoreForm = formBuilder.group<RestoreModel>({
|
|
||||||
email: 'email@test.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
this.handleUrl(activatedRoute.snapshot.url);
|
|
||||||
activatedRoute.url.subscribe(url => {
|
|
||||||
this.handleUrl(url);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleUrl(url: UrlSegment[]): void {
|
|
||||||
const path = url[0].path;
|
|
||||||
this.tab = path as AuthTabEnum;
|
|
||||||
this.selectedIndex = this.getSelectedIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedIndex(tab: AuthTabEnum = null): number {
|
|
||||||
if (tab === null) {
|
|
||||||
tab = this.tab;
|
|
||||||
}
|
|
||||||
let index = this.tabIndexes.findIndex(i => i === tab);
|
|
||||||
if (index === -1) {
|
|
||||||
index = this.tabIndexes.findIndex(i => i === this.defaultTab);
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIndexTab(): AuthTabEnum {
|
|
||||||
return this.tabIndexes[this.selectedIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedIndexChange(index: number): void {
|
|
||||||
this.selectedIndex = index;
|
|
||||||
const tab = this.getIndexTab();
|
|
||||||
const url = this.router.createUrlTree(['..', tab], {
|
|
||||||
relativeTo: this.activatedRoute,
|
|
||||||
}).toString();
|
|
||||||
this.location.go(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.appService.setSidebarHidden(true);
|
|
||||||
this.appService.addDynamicToolbarComponent(ThemeSwitcherComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.appService.setSidebarHidden(false);
|
|
||||||
this.appService.removeDynamicToolbarComponent(ThemeSwitcherComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
register(): void {
|
|
||||||
this.authService.createAccount(this.registerForm.getRawValue()).subscribe(data => {
|
|
||||||
this.loginForm.patchValue({
|
|
||||||
email: this.registerForm.controls.email.value,
|
|
||||||
password: this.registerForm.controls.password.value,
|
|
||||||
});
|
|
||||||
this.selectedIndexChange(this.getSelectedIndex(AuthTabEnum.Login));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
login(): void {
|
|
||||||
this.authService.login(this.loginForm.getRawValue()).subscribe(data => {
|
|
||||||
const afterUrl = '/';
|
|
||||||
this.router.navigateByUrl(afterUrl);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
<button mat-icon-button (click)="toggleTheme()">
|
|
||||||
<i class="fa" [class.fa-sun-o]="isDark" [class.fa-moon-o]="!isDark"></i>
|
|
||||||
</button>
|
|
|
@ -1,32 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { ThemeService } from 'src/app/modules/shared/services/theme/theme.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-theme-switcher',
|
|
||||||
templateUrl: './theme-switcher.component.html',
|
|
||||||
styleUrls: ['./theme-switcher.component.scss']
|
|
||||||
})
|
|
||||||
export class ThemeSwitcherComponent implements OnInit {
|
|
||||||
|
|
||||||
isDark = false;
|
|
||||||
darkTheme = 'dark';
|
|
||||||
lightTheme = 'light';
|
|
||||||
theme = 'light';
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private themeService: ThemeService,
|
|
||||||
) {
|
|
||||||
this.theme = themeService.getTheme();
|
|
||||||
themeService.themeChange.subscribe(theme => {
|
|
||||||
this.theme = theme;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleTheme(): void {
|
|
||||||
this.themeService.setTheme(this.theme === this.darkTheme ? this.lightTheme : this.darkTheme);
|
|
||||||
this.isDark = this.theme === this.darkTheme;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
export enum AuthTabEnum {
|
|
||||||
Login = 'login',
|
|
||||||
Register = 'register',
|
|
||||||
RestorePassword = 'restore-password',
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
export interface LoginModel {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
export interface RegisterModel {
|
|
||||||
name: string;
|
|
||||||
surname: string;
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface RestoreModel {
|
|
||||||
email: string;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface TokenResponse {
|
|
||||||
token: string;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
export interface UserModel {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
surname: string;
|
|
||||||
avatar: string | null;
|
|
||||||
country: string | null;
|
|
||||||
state: string | null;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { AuthTokenService } from 'src/app/modules/shared/services/auth/auth-token.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class AuthGuard implements CanActivate, CanActivateChild {
|
|
||||||
constructor(private authTokenService: AuthTokenService, private router: Router) {
|
|
||||||
|
|
||||||
}
|
|
||||||
canActivate(
|
|
||||||
route: ActivatedRouteSnapshot,
|
|
||||||
state: RouterStateSnapshot,
|
|
||||||
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
|
||||||
const can = this.authTokenService.userValidate();
|
|
||||||
if (!can){
|
|
||||||
this.router.navigate(['/auth']);
|
|
||||||
}
|
|
||||||
return can;
|
|
||||||
}
|
|
||||||
|
|
||||||
canActivateChild(
|
|
||||||
childRoute: ActivatedRouteSnapshot,
|
|
||||||
state: RouterStateSnapshot,
|
|
||||||
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
|
||||||
const can = this.authTokenService.userValidate();
|
|
||||||
if (!can){
|
|
||||||
this.router.navigate(['/auth']);
|
|
||||||
}
|
|
||||||
return can;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Observable, Subject } from 'rxjs';
|
|
||||||
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<UserModel>();
|
|
||||||
|
|
||||||
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(): void {
|
|
||||||
this.http.post<UserModel>('/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<UserModel> {
|
|
||||||
return this.http.post<UserModel>('/api/register', data);
|
|
||||||
}
|
|
||||||
|
|
||||||
login(data: LoginModel): Observable<TokenResponse> {
|
|
||||||
const out = new Subject<TokenResponse>();
|
|
||||||
this.http.post<TokenResponse>('/api/login', {
|
|
||||||
username: data.email,
|
|
||||||
password: data.password,
|
|
||||||
}).subscribe(response => {
|
|
||||||
this.authTokenService.setToken(response.token);
|
|
||||||
this.checkUser();
|
|
||||||
out.next(response);
|
|
||||||
});
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
logout(): void {
|
|
||||||
this.authTokenService.removeToken();
|
|
||||||
this.router.navigate(['/auth']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import {MatToolbarModule} from '@angular/material/toolbar';
|
|
||||||
import {MatButtonModule} from '@angular/material/button';
|
|
||||||
import {MatSidenavModule} from '@angular/material/sidenav';
|
|
||||||
import {MatSelectModule} from '@angular/material/select';
|
|
||||||
import {MatMenuModule} from '@angular/material/menu';
|
|
||||||
import {MatCardModule} from '@angular/material/card';
|
|
||||||
import {MatTabsModule} from '@angular/material/tabs';
|
|
||||||
import {MatInputModule} from '@angular/material/input';
|
|
||||||
|
|
||||||
const itemsToExport = [
|
|
||||||
MatToolbarModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatSidenavModule,
|
|
||||||
MatSelectModule,
|
|
||||||
MatMenuModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatTabsModule,
|
|
||||||
MatInputModule,
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
...itemsToExport,
|
|
||||||
],
|
|
||||||
exports: [
|
|
||||||
...itemsToExport,
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class MaterialModule { }
|
|
|
@ -1,10 +0,0 @@
|
||||||
<div class="primary-background toolbar-background"></div>
|
|
||||||
<div class="content align-items-center justify-content-center">
|
|
||||||
<div class="col-11 col-lg-7 col-xl-5">
|
|
||||||
<mat-card>
|
|
||||||
<div class="m-3 p-3">
|
|
||||||
{{ 'ERROR.PAGE_NOT_FOUND' | translate }}
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
.primary-background{
|
|
||||||
background-color: var(--toolbar-background);
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
.content{
|
|
||||||
margin: 0px auto;
|
|
||||||
margin-top: -100px;
|
|
||||||
height: 200px;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-not-found',
|
|
||||||
templateUrl: './not-found.component.html',
|
|
||||||
styleUrls: ['./not-found.component.scss']
|
|
||||||
})
|
|
||||||
export class NotFoundComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { AuthTokenService } from 'src/app/modules/shared/services/auth/auth-token.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class TokenInterceptor implements HttpInterceptor {
|
|
||||||
|
|
||||||
constructor(private authTokenService: AuthTokenService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
|
||||||
if (this.authTokenService.hasToken()) {
|
|
||||||
const Authorization = `Bearer ${this.authTokenService.getToken()}`;
|
|
||||||
return next.handle(httpRequest.clone({ setHeaders: { Authorization } }));
|
|
||||||
}
|
|
||||||
return next.handle(httpRequest);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
export class User {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
name: string;
|
|
||||||
surname: string;
|
|
||||||
avatar: string;
|
|
||||||
country: string;
|
|
||||||
state: string;
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
import { fromEvent, Subject } from 'rxjs';
|
|
||||||
import { BrowserStorageService } from '../browser-storage/browser-storage.service';
|
|
||||||
|
|
||||||
export class WindowSize {
|
|
||||||
isMobile: boolean;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public width: number,
|
|
||||||
public height: number,
|
|
||||||
) {
|
|
||||||
this.isMobile = this.width <= 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
static generate(): WindowSize {
|
|
||||||
return new WindowSize(window.innerWidth, window.innerHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(): WindowSize {
|
|
||||||
this.width = window.innerWidth;
|
|
||||||
this.height = window.innerHeight;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AppService {
|
|
||||||
private sidebarHidden = false;
|
|
||||||
private lang = 'en';
|
|
||||||
private defaultLang = 'en';
|
|
||||||
private dynamicToolbarComponents = [];
|
|
||||||
langChange = new Subject<string>();
|
|
||||||
size: WindowSize;
|
|
||||||
sizeChange = new Subject<WindowSize>();
|
|
||||||
sidebarHiddenChange = new Subject<boolean>();
|
|
||||||
dynamicToolbarComponentsChange = new Subject<any[]>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private browserStorageService: BrowserStorageService,
|
|
||||||
private translate: TranslateService,
|
|
||||||
) {
|
|
||||||
this.configureResizeEvents();
|
|
||||||
this.configureLanguageEvents();
|
|
||||||
this.configureSidebarEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
configureSidebarEvents(): void {
|
|
||||||
this.sidebarHiddenChange.subscribe(hidden => {
|
|
||||||
this.sidebarHidden = hidden;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
configureResizeEvents(): void {
|
|
||||||
this.sizeChange.subscribe(size => this.size = size);
|
|
||||||
this.sizeChange.next(WindowSize.generate());
|
|
||||||
fromEvent(window, 'resize').subscribe(e => {
|
|
||||||
this.sizeChange.next(WindowSize.generate());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
configureLanguageEvents(): void {
|
|
||||||
this.langChange.subscribe(lang => {
|
|
||||||
this.lang = lang;
|
|
||||||
this.browserStorageService.setItem('language', lang);
|
|
||||||
});
|
|
||||||
let language = this.browserStorageService.getItem('language');
|
|
||||||
if (!language) {
|
|
||||||
language = this.defaultLang;
|
|
||||||
}
|
|
||||||
this.translate.setDefaultLang(this.defaultLang);
|
|
||||||
this.changeLang(language);
|
|
||||||
}
|
|
||||||
|
|
||||||
addDynamicToolbarComponent(component): void {
|
|
||||||
this.dynamicToolbarComponents.push(component);
|
|
||||||
this.dynamicToolbarComponentsChange.next(this.dynamicToolbarComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeDynamicToolbarComponent(component): void {
|
|
||||||
this.dynamicToolbarComponents = this.dynamicToolbarComponents.filter(c => c !== component);
|
|
||||||
this.dynamicToolbarComponentsChange.next(this.dynamicToolbarComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSidebarHidden(hidden: boolean): void {
|
|
||||||
this.sidebarHiddenChange.next(hidden);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSidebarHidden(): boolean {
|
|
||||||
return this.sidebarHidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
changeLang(lang: string): void {
|
|
||||||
if (lang !== this.lang) {
|
|
||||||
this.translate.use(lang);
|
|
||||||
this.langChange.next(lang);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getLang(): string {
|
|
||||||
return this.lang;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLangs(): string[] {
|
|
||||||
return [
|
|
||||||
'pl',
|
|
||||||
'en',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { BrowserStorageService } from 'src/app/modules/shared/services/browser-storage/browser-storage.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AuthTokenService {
|
|
||||||
private TokenKey = 'jwt.token';
|
|
||||||
|
|
||||||
constructor( private browserStorageService: BrowserStorageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
setToken(token: string): void {
|
|
||||||
this.browserStorageService.setItem(this.TokenKey, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasToken(): boolean {
|
|
||||||
const token = this.browserStorageService.getItemOrDefault(this.TokenKey, null);
|
|
||||||
return token !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getToken(): string {
|
|
||||||
return this.browserStorageService.getItem(this.TokenKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeToken(): void {
|
|
||||||
this.browserStorageService.setItem(this.TokenKey, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
userValidate(): boolean {
|
|
||||||
if (!this.hasToken()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class BrowserStorageService {
|
|
||||||
|
|
||||||
private storage: Storage;
|
|
||||||
private namespace: string;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.storage = localStorage;
|
|
||||||
this.namespace = 'default';
|
|
||||||
}
|
|
||||||
|
|
||||||
setNamespace(namespace: string): void {
|
|
||||||
this.namespace = namespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
getNamespace(namespace: string | null = null): string {
|
|
||||||
return namespace ?? this.namespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
setItem(key: string, value: any, namespace: string | null = null): void {
|
|
||||||
namespace = this.getNamespace(namespace);
|
|
||||||
const path = `${namespace}.${key}`;
|
|
||||||
this.storage.setItem(path, JSON.stringify(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
getItem(key: string, namespace: string | null = null): any {
|
|
||||||
namespace = this.getNamespace(namespace);
|
|
||||||
const path = `${namespace}.${key}`;
|
|
||||||
return JSON.parse(this.storage.getItem(path) ?? 'null');
|
|
||||||
}
|
|
||||||
|
|
||||||
getItemOrDefault(key: string, defaultValue: any, namespace: string | null = null): any {
|
|
||||||
return this.getItem(key, namespace) ?? defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { BrowserStorageService } from '../browser-storage/browser-storage.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ThemeService {
|
|
||||||
private theme: string;
|
|
||||||
themeChange = new Subject<string>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
browserStorageService: BrowserStorageService
|
|
||||||
) {
|
|
||||||
this.themeChange.subscribe(theme => {
|
|
||||||
this.theme = theme;
|
|
||||||
browserStorageService.setItem('current-theme', theme);
|
|
||||||
});
|
|
||||||
let userTheme = browserStorageService.getItem('current-theme');
|
|
||||||
if (!userTheme) {
|
|
||||||
userTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
||||||
}
|
|
||||||
this.setTheme(userTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTheme(): string {
|
|
||||||
return this.theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTheme(theme: string): void {
|
|
||||||
if (theme !== this.theme) {
|
|
||||||
this.themeChange.next(theme);
|
|
||||||
document.getElementById('current-theme').setAttribute('href', `/${theme}.css`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getThemes(): string[] {
|
|
||||||
return [
|
|
||||||
'light',
|
|
||||||
'dark',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
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: [
|
|
||||||
NotFoundComponent
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
MaterialModule,
|
|
||||||
TranslateModule.forRoot({
|
|
||||||
defaultLanguage: 'en',
|
|
||||||
loader: {
|
|
||||||
provide: TranslateLoader,
|
|
||||||
useFactory: HttpLoaderFactory,
|
|
||||||
deps: [HttpClient]
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class SharedModule { }
|
|
|
@ -1,38 +0,0 @@
|
||||||
@use 'sass:map';
|
|
||||||
|
|
||||||
$primary-color: map.get($theme, color, primary, 500);
|
|
||||||
$toolbar-background: map.get($theme, color, background, app-bar);
|
|
||||||
$toolbar-color: map.get($theme, color, primary, contrast, 500) !default;
|
|
||||||
$main-background: map.get($theme, color, background, background) !default;
|
|
||||||
$warn-color: map.get($theme, warn, 500) !default;
|
|
||||||
body {
|
|
||||||
--primary-color: #{$primary-color};
|
|
||||||
--toolbar-background: #{$toolbar-background};
|
|
||||||
--toolbar-color: #{$toolbar-color};
|
|
||||||
--main-background: #{$main-background};
|
|
||||||
--warn-color: #{$warn-color};
|
|
||||||
.mat-toolbar{
|
|
||||||
background-color: var(--toolbar-background);
|
|
||||||
color: var(--toolbar-color);
|
|
||||||
}
|
|
||||||
.toolbar-background{
|
|
||||||
position: relative;
|
|
||||||
& > *{
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
&:before{
|
|
||||||
position: absolute;
|
|
||||||
z-index: 0;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
width:100%;
|
|
||||||
height: 100%;
|
|
||||||
content: "";
|
|
||||||
opacity: 0.125;
|
|
||||||
background-image: url('/assets/background/items.png');
|
|
||||||
background-position: top;
|
|
||||||
background-attachment: fixed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,398 +0,0 @@
|
||||||
$theme: (
|
|
||||||
color: (
|
|
||||||
primary: (
|
|
||||||
50: #e8eaf6,
|
|
||||||
100: #c5cae9,
|
|
||||||
200: #9fa8da,
|
|
||||||
300: #7986cb,
|
|
||||||
400: #5c6bc0,
|
|
||||||
500: #3f51b5,
|
|
||||||
600: #3949ab,
|
|
||||||
700: #303f9f,
|
|
||||||
800: #283593,
|
|
||||||
900: #1a237e,
|
|
||||||
A100: #8c9eff,
|
|
||||||
A200: #536dfe,
|
|
||||||
A400: #3d5afe,
|
|
||||||
A700: #304ffe,
|
|
||||||
contrast: (
|
|
||||||
50: rgba(0, 0, 0, 0.87),
|
|
||||||
100: rgba(0, 0, 0, 0.87),
|
|
||||||
200: rgba(0, 0, 0, 0.87),
|
|
||||||
300: white,
|
|
||||||
400: white,
|
|
||||||
500: white,
|
|
||||||
600: white,
|
|
||||||
700: white,
|
|
||||||
800: white,
|
|
||||||
900: white,
|
|
||||||
A100: rgba(0, 0, 0, 0.87),
|
|
||||||
A200: white,
|
|
||||||
A400: white,
|
|
||||||
A700: white,
|
|
||||||
),
|
|
||||||
default: #3f51b5,
|
|
||||||
lighter: #c5cae9,
|
|
||||||
darker: #303f9f,
|
|
||||||
text: #3f51b5,
|
|
||||||
default-contrast: white,
|
|
||||||
lighter-contrast: rgba(0, 0, 0, 0.87),
|
|
||||||
darker-contrast: white,
|
|
||||||
"50-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"200-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"300-contrast": white,
|
|
||||||
"400-contrast": white,
|
|
||||||
"500-contrast": white,
|
|
||||||
"600-contrast": white,
|
|
||||||
"700-contrast": white,
|
|
||||||
"800-contrast": white,
|
|
||||||
"900-contrast": white,
|
|
||||||
"A100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"A200-contrast": white,
|
|
||||||
"A400-contrast": white,
|
|
||||||
"A700-contrast": white,
|
|
||||||
"contrast-contrast": null,
|
|
||||||
),
|
|
||||||
accent: (
|
|
||||||
50: #fce4ec,
|
|
||||||
100: #f8bbd0,
|
|
||||||
200: #f48fb1,
|
|
||||||
300: #f06292,
|
|
||||||
400: #ec407a,
|
|
||||||
500: #e91e63,
|
|
||||||
600: #d81b60,
|
|
||||||
700: #c2185b,
|
|
||||||
800: #ad1457,
|
|
||||||
900: #880e4f,
|
|
||||||
A100: #ff80ab,
|
|
||||||
A200: #ff4081,
|
|
||||||
A400: #f50057,
|
|
||||||
A700: #c51162,
|
|
||||||
contrast: (
|
|
||||||
50: rgba(0, 0, 0, 0.87),
|
|
||||||
100: rgba(0, 0, 0, 0.87),
|
|
||||||
200: rgba(0, 0, 0, 0.87),
|
|
||||||
300: rgba(0, 0, 0, 0.87),
|
|
||||||
400: rgba(0, 0, 0, 0.87),
|
|
||||||
500: white,
|
|
||||||
600: white,
|
|
||||||
700: white,
|
|
||||||
800: white,
|
|
||||||
900: white,
|
|
||||||
A100: rgba(0, 0, 0, 0.87),
|
|
||||||
A200: white,
|
|
||||||
A400: white,
|
|
||||||
A700: white,
|
|
||||||
),
|
|
||||||
default: #ff4081,
|
|
||||||
lighter: #ff80ab,
|
|
||||||
darker: #f50057,
|
|
||||||
text: #ff4081,
|
|
||||||
default-contrast: white,
|
|
||||||
lighter-contrast: rgba(0, 0, 0, 0.87),
|
|
||||||
darker-contrast: white,
|
|
||||||
"50-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"200-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"300-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"400-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"500-contrast": white,
|
|
||||||
"600-contrast": white,
|
|
||||||
"700-contrast": white,
|
|
||||||
"800-contrast": white,
|
|
||||||
"900-contrast": white,
|
|
||||||
"A100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"A200-contrast": white,
|
|
||||||
"A400-contrast": white,
|
|
||||||
"A700-contrast": white,
|
|
||||||
"contrast-contrast": null,
|
|
||||||
),
|
|
||||||
warn: (
|
|
||||||
50: #ffebee,
|
|
||||||
100: #ffcdd2,
|
|
||||||
200: #ef9a9a,
|
|
||||||
300: #e57373,
|
|
||||||
400: #ef5350,
|
|
||||||
500: #f44336,
|
|
||||||
600: #e53935,
|
|
||||||
700: #d32f2f,
|
|
||||||
800: #c62828,
|
|
||||||
900: #b71c1c,
|
|
||||||
A100: #ff8a80,
|
|
||||||
A200: #ff5252,
|
|
||||||
A400: #ff1744,
|
|
||||||
A700: #d50000,
|
|
||||||
contrast: (
|
|
||||||
50: rgba(0, 0, 0, 0.87),
|
|
||||||
100: rgba(0, 0, 0, 0.87),
|
|
||||||
200: rgba(0, 0, 0, 0.87),
|
|
||||||
300: rgba(0, 0, 0, 0.87),
|
|
||||||
400: rgba(0, 0, 0, 0.87),
|
|
||||||
500: white,
|
|
||||||
600: white,
|
|
||||||
700: white,
|
|
||||||
800: white,
|
|
||||||
900: white,
|
|
||||||
A100: rgba(0, 0, 0, 0.87),
|
|
||||||
A200: white,
|
|
||||||
A400: white,
|
|
||||||
A700: white,
|
|
||||||
),
|
|
||||||
default: #f44336,
|
|
||||||
lighter: #ffcdd2,
|
|
||||||
darker: #d32f2f,
|
|
||||||
text: #f44336,
|
|
||||||
default-contrast: white,
|
|
||||||
lighter-contrast: rgba(0, 0, 0, 0.87),
|
|
||||||
darker-contrast: white,
|
|
||||||
"50-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"200-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"300-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"400-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"500-contrast": white,
|
|
||||||
"600-contrast": white,
|
|
||||||
"700-contrast": white,
|
|
||||||
"800-contrast": white,
|
|
||||||
"900-contrast": white,
|
|
||||||
"A100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"A200-contrast": white,
|
|
||||||
"A400-contrast": white,
|
|
||||||
"A700-contrast": white,
|
|
||||||
"contrast-contrast": null,
|
|
||||||
),
|
|
||||||
is-dark: true,
|
|
||||||
foreground: (
|
|
||||||
base: white,
|
|
||||||
divider: rgba(255, 255, 255, 0.12),
|
|
||||||
dividers: rgba(255, 255, 255, 0.12),
|
|
||||||
disabled: rgba(255, 255, 255, 0.5),
|
|
||||||
disabled-button: rgba(255, 255, 255, 0.3),
|
|
||||||
disabled-text: rgba(255, 255, 255, 0.5),
|
|
||||||
elevation: black,
|
|
||||||
hint-text: rgba(255, 255, 255, 0.5),
|
|
||||||
secondary-text: rgba(255, 255, 255, 0.7),
|
|
||||||
icon: white,
|
|
||||||
icons: white,
|
|
||||||
text: white,
|
|
||||||
slider-min: white,
|
|
||||||
slider-off: rgba(255, 255, 255, 0.3),
|
|
||||||
slider-off-active: rgba(255, 255, 255, 0.3),
|
|
||||||
),
|
|
||||||
background: (
|
|
||||||
status-bar: black,
|
|
||||||
app-bar: #212121,
|
|
||||||
background: #303030,
|
|
||||||
hover: rgba(255, 255, 255, 0.04),
|
|
||||||
card: #424242,
|
|
||||||
dialog: #424242,
|
|
||||||
disabled-button: rgba(255, 255, 255, 0.12),
|
|
||||||
raised-button: #424242,
|
|
||||||
focused-button: rgba(255, 255, 255, 0.12),
|
|
||||||
selected-button: #212121,
|
|
||||||
selected-disabled-button: #424242,
|
|
||||||
disabled-button-toggle: black,
|
|
||||||
unselected-chip: #616161,
|
|
||||||
disabled-list-option: black,
|
|
||||||
tooltip: #616161,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
primary: (
|
|
||||||
50: #e8eaf6,
|
|
||||||
100: #c5cae9,
|
|
||||||
200: #9fa8da,
|
|
||||||
300: #7986cb,
|
|
||||||
400: #5c6bc0,
|
|
||||||
500: #3f51b5,
|
|
||||||
600: #3949ab,
|
|
||||||
700: #303f9f,
|
|
||||||
800: #283593,
|
|
||||||
900: #1a237e,
|
|
||||||
A100: #8c9eff,
|
|
||||||
A200: #536dfe,
|
|
||||||
A400: #3d5afe,
|
|
||||||
A700: #304ffe,
|
|
||||||
contrast: (
|
|
||||||
50: rgba(0, 0, 0, 0.87),
|
|
||||||
100: rgba(0, 0, 0, 0.87),
|
|
||||||
200: rgba(0, 0, 0, 0.87),
|
|
||||||
300: white,
|
|
||||||
400: white,
|
|
||||||
500: white,
|
|
||||||
600: white,
|
|
||||||
700: white,
|
|
||||||
800: white,
|
|
||||||
900: white,
|
|
||||||
A100: rgba(0, 0, 0, 0.87),
|
|
||||||
A200: white,
|
|
||||||
A400: white,
|
|
||||||
A700: white,
|
|
||||||
),
|
|
||||||
default: #3f51b5,
|
|
||||||
lighter: #c5cae9,
|
|
||||||
darker: #303f9f,
|
|
||||||
text: #3f51b5,
|
|
||||||
default-contrast: white,
|
|
||||||
lighter-contrast: rgba(0, 0, 0, 0.87),
|
|
||||||
darker-contrast: white,
|
|
||||||
"50-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"200-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"300-contrast": white,
|
|
||||||
"400-contrast": white,
|
|
||||||
"500-contrast": white,
|
|
||||||
"600-contrast": white,
|
|
||||||
"700-contrast": white,
|
|
||||||
"800-contrast": white,
|
|
||||||
"900-contrast": white,
|
|
||||||
"A100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"A200-contrast": white,
|
|
||||||
"A400-contrast": white,
|
|
||||||
"A700-contrast": white,
|
|
||||||
"contrast-contrast": null,
|
|
||||||
),
|
|
||||||
accent: (
|
|
||||||
50: #fce4ec,
|
|
||||||
100: #f8bbd0,
|
|
||||||
200: #f48fb1,
|
|
||||||
300: #f06292,
|
|
||||||
400: #ec407a,
|
|
||||||
500: #e91e63,
|
|
||||||
600: #d81b60,
|
|
||||||
700: #c2185b,
|
|
||||||
800: #ad1457,
|
|
||||||
900: #880e4f,
|
|
||||||
A100: #ff80ab,
|
|
||||||
A200: #ff4081,
|
|
||||||
A400: #f50057,
|
|
||||||
A700: #c51162,
|
|
||||||
contrast: (
|
|
||||||
50: rgba(0, 0, 0, 0.87),
|
|
||||||
100: rgba(0, 0, 0, 0.87),
|
|
||||||
200: rgba(0, 0, 0, 0.87),
|
|
||||||
300: rgba(0, 0, 0, 0.87),
|
|
||||||
400: rgba(0, 0, 0, 0.87),
|
|
||||||
500: white,
|
|
||||||
600: white,
|
|
||||||
700: white,
|
|
||||||
800: white,
|
|
||||||
900: white,
|
|
||||||
A100: rgba(0, 0, 0, 0.87),
|
|
||||||
A200: white,
|
|
||||||
A400: white,
|
|
||||||
A700: white,
|
|
||||||
),
|
|
||||||
default: #ff4081,
|
|
||||||
lighter: #ff80ab,
|
|
||||||
darker: #f50057,
|
|
||||||
text: #ff4081,
|
|
||||||
default-contrast: white,
|
|
||||||
lighter-contrast: rgba(0, 0, 0, 0.87),
|
|
||||||
darker-contrast: white,
|
|
||||||
"50-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"200-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"300-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"400-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"500-contrast": white,
|
|
||||||
"600-contrast": white,
|
|
||||||
"700-contrast": white,
|
|
||||||
"800-contrast": white,
|
|
||||||
"900-contrast": white,
|
|
||||||
"A100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"A200-contrast": white,
|
|
||||||
"A400-contrast": white,
|
|
||||||
"A700-contrast": white,
|
|
||||||
"contrast-contrast": null,
|
|
||||||
),
|
|
||||||
warn: (
|
|
||||||
50: #ffebee,
|
|
||||||
100: #ffcdd2,
|
|
||||||
200: #ef9a9a,
|
|
||||||
300: #e57373,
|
|
||||||
400: #ef5350,
|
|
||||||
500: #f44336,
|
|
||||||
600: #e53935,
|
|
||||||
700: #d32f2f,
|
|
||||||
800: #c62828,
|
|
||||||
900: #b71c1c,
|
|
||||||
A100: #ff8a80,
|
|
||||||
A200: #ff5252,
|
|
||||||
A400: #ff1744,
|
|
||||||
A700: #d50000,
|
|
||||||
contrast: (
|
|
||||||
50: rgba(0, 0, 0, 0.87),
|
|
||||||
100: rgba(0, 0, 0, 0.87),
|
|
||||||
200: rgba(0, 0, 0, 0.87),
|
|
||||||
300: rgba(0, 0, 0, 0.87),
|
|
||||||
400: rgba(0, 0, 0, 0.87),
|
|
||||||
500: white,
|
|
||||||
600: white,
|
|
||||||
700: white,
|
|
||||||
800: white,
|
|
||||||
900: white,
|
|
||||||
A100: rgba(0, 0, 0, 0.87),
|
|
||||||
A200: white,
|
|
||||||
A400: white,
|
|
||||||
A700: white,
|
|
||||||
),
|
|
||||||
default: #f44336,
|
|
||||||
lighter: #ffcdd2,
|
|
||||||
darker: #d32f2f,
|
|
||||||
text: #f44336,
|
|
||||||
default-contrast: white,
|
|
||||||
lighter-contrast: rgba(0, 0, 0, 0.87),
|
|
||||||
darker-contrast: white,
|
|
||||||
"50-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"200-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"300-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"400-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"500-contrast": white,
|
|
||||||
"600-contrast": white,
|
|
||||||
"700-contrast": white,
|
|
||||||
"800-contrast": white,
|
|
||||||
"900-contrast": white,
|
|
||||||
"A100-contrast": rgba(0, 0, 0, 0.87),
|
|
||||||
"A200-contrast": white,
|
|
||||||
"A400-contrast": white,
|
|
||||||
"A700-contrast": white,
|
|
||||||
"contrast-contrast": null,
|
|
||||||
),
|
|
||||||
is-dark: true,
|
|
||||||
foreground: (
|
|
||||||
base: white,
|
|
||||||
divider: rgba(255, 255, 255, 0.12),
|
|
||||||
dividers: rgba(255, 255, 255, 0.12),
|
|
||||||
disabled: rgba(255, 255, 255, 0.5),
|
|
||||||
disabled-button: rgba(255, 255, 255, 0.3),
|
|
||||||
disabled-text: rgba(255, 255, 255, 0.5),
|
|
||||||
elevation: black,
|
|
||||||
hint-text: rgba(255, 255, 255, 0.5),
|
|
||||||
secondary-text: rgba(255, 255, 255, 0.7),
|
|
||||||
icon: white,
|
|
||||||
icons: white,
|
|
||||||
text: white,
|
|
||||||
slider-min: white,
|
|
||||||
slider-off: rgba(255, 255, 255, 0.3),
|
|
||||||
slider-off-active: rgba(255, 255, 255, 0.3),
|
|
||||||
),
|
|
||||||
background: (
|
|
||||||
status-bar: black,
|
|
||||||
app-bar: #212121,
|
|
||||||
background: #303030,
|
|
||||||
hover: rgba(255, 255, 255, 0.04),
|
|
||||||
card: #424242,
|
|
||||||
dialog: #424242,
|
|
||||||
disabled-button: rgba(255, 255, 255, 0.12),
|
|
||||||
raised-button: #424242,
|
|
||||||
focused-button: rgba(255, 255, 255, 0.12),
|
|
||||||
selected-button: #212121,
|
|
||||||
selected-disabled-button: #424242,
|
|
||||||
disabled-button-toggle: black,
|
|
||||||
unselected-chip: #616161,
|
|
||||||
disabled-list-option: black,
|
|
||||||
tooltip: #616161,
|
|
||||||
),
|
|
||||||
);
|
|
|
@ -1,35 +0,0 @@
|
||||||
// Custom Theming for Angular Material
|
|
||||||
// For more information: https://material.angular.io/guide/theming
|
|
||||||
@use '~@angular/material' as mat;
|
|
||||||
// Plus imports for other components in your app.
|
|
||||||
|
|
||||||
// Include the common styles for Angular Material. We include this here so that you only
|
|
||||||
// have to load a single css file for Angular Material in your app.
|
|
||||||
// Be sure that you only ever include this mixin once!
|
|
||||||
@include mat.core();
|
|
||||||
|
|
||||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
|
||||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
|
||||||
// hue. Available color palettes: https://material.io/design/color/
|
|
||||||
$theme-primary: mat.define-palette(mat.$indigo-palette);
|
|
||||||
$theme-accent: mat.define-palette(mat.$green-palette, A200, A100, A400);
|
|
||||||
|
|
||||||
// The warn palette is optional (defaults to red).
|
|
||||||
$theme-warn: mat.define-palette(mat.$red-palette);
|
|
||||||
|
|
||||||
// Create the theme object. A theme consists of configurations for individual
|
|
||||||
// theming systems such as "color" or "typography".
|
|
||||||
$theme: mat.define-dark-theme((
|
|
||||||
color: (
|
|
||||||
primary: $theme-primary,
|
|
||||||
accent: $theme-accent,
|
|
||||||
warn: $theme-warn,
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
// Include theme styles for core and each component used in your app.
|
|
||||||
// Alternatively, you can import and @include the theme mixins for each component
|
|
||||||
// that you are using.
|
|
||||||
@include mat.all-component-themes($theme);
|
|
||||||
|
|
||||||
@import "./base";
|
|
|
@ -1,40 +0,0 @@
|
||||||
@use "sass:map";
|
|
||||||
// Custom Theming for Angular Material
|
|
||||||
// For more information: https://material.angular.io/guide/theming
|
|
||||||
@use '~@angular/material' as mat;
|
|
||||||
// Plus imports for other components in your app.
|
|
||||||
|
|
||||||
// Include the common styles for Angular Material. We include this here so that you only
|
|
||||||
// have to load a single css file for Angular Material in your app.
|
|
||||||
// Be sure that you only ever include this mixin once!
|
|
||||||
@include mat.core();
|
|
||||||
|
|
||||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
|
||||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
|
||||||
// hue. Available color palettes: https://material.io/design/color/
|
|
||||||
$theme-primary: mat.define-palette(mat.$blue-palette);
|
|
||||||
$theme-accent: mat.define-palette(mat.$light-blue-palette, A200, A100, A400);
|
|
||||||
|
|
||||||
// The warn palette is optional (defaults to red).
|
|
||||||
$theme-warn: mat.define-palette(mat.$red-palette);
|
|
||||||
|
|
||||||
// Create the theme object. A theme consists of configurations for individual
|
|
||||||
// theming systems such as "color" or "typography".
|
|
||||||
$theme: mat.define-light-theme((
|
|
||||||
color: (
|
|
||||||
primary: $theme-primary,
|
|
||||||
accent: $theme-accent,
|
|
||||||
warn: $theme-warn,
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
$toolbar-background: map.get($theme, color, primary, 500);
|
|
||||||
$toolbar-text: map.get($theme, color, primary, contrast, 500);
|
|
||||||
$theme: map.set($theme, color, background, app-bar, $toolbar-background);
|
|
||||||
$theme: map.set($theme, color, foreground, app-bar, $toolbar-text);
|
|
||||||
// Include theme styles for core and each component used in your app.
|
|
||||||
// Alternatively, you can import and @include the theme mixins for each component
|
|
||||||
// that you are using.
|
|
||||||
@include mat.all-component-themes($theme);
|
|
||||||
|
|
||||||
@import "./base";
|
|
Binary file not shown.
Before Width: | Height: | Size: 104 KiB |
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"APP": {
|
|
||||||
"NAME": "CureNet",
|
|
||||||
"THEME": "Theme",
|
|
||||||
"LANGUAGE": "Language"
|
|
||||||
},
|
|
||||||
"ERROR": {
|
|
||||||
"PAGE_NOT_FOUND": "Page not found or not implemented yet!"
|
|
||||||
},
|
|
||||||
"THEME": {
|
|
||||||
"LIGHT": "Light",
|
|
||||||
"DARK": "Dark"
|
|
||||||
},
|
|
||||||
"LANGUAGE": {
|
|
||||||
"PL": "Polish",
|
|
||||||
"EN": "English"
|
|
||||||
},
|
|
||||||
"MENU": {
|
|
||||||
"HOME": "Dashboard",
|
|
||||||
"PROFILE": "Profile",
|
|
||||||
"COMMUNITY": "Community",
|
|
||||||
"GROUP": "My group",
|
|
||||||
"MESSAGES": "Messages",
|
|
||||||
"QUESTIONS": "Q&A",
|
|
||||||
"TESTS": "Laboratory tests",
|
|
||||||
"RESEARCH": "Research",
|
|
||||||
"ADMIN": "Admin",
|
|
||||||
"USERS": "Users"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"APP": {
|
|
||||||
"NAME": "CureNet",
|
|
||||||
"THEME": "Motyw",
|
|
||||||
"LANGUAGE": "Język"
|
|
||||||
},
|
|
||||||
"ERROR": {
|
|
||||||
"PAGE_NOT_FOUND": "Nie znaleziono strony lub nie została ona jeszcze zaimplementowana!"
|
|
||||||
},
|
|
||||||
"THEME": {
|
|
||||||
"LIGHT": "Jasny",
|
|
||||||
"DARK": "Ciemny"
|
|
||||||
},
|
|
||||||
"LANGUAGE": {
|
|
||||||
"PL": "Polski",
|
|
||||||
"EN": "Angielski"
|
|
||||||
},
|
|
||||||
"MENU": {
|
|
||||||
"HOME": "Kokpit",
|
|
||||||
"PROFILE": "Profil",
|
|
||||||
"COMMUNITY": "Społeczność",
|
|
||||||
"GROUP": "Moja grupa",
|
|
||||||
"MESSAGES": "Wiadomości",
|
|
||||||
"QUESTIONS": "Pytania i odpowiedzi",
|
|
||||||
"TESTS": "Wyniki badań",
|
|
||||||
"RESEARCH": "Badania naukowe",
|
|
||||||
"ADMIN": "Panel administratora",
|
|
||||||
"USERS": "Użytkownicy"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,3 @@
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true
|
||||||
buildId: -1001,
|
|
||||||
buildTime: -1002,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,9 +3,7 @@
|
||||||
// The list of file replacements can be found in `angular.json`.
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false
|
||||||
buildId: -1001,
|
|
||||||
buildTime: -1002,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>CureNet</title>
|
<title>Frontend</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
</head>
|
||||||
<link rel="stylesheet" href="/light.css" id="current-theme">
|
<body>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
<app-root></app-root>
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
</body>
|
||||||
</head>
|
</html>
|
||||||
<body>
|
|
||||||
<app-root></app-root>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -1,50 +1 @@
|
||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
|
||||||
html, body { height: 100%; }
|
|
||||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
|
||||||
|
|
||||||
@import "~bootstrap/dist/css/bootstrap.css";
|
|
||||||
@import "~font-awesome/css/font-awesome.css";
|
|
||||||
|
|
||||||
body .mat-drawer.mat-drawer-side {
|
|
||||||
visibility: visible !important;
|
|
||||||
transform: none !important;
|
|
||||||
width: 250px;
|
|
||||||
&,
|
|
||||||
& .mat-drawer-inner-container{
|
|
||||||
transition-duration: 400ms !important;
|
|
||||||
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important;
|
|
||||||
transition-property: transform, margin-left, margin-right, width !important;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
& ~ .mat-drawer-content{
|
|
||||||
margin-left: 250px !important;
|
|
||||||
}
|
|
||||||
&:not(.mat-drawer-opened) {
|
|
||||||
width: 60px;
|
|
||||||
.menu-item{
|
|
||||||
margin-left: 0px !important;
|
|
||||||
&:after{
|
|
||||||
right: 190px;
|
|
||||||
}
|
|
||||||
& > i{
|
|
||||||
width: 40px;
|
|
||||||
font-size: 120%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.hide-on-side-opened{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
& ~ .mat-drawer-content {
|
|
||||||
margin-left: 60px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.w-220{
|
|
||||||
width: 220px;
|
|
||||||
}
|
|
||||||
[required]:after{
|
|
||||||
content: "*";
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--warn-color);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
name=value
|
|
||||||
name2="value 2"
|
|
||||||
#name3=value3
|
|
||||||
name4 = value4
|
|
||||||
name5 = "value 5"
|
|
|
@ -1,80 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Tools;
|
|
||||||
|
|
||||||
class PutEnv {
|
|
||||||
private string $file;
|
|
||||||
private string $key;
|
|
||||||
private string $value;
|
|
||||||
private array $content;
|
|
||||||
public function __construct() {
|
|
||||||
$argv = $_SERVER['argv'];
|
|
||||||
$argc = sizeof($argv);
|
|
||||||
switch($argc) {
|
|
||||||
case 4:
|
|
||||||
$this->file = $argv[1];
|
|
||||||
$this->key = $argv[2];
|
|
||||||
$this->value = $argv[3];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
$this->file = $argv[1];
|
|
||||||
$this->key = $argv[2];
|
|
||||||
$this->value = fgets(STDIN);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
echo "usage:
|
|
||||||
php8.0 putenv.php filename key value
|
|
||||||
echo value | php8.0 putenv filename key";
|
|
||||||
throw new Exception("invalid params");
|
|
||||||
}
|
|
||||||
if (!file_exists($this->file)) {
|
|
||||||
throw new Exception('File not found');
|
|
||||||
}
|
|
||||||
$changed = 0;
|
|
||||||
$lineWasEmpty = false;
|
|
||||||
$key = $this->key;
|
|
||||||
$value = $this->value;
|
|
||||||
if (strpos($value, ' ') !== false) {
|
|
||||||
$value = '"' . addslashes($value) . '"';
|
|
||||||
}
|
|
||||||
$this->content = file($this->file);
|
|
||||||
foreach ($this->content as $l => $line) {
|
|
||||||
if (strlen(trim($line)) < 1) {
|
|
||||||
if ($lineWasEmpty) {
|
|
||||||
$this->content[$l] = null;
|
|
||||||
} else {
|
|
||||||
$lineWasEmpty = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$lineWasEmpty = false;
|
|
||||||
if (!str_starts_with($line, $this->key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$next = trim(substr($line, strlen($this->key)));
|
|
||||||
if (strlen($next) === 0 || $next[0] !== '=') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->content[$l] = $key . '=' . $value;
|
|
||||||
$changed++;
|
|
||||||
}
|
|
||||||
if ($changed === 0) {
|
|
||||||
$this->content[] = $key . '=' . $value;
|
|
||||||
} else if ($changed > 1) {
|
|
||||||
echo "Key $key changed $changed times\n";
|
|
||||||
}
|
|
||||||
$content = $this->content;
|
|
||||||
$this->content = [];
|
|
||||||
foreach ($content as $line) {
|
|
||||||
if ($line !== null) {
|
|
||||||
$this->content[] = $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$content = implode('', $this->content);
|
|
||||||
file_put_contents($this->file, $content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new PutEnv();
|
|
Loading…
Reference in New Issue