diff --git a/assets/app.js b/assets/app.js index 8755ccb..71efa05 100644 --- a/assets/app.js +++ b/assets/app.js @@ -24,8 +24,35 @@ function showPasswd(selector) { }); } -document.addEventListener('DOMContentLoaded', () => { - if (location.pathname.includes('login')) { - showPasswd('#show-pw'); +console.log('whatever'); + +if (location.pathname.includes('login')) { + showPasswd('#show-pw'); + + document.querySelector('#submit > button').addEventListener('click', function () { + this.parentElement.classList.add('is-loading'); + }); + + const error = document.querySelector('.is-danger'); + + if (error) { + error.querySelector('.delete').addEventListener('click', () => { + error.classList.add('is-hidden'); + }); } -}); +} + +if (! location.pathname.includes('login')) { + const vocabs = document.querySelector('#vocabs'); + document.querySelector('#for-vocabs').addEventListener('click', function () { + vocabs.classList.toggle('is-hidden'); + + if (this.firstElementChild.classList.contains('fa-angle-right')) { + this.firstElementChild.classList.remove('fa-angle-right'); + this.firstElementChild.classList.add('fa-angle-down'); + } else { + this.firstElementChild.classList.remove('fa-angle-down'); + this.firstElementChild.classList.add('fa-angle-right'); + } + }); +} \ No newline at end of file diff --git a/assets/img/favicon.png b/assets/img/favicon.png new file mode 100644 index 0000000..32c7653 Binary files /dev/null and b/assets/img/favicon.png differ diff --git a/assets/img/guide.png b/assets/img/guide.png new file mode 100644 index 0000000..1c76678 Binary files /dev/null and b/assets/img/guide.png differ diff --git a/assets/img/media.png b/assets/img/media.png new file mode 100644 index 0000000..2a26147 Binary files /dev/null and b/assets/img/media.png differ diff --git a/assets/styles/app.css b/assets/styles/app.css index 03ead64..0b0d436 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -4,4 +4,17 @@ body { font-family: 'nunitolight'; -} \ No newline at end of file +} + +.arcoa-menu { + background-color: rgba(66,135,199,0.98); + max-height: 100vh; + overflow-y: auto; +} +#vocabs a { + color: #fff; +} +/* For dev only*/ +.sf-toolbar-clearer { + display: none !important; +} diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 2689869..43632b6 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -4,7 +4,12 @@ security: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider providers: - users_in_memory: { memory: null } + # used to reload user from session & other features (e.g. switch_user) + app_user_provider: + entity: + class: App\Entity\User + property: username + # used to reload user from session & other features (e.g. switch_user) firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ @@ -15,7 +20,7 @@ security: check_path: app_login enable_csrf: true lazy: true - provider: users_in_memory + provider: app_user_provider # activate different ways to authenticate # https://symfony.com/doc/current/security.html#the-firewall @@ -27,8 +32,8 @@ security: # Note: Only the *first* access control that matches will be used access_control: - { path: ^/$, roles: ROLE_USER } - # - { path: ^/admin, roles: ROLE_ADMIN } - # - { path: ^/profile, roles: ROLE_USER } + - { path: ^/admin, roles: ROLE_ADMIN } + - { path: ^/profile, roles: ROLE_USER } when@test: security: diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php index 261aac6..6ccfe8e 100644 --- a/src/Controller/HomeController.php +++ b/src/Controller/HomeController.php @@ -11,7 +11,7 @@ class HomeController extends AbstractController #[Route('/', name: 'app_home')] public function index(): Response { - return $this->render('index.html.twig', [ + return $this->render('home/index.html.twig', [ 'controller_name' => 'HomeController', ]); } diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index 585546e..d2fac88 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Entity\User; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; diff --git a/src/Entity/User.php b/src/Entity/User.php index c5a7b15..2bef50d 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -4,57 +4,44 @@ namespace App\Entity; use App\Repository\UserRepository; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; +use Symfony\Component\Security\Core\User\UserInterface; #[ORM\Entity(repositoryClass: UserRepository::class)] -#[ORM\Table(name: '`user`')] -class User +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])] +class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] private ?int $id = null; - #[ORM\Column(length: 30)] - private ?string $firstName = null; - - #[ORM\Column(length: 40)] - private ?string $lastName = null; - - #[ORM\Column(length: 30)] + #[ORM\Column(length: 180)] private ?string $username = null; - #[ORM\Column(length: 200)] + /** + * @var list The user roles + */ + #[ORM\Column] + private array $roles = []; + + /** + * @var string The hashed password + */ + #[ORM\Column] private ?string $password = null; + #[ORM\Column(length: 30, nullable: true)] + private ?string $firstname = null; + + #[ORM\Column(length: 40, nullable: true)] + private ?string $lastname = null; + public function getId(): ?int { return $this->id; } - public function getFirstName(): ?string - { - return $this->firstName; - } - - public function setFirstName(string $firstName): static - { - $this->firstName = $firstName; - - return $this; - } - - public function getLastName(): ?string - { - return $this->lastName; - } - - public function setLastName(string $lastName): static - { - $this->lastName = $lastName; - - return $this; - } - public function getUsername(): ?string { return $this->username; @@ -67,6 +54,43 @@ class User return $this; } + /** + * A visual identifier that represents this user. + * + * @see UserInterface + */ + public function getUserIdentifier(): string + { + return (string) $this->username; + } + + /** + * @see UserInterface + * + * @return list + */ + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + + /** + * @param list $roles + */ + public function setRoles(array $roles): static + { + $this->roles = $roles; + + return $this; + } + + /** + * @see PasswordAuthenticatedUserInterface + */ public function getPassword(): ?string { return $this->password; @@ -78,4 +102,37 @@ class User return $this; } + + /** + * @see UserInterface + */ + public function eraseCredentials(): void + { + // If you store any temporary, sensitive data on the user, clear it here + // $this->plainPassword = null; + } + + public function getFirstname(): ?string + { + return $this->firstname; + } + + public function setFirstname(?string $firstname): static + { + $this->firstname = $firstname; + + return $this; + } + + public function getLastname(): ?string + { + return $this->lastname; + } + + public function setLastname(?string $lastname): static + { + $this->lastname = $lastname; + + return $this; + } } diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php new file mode 100644 index 0000000..4f2804e --- /dev/null +++ b/src/Repository/UserRepository.php @@ -0,0 +1,60 @@ + + */ +class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, User::class); + } + + /** + * Used to upgrade (rehash) the user's password automatically over time. + */ + public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void + { + if (!$user instanceof User) { + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class)); + } + + $user->setPassword($newHashedPassword); + $this->getEntityManager()->persist($user); + $this->getEntityManager()->flush(); + } + + // /** + // * @return User[] Returns an array of User objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('u.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?User + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/templates/base.html.twig b/templates/base.html.twig index 848301d..ee542bf 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -3,7 +3,7 @@ {% block title %}Welcome!{% endblock %} - + {% block stylesheets %} {% endblock %} @@ -19,7 +19,7 @@

About

Credits

- ArCOA Data Entry - Copyright © 2021 - {{ 'now' | date('Y') }} + ArCOA - Copyright © 2021 - {{ 'now' | date('Y') }} CNR-ISPC - UniMi

diff --git a/templates/home/index.html.twig b/templates/home/index.html.twig new file mode 100644 index 0000000..aacddf5 --- /dev/null +++ b/templates/home/index.html.twig @@ -0,0 +1,63 @@ +{% extends 'base.html.twig' %} + +{% block title %}Home | ArCOA{% endblock %} + +{% block body %} + +
+ +
+
+ +
+

ArCOA Digital Archive

+

Archivi e Collezioni dell'Oriente Antico

+

Archives and Collections of the Ancient Near East

+ +
+
+
+

Resources

+
+ +
+
+
+
+
+

Guide

+
+ +
+
+
+
+
+
+ +{% endblock %} diff --git a/templates/login/index.html.twig b/templates/login/index.html.twig index 44045b9..7e97ce5 100644 --- a/templates/login/index.html.twig +++ b/templates/login/index.html.twig @@ -4,7 +4,7 @@ {% block body %} -
+
@@ -13,14 +13,10 @@
{% if error %}
-
-

Authentication error

- -
-
{{ error.messageKey|trans(error.messageData, 'security') }}
+
Wrong user name and/or password. Please retry
{% endif %} -
+

Sign in

@@ -41,8 +37,8 @@
-

-