WIP: Implement admin dashboard

This commit is contained in:
Björn Fromme
2023-10-22 17:05:43 +02:00
parent 38d6fafcb2
commit 91f0f76ccc
15 changed files with 280 additions and 4 deletions
@@ -3,6 +3,7 @@
namespace App\Controller\Admin\Assignment;
use App\Entity\Assignment;
use App\Entity\User;
use App\Form\AssignmentType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
@@ -24,7 +25,11 @@ class CreateController extends AbstractController
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Request $request): Response
{
/** @var User $user */
$user = $this->getUser();
$assignment = new Assignment();
$assignment->setOwner($user);
$form = $this->createForm(AssignmentType::class, $assignment);
$form->handleRequest($request);
@@ -60,6 +60,16 @@ class CheckController extends AbstractController
case Upload::STATUS_REJECTED:
$this->rejectDocument($document, $formData->getComment());
$this->eventDispatcher->dispatch(new DocumentRejectedEvent($formData), DocumentRejectedEvent::NAME);
default:
$document->setStatus($formData->getStatus());
$this->entityManager->flush();
$this->addFlash('success', 'Der Status wurde aktualisiert');
$this->logger->info('Update document status', [
'document_id' => $document->getId(),
'document_filename' => $document->getOriginalFilename(),
'owner' => $document->getOwner()->getFullName(),
'status' => $formData->getStatus(),
]);
}
$returnUrl = $this->generateUrl('app_admin_document_index');
+36 -1
View File
@@ -2,6 +2,12 @@
namespace App\Controller\Admin;
use App\Entity\Application;
use App\Entity\Upload;
use App\Repository\ApplicationRepository;
use App\Repository\AssignmentRepository;
use App\Repository\AvailabilityRepository;
use App\Repository\UploadRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -9,10 +15,39 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class IndexController extends AbstractController
{
public function __construct(
private readonly ApplicationRepository $applicationRepository,
private readonly AssignmentRepository $assignmentRepository,
private readonly AvailabilityRepository $availabilityRepository,
private readonly UploadRepository $uploadRepository
) {
}
#[Route('/admin', name: 'app_admin_index')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(): Response
{
return $this->render('admin/index.html.twig');
$applications = $this->applicationRepository->getNew();
$newApplicationsCount = $this->applicationRepository->getCountByStatus(Application::STATUS_NEW);
$pendingApplicationsCount = $this->applicationRepository->getCountByStatus(Application::STATUS_PENDING);
$assignments = $this->assignmentRepository->getNew();
$availabilities = $this->availabilityRepository->getNew();
$documents = $this->uploadRepository->getNew();
$newDocumentsCount = $this->uploadRepository->getCountByStatus(Upload::STATUS_NEW);
$pendingDocumentsCount = $this->uploadRepository->getCountByStatus(Upload::STATUS_PENDING);
return $this->render('admin/index.html.twig', [
'applications' => $applications,
'newApplicationsCount' => $newApplicationsCount,
'pendingApplicationsCount' => $pendingApplicationsCount,
'assignments' => $assignments,
'availabilities' => $availabilities,
'documents' => $documents,
'newDocumentsCount' => $newDocumentsCount,
'pendingDocumentsCount' => $pendingDocumentsCount,
]);
}
}
+15
View File
@@ -81,6 +81,9 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
#[ORM\ManyToMany(targetEntity: Upload::class)]
private Collection $documents;
#[ORM\ManyToOne]
private ?User $owner = null;
public function __construct()
{
$this->uuid = Uuid::v4();
@@ -421,4 +424,16 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this;
}
public function getOwner(): ?User
{
return $this->owner;
}
public function setOwner(?User $owner): static
{
$this->owner = $owner;
return $this;
}
}
+1
View File
@@ -23,6 +23,7 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
public const TYPE_DOCUMENT = 'document';
public const STATUS_NEW = 'new';
public const STATUS_PENDING = 'pending';
public const STATUS_CHECKED = 'checked';
public const STATUS_PAID = 'paid';
public const STATUS_REJECTED = 'rejected';
+2
View File
@@ -36,10 +36,12 @@ class DocumentCheckType extends AbstractType
'data_class' => DocumentCheckDto::class,
'status_choices' => [
Upload::TYPE_CONTRACT => [
'in Bearbeitung' => Upload::STATUS_PENDING,
'bestätigt' => Upload::STATUS_CHECKED,
'abgelehnt' => Upload::STATUS_REJECTED,
],
Upload::TYPE_INVOICE => [
'in Bearbeitung' => Upload::STATUS_PENDING,
'bezahlt' => Upload::STATUS_PAID,
'abgelehnt' => Upload::STATUS_REJECTED,
],
+32
View File
@@ -72,4 +72,36 @@ class ApplicationRepository extends ServiceEntityRepository
->getResult()
;
}
public function getNew(int $limit = 5): array
{
$qb = $this->createQueryBuilder('application');
return $qb
->select('application', 'assignment', 'destination', 'job_profile', 'teamer')
->innerJoin('application.assignment', 'assignment')
->innerJoin('assignment.destination', 'destination')
->innerJoin('assignment.jobProfile', 'job_profile')
->innerJoin('application.teamer', 'teamer')
->where($qb->expr()->neq('application.status', ':status'))
->orderBy('application.createdAt', 'DESC')
->setParameter('status', Application::STATUS_REJECTED)
->setMaxResults($limit)
->getQuery()
->getResult()
;
}
public function getCountByStatus(string $status): ?int
{
$qb = $this->createQueryBuilder('application');
return $qb
->select($qb->expr()->count('application'))
->where($qb->expr()->eq('application.status', ':status'))
->setParameter('status', $status)
->getQuery()
->getSingleScalarResult()
;
}
}
+16
View File
@@ -121,4 +121,20 @@ class AssignmentRepository extends ServiceEntityRepository
return $options;
}
public function getNew(int $limit = 5): array
{
$qb = $this->createQueryBuilder('assignment');
return $qb
->select('assignment', 'destination', 'job_profile', 'owner')
->innerJoin('assignment.destination', 'destination')
->innerJoin('assignment.jobProfile', 'job_profile')
->innerJoin('assignment.owner', 'owner')
->orderBy('assignment.createdAt', 'DESC')
->setMaxResults($limit)
->getQuery()
->getResult()
;
}
}
+13
View File
@@ -65,4 +65,17 @@ class AvailabilityRepository extends ServiceEntityRepository
->getResult()
;
}
public function getNew(int $limit = 5): array
{
$qb = $this->createQueryBuilder('availability');
return $qb
->where($qb->expr()->isNotNull('availability.owner'))
->orderBy('availability.createdAt', 'DESC')
->setMaxResults($limit)
->getQuery()
->getResult()
;
}
}
+41
View File
@@ -6,6 +6,7 @@ use App\Entity\Upload;
use App\Repository\Traits\QueryHelperTrait;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\Persistence\ManagerRegistry;
/**
@@ -83,4 +84,44 @@ class UploadRepository extends ServiceEntityRepository
->getQuery()
;
}
public function getNew(int $limit = 5): array
{
$qb = $this->createQueryBuilder('upload');
return $qb
->select('upload', 'owner', 'teamer', 'disposition', 'assignment')
->innerJoin('upload.owner', 'owner')
->innerJoin('owner.teamer', 'teamer')
->leftJoin('upload.disposition', 'disposition')
->leftJoin('disposition.assignment', 'assignment')
->where($qb->expr()->andX(
$qb->expr()->in('upload.type', ':type'),
$qb->expr()->in('upload.status', ':status')
))
->orderBy('upload.createdAt', 'DESC')
->setParameter('type', [Upload::TYPE_CONTRACT, Upload::TYPE_INVOICE])
->setParameter('status', [Upload::STATUS_NEW, Upload::STATUS_PENDING])
->setMaxResults($limit)
->getQuery()
->getResult()
;
}
public function getCountByStatus(string $status): ?int
{
$qb = $this->createQueryBuilder('upload');
return $qb
->select($qb->expr()->count('upload'))
->where($qb->expr()->andX(
$qb->expr()->in('upload.type', ':type'),
$qb->expr()->eq('upload.status', ':status')
))
->setParameter('type', [Upload::TYPE_CONTRACT, Upload::TYPE_INVOICE])
->setParameter('status', $status)
->getQuery()
->getSingleScalarResult()
;
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ class UploadVoter extends Voter
if (true === in_array('ROLE_ADMINISTRATIVE', $token->getRoleNames())) {
// Only new documents may be checked
if (static::CHECK === $attribute) {
return Upload::STATUS_NEW === $upload->getStatus();
return in_array($upload->getStatus(), [Upload::STATUS_NEW, Upload::STATUS_PENDING]);
}
return true;