Add basic auth + draft templates
This commit is contained in:
parent
a9ef27ccb6
commit
da27b36eb4
@ -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');
|
||||
}
|
||||
});
|
||||
}
|
BIN
assets/img/favicon.png
Normal file
BIN
assets/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
assets/img/guide.png
Normal file
BIN
assets/img/guide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
BIN
assets/img/media.png
Normal file
BIN
assets/img/media.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -5,3 +5,16 @@
|
||||
body {
|
||||
font-family: 'nunitolight';
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
]);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<string> 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<string>
|
||||
*/
|
||||
public function getRoles(): array
|
||||
{
|
||||
$roles = $this->roles;
|
||||
// guarantee every user at least has ROLE_USER
|
||||
$roles[] = 'ROLE_USER';
|
||||
|
||||
return array_unique($roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $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;
|
||||
}
|
||||
}
|
||||
|
60
src/Repository/UserRepository.php
Normal file
60
src/Repository/UserRepository.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\User;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<User>
|
||||
*/
|
||||
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()
|
||||
// ;
|
||||
// }
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
<link rel="shortcut icon" type="image/png" href="{{ asset('img/favicon.png') }}">
|
||||
{% block stylesheets %}
|
||||
{% endblock %}
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<p><strong><a href="/about">About</a></strong></p>
|
||||
<p><strong><a href="/credits">Credits</a> </strong></p>
|
||||
<p>
|
||||
<strong>ArCOA Data Entry</strong> - Copyright © 2021 - {{ 'now' | date('Y') }}
|
||||
<strong>ArCOA</strong> - Copyright © 2021 - {{ 'now' | date('Y') }}
|
||||
<a href="https://ispc.cnr.it">CNR-ISPC</a> - <a href="http://www.studilefili.unimi.it/ecm/home">UniMi</a>
|
||||
</p>
|
||||
</div>
|
||||
|
63
templates/home/index.html.twig
Normal file
63
templates/home/index.html.twig
Normal file
@ -0,0 +1,63 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Home | ArCOA{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="columns mb-0">
|
||||
<div class="column is-one-fifth arcoa-menu mb-0">
|
||||
<aside class="menu">
|
||||
<p class="menu-label has-text-white mt-3 pt-5 pl-5 is-size-6">
|
||||
Vocabularies
|
||||
<span class="icon is-clickable pl-4" id="for-vocabs">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</span>
|
||||
</p>
|
||||
<ul class="pl-6 is-hidden has-text-white" id="vocabs">
|
||||
<li><a>Access rights</a></li>
|
||||
<li><a>Civilization</a></li>
|
||||
<li><a>Copyright</a></li>
|
||||
<li><a>Document format</a></li>
|
||||
<li><a>Document type</a></li>
|
||||
<li><a>Functional context</a></li>
|
||||
<li><a>Language</a></li>
|
||||
<li><a>License</a></li>
|
||||
<li><a>Medium</a></li>
|
||||
<li><a>Object class</a></li>
|
||||
<li><a>Object type</a></li>
|
||||
<li><a>Period</a></li>
|
||||
<li><a>Script</a></li>
|
||||
<li><a>Text type</a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="column mt-6 mb-6">
|
||||
<div class="has-text-centered">
|
||||
<img width="200px" src="{{ asset('img/Logo-ArCOA-def.png') }}" />
|
||||
</div>
|
||||
<h1 class="is-size-1 mt-6 mb-6 has-text-centered">ArCOA Digital Archive</h1>
|
||||
<h2 class="is-size-3 mb-3 has-text-centered">Archivi e Collezioni dell'Oriente Antico</h2>
|
||||
<h2 class="is-size-3 mb-6 has-text-centered">Archives and Collections of the Ancient Near East</h2>
|
||||
|
||||
<div class="columns" style="max-width: 35vw; margin: 0 auto;">
|
||||
<div class="column mt-6 mb-5">
|
||||
<div class="card content p-4 is-clickable">
|
||||
<h3 class="is-size-5 has-text-centered">Resources</h3>
|
||||
<figure class="figure has-text-centered">
|
||||
<img src="{{ asset('img/media.png') }}" width="120px" />
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column mt-6 mb-5">
|
||||
<div class="card content p-4 is-clickable">
|
||||
<h3 class="is-size-5 has-text-centered">Guide</h3>
|
||||
<figure class="figure has-text-centered">
|
||||
<img src="{{ asset('img/guide.png') }}" width="120px"/>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -4,7 +4,7 @@
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container mt-6">
|
||||
<div class="container mt-6 mb-6">
|
||||
<div class="has-text-centered">
|
||||
<img width="200px" src="{{ asset('img/Logo-ArCOA-def.png') }}" />
|
||||
</div>
|
||||
@ -13,14 +13,10 @@
|
||||
<div class="card" style="max-width: 40vw; margin: 0 auto;">
|
||||
{% if error %}
|
||||
<article class="message is-danger">
|
||||
<div class="message-header">
|
||||
<p>Authentication error</p>
|
||||
<button class="delete" aria-label="delete"></button>
|
||||
</div>
|
||||
<div class="message-body">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||
<div class="message-body">Wrong user name and/or password. Please retry</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
<form class="card-content p-5" action="{{ path('app_login') }}" id="login" method="post">
|
||||
<form class="card-content pl-5 pr-5 pt-6" action="{{ path('app_login') }}" id="login" method="post">
|
||||
<div class="field">
|
||||
<h2 class="label is-size-3 has-text-centered">Sign in</h2>
|
||||
</div>
|
||||
@ -41,8 +37,8 @@
|
||||
</div>
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||
<div class="field mt-5">
|
||||
<p class="control">
|
||||
<button class="button is-link is-fullwidth">
|
||||
<p class="control" id="submit">
|
||||
<button class="button is-link is-fullwidth" type="submit">
|
||||
Sign in
|
||||
</button>
|
||||
</p>
|
||||
|
Loading…
Reference in New Issue
Block a user