<?php
namespace App\Controller\Front;
use App\EmailNotification\ToAdmin;
use App\Entity\Friend;
use App\Entity\Politician;
use App\Entity\Testament;
use App\Form\SupportPoliticianType;
use App\Form\TestamentType;
use App\Repository\FriendRepository;
use App\Repository\TestamentRepository;
use DateTime;
use Exception;
use function sleep;
use App\Entity\Post;
use App\Entity\User;
use App\Form\PostType;
use DateTimeImmutable;
use App\Entity\Contact;
use App\Form\ContactType;
use App\Entity\Suggestion;
use ColorThief\ColorThief;
use App\Form\ParameterType;
use App\Entity\Notification;
use App\Entity\ResetPassword;
use App\Entity\UserAnonymous;
use App\Entity\ChangePassword;
use App\Entity\InscriptionNote;
use App\Form\ResetPasswordType;
use App\Form\ChangePasswordType;
use App\EmailNotification\ToUser;
use App\Form\InscriptionNoteType;
use App\Repository\PostRepository;
use App\Repository\UserRepository;
use App\Form\CitizenSuggestionType;
use App\Repository\ReportRepository;
use Symfony\Component\Form\FormError;
use Symfony\Component\Mercure\Update;
use Doctrine\ORM\EntityManagerInterface;
use App\Repository\SensibilityRepository;
use App\Repository\UserAnonymousRepository;
use App\Repository\PoliticalPartyRepository;
use App\Repository\PoliticianRepository;
use App\Service\ImageOptimizer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class AccountController extends AbstractController
{
public function __construct(
private EntityManagerInterface $manager
){}
public function generateToken(): string
{
try {return rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');} catch (Exception) {}
}
private function generateUniqueName(): string
{
return md5(uniqid());
}
/* No User type in registration */
#[Route('/inscription/remarque', name: 'registration_no_user')]
public function noUserType(Request $request, EntityManagerInterface $manager, Session $session): Response
{
$inscriptionNote = new InscriptionNote();
$form = $this->createForm(InscriptionNoteType::class, $inscriptionNote);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$inscriptionNote->setEmail($session->get('email') ?? "N/A")
->setFirstname($session->get('firstname') ?? "N/A")
->setLastname($session->get('lastname') ?? "N/A");
$manager->persist($inscriptionNote);
$manager->flush();
$this->addFlash("success", "Votre remarque a bien été envoyer, vous recevrez une réponse par mail");
return $this->redirectToRoute('user_welcome');
}
return $this->render('front/registration/no-user-type.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/app-user-login', name: 'user_login')]
public function index(ReportRepository $reportRepository): Response
{
sleep(1);
/** @var User $user */
$user = $this->getUser();
$message = null;
$success = false;
if ($user)
{
if ($user->getStatus() == "banned")
{
if ($user->getBannedUntil())
{
$message = "Votre compte est suspendu jusqu'au " . $user->getBannedUntil()->format('d/m/Y');
}
else
{
$message = "Votre compte est suspendu";
}
$report = $reportRepository->findOneBy(['user' => $user, 'status' => 'done'], ['id' => 'DESC']) ?? null;
if ($report) { $reason = $report->getAnswer(); }
$token = $user->getToken();
}
elseif ($user->getStatus() == "anonymous") {
return $this->json([
'success' => 'anonymous',
]);
}
else
{
$success = true;
}
}
return $this->json([
'success' => $success,
'message' => $message,
'reason' => $reason ?? null,
'token' => $token ?? false
]);
}
#[Route('/deconnexion', name: 'user_logout')]
public function logout(){}
#[Route('/reintegration', name: 'user_stop_anonymous')]
public function stopAnonymous(Request $request, UserAnonymousRepository $userAnonymousRepository, EntityManagerInterface $manager): Response
{
if ($request->getMethod() == "POST") {
/* @var User $user */
$user = $this->getUser();
$userAnonymousQuery = $userAnonymousRepository->getUser($user);
$userAnonymous = $userAnonymousQuery[0];
$user->setFirstname($userAnonymous->getFirstname())
->setLastname($userAnonymous->getLastname())
->setSlugUser($userAnonymous->getSlugUser())
->setCover($userAnonymous->getCover())
->setAvatar($userAnonymous->getAvatar())
->setPhone($userAnonymous->getPhone())
->setStatus('online')
->setAnonymousAt(null);
$manager->remove($userAnonymous);
$manager->flush();
$this->addFlash("success", "Nous sommes ravi de vous revoir");
return $this->redirectToRoute('feed');
}
return $this->render('front/shared/anonymous.html.twig');
}
#[Route('/sensibility-details', name: 'sensibility_details')]
public function getSensibilityDetails(Request $request, SensibilityRepository $sensibilityRepository): JsonResponse
{
$data = json_decode($request->getContent(), true);
$sensibility = $sensibilityRepository->find($data['sensibilityId']);
if ($sensibility) {
return new JsonResponse([
'status' => 'success',
'title' => $sensibility->getTitle(),
'description' => $sensibility->getDescription()
]);
}
return new JsonResponse([
'status' => 'error',
]);
}
#[Route('/save-user-profile-photo', name: 'save_user_profile')]
public function saveProfileImage(ImageOptimizer $imageOptimizer, Request $request, EntityManagerInterface $manager): JsonResponse
{
if ($request->isXmlHttpRequest()){
$user = $this->getUser();
// the file
$file = $_FILES['file'];
$file = new UploadedFile($file['tmp_name'], $file['name'], $file['type']);
$filename = $this->generateUniqueName() . '.' . $file->guessExtension();
$imageOptimizer->resizeImage($file, $filename, 'profiles_directory', 'avatar');
/*
$file->move(
$this->getParameter('profiles_directory'),
$filename
);
*/
$oldProfile = $user->getAvatar();
if ($oldProfile != 'default-profile.png' && file_exists($this->getParameter('profiles_directory').'/'.$oldProfile) && is_file($this->getParameter('profiles_directory').'/'.$oldProfile)) {
unlink($this->getParameter('profiles_directory').'/'.$oldProfile);
}
$user->setAvatar($filename);
$manager->persist($user);
$manager->flush();
$this->addFlash(
'success',
"Votre photo de profil à été modifiée"
);
return new JsonResponse("success");
}
return new JsonResponse("This is not an ajax request");
}
#[Route('/save-user-cover-photo', name: 'save_user_cover')]
public function saveCoverImage(ImageOptimizer $imageOptimizer, Request $request, EntityManagerInterface $manager): JsonResponse
{
if ($request->isXmlHttpRequest()){
$user = $this->getUser();
// the file
$file = $_FILES['file'];
$file = new UploadedFile($file['tmp_name'], $file['name'], $file['type']);
$filename = $this->generateUniqueName() . '.' . $file->guessExtension();
$imageOptimizer->resizeImage($file, $filename, 'profiles_directory', 'cover');
/*
$file->move(
$this->getParameter('profiles_directory'),
$filename
);
*/
$oldProfile = $user->getCover();
if ($oldProfile != 'default-cover.png' && file_exists($this->getParameter('profiles_directory').'/'.$oldProfile) && is_file($this->getParameter('profiles_directory').'/'.$oldProfile)) {
unlink($this->getParameter('profiles_directory').'/'.$oldProfile);
}
$user->setCover($filename);
$manager->persist($user);
$manager->flush();
$this->addFlash(
'success',
"Votre photo de couverture à été modifiée"
);
return new JsonResponse("success");
}
return new JsonResponse("This is not an ajax request");
}
#[Route('/mon-profil/parametres', name: 'user_parameters')]
public function parameters(Request $request, EntityManagerInterface $manager, UserPasswordHasherInterface $passwordHasher, TestamentRepository $testamentRepository): Response
{
/**
* @var $user User
*/
$user = $this->getUser();
// Change password
$changepassword = new ChangePassword;
$formPassword = $this->createForm(ChangePasswordType::class, $changepassword);
$formPassword->handleRequest($request);
if($formPassword->isSubmitted() && $formPassword->isValid()){
if(password_verify($changepassword->getCurrentPassword(), $user->getPassword())){
$user->setPassword($passwordHasher->hashPassword($user, $changepassword->getPassword()));
$manager->persist($user);
$manager->flush();
$this->addFlash('success', 'Votre mot de passe a bien été modifié');
return $this->redirectToRoute('user_parameters');
}
else{
$formPassword->get('currentPassword')->addError(new FormError("Le mot de passe actuel est incorrect"));
}
}
if ($user->getType() == "politician") {
$testament = $testamentRepository->findOneBy(['politician' => $user]);
if (!$testament) { $testament = new Testament(); }
$formTestament = $this->createForm(TestamentType::class, $testament);
$formTestament->handleRequest($request);
if ($formTestament->isSubmitted() && $formTestament->isValid()) {
$testament->setPolitician($user)
->setUpdateAt(new DateTime());
$this->manager->persist($testament);
$this->manager->flush();
$this->addFlash("success", "Votre testament à bien été enregistré");
return $this->redirectToRoute('user_parameters');
}
}
// Handle confidentiality
$parameter = $user->getParameter();
$formParameter = $this->createForm(ParameterType::class, $parameter);
$formParameter->handleRequest($request);
if ($formParameter->isSubmitted() && $formParameter->isValid()) {
$manager->persist($parameter);
$manager->flush();
$this->addFlash('success', 'Vos paramètres de confidentialité ont été mis à jour');
return $this->redirectToRoute('user_parameters');
}
/* Contact form */
$contact = new Contact();
$formContact = $this->createForm(ContactType::class, $contact);
$formContact->handleRequest($request);
if ($formContact->isSubmitted() && $formContact->isValid()) {
$contact->setUser($this->getUser());
$manager->persist($contact);
$manager->flush();
$this->addFlash("success", "Votre demande a bien été envoyé");
return $this->redirect($request->getUri());
}
return $this->render('front/shared/parameters.html.twig', [
'menu' => 'parameters',
'showing' => 'owner',
'user' => $user,
'type' => $user->getType(),
'formPassword' => $formPassword->createView(),
'formParameter' => $formParameter->createView(),
'formContact' => $formContact->createView(),
'formTestament' => isset($formTestament) ? $formTestament->createView() : null
]);
}
#[Route('/profil/{slugUser}', name: 'public_profile')]
public function showProfil(ToAdmin $toAdmin, User $user, PostRepository $postRepo, Request $request): Response
{
if ($user->getStatus() != "online") { return $this->redirectToRoute('feed'); }
if ($user === $this->getUser()) { return $this->redirectToRoute('owner_profile'); }
if ($user->getType() == "politician") {
$suggestion = new Suggestion();
$suggestionForm = $this->createForm(CitizenSuggestionType::class, $suggestion);
$suggestionForm->handleRequest($request);
if ($suggestionForm->isSubmitted() && $suggestionForm->isValid()) {
$suggestion->setCreatedAt(new DateTimeImmutable())
->setPolitician($user)
->setStatus('pending')
->setCitizen($this->getUser())
->setShowPublic(true);
$this->manager->persist($suggestion);
$this->manager->flush();
$toAdmin->newSuggestion($suggestion);
$this->addFlash("success", "Votre suggestion a bien été enregistrée");
return $this->redirect($request->getUri());
}
}
else {
$suggestionForm = $this->createForm(CitizenSuggestionType::class);
}
$posts = $postRepo->feedByUserAccount($user);
return $this->render('front/shared/public-profile.html.twig', [
'showing' => 'public',
'user' => $user,
'type' => $user->getType(),
'posts' => $posts,
'suggestionForm' => $suggestionForm->createView(),
'totalPost' => $postRepo->feedByUserAccountCount($user),
'postSubmenu' => false
]);
}
#[Route('/mon-profil', name: 'owner_profile')]
public function ownProfile(PostRepository $postRepo, Request $request, EntityManagerInterface $manager, PoliticianRepository $politicianRepo): Response
{
/** @var User $user */
$user = $this->getUser();
if ($user->getStatus() == "banned" || $user->getStatus() == "anonymous") { return $this->redirectToRoute('user_logout'); }
$posts = $postRepo->feedByUserAccount($user);
$post = new Post();
$post->setHandleRedirect('profile');
$form = $this->createForm(PostType::class, $post, [
'action' => $this->generateUrl('handle_post_submit')
]);
$form->handleRequest($request);
if ($request->request->get('testament')) {
$user->setTestamentText($request->request->get('testament'))
->setTestamentUpdatedAt(new DateTimeImmutable());
$manager->persist($user);
$manager->flush();
$this->addFlash("success", "Votre testament a bien été enregistré");
return $this->redirectToRoute('owner_profile');
}
if ($request->request->get('supportedName')) {
$user->setSupported($request->request->get('supportedName'));
if ($request->request->get('supportedId') && $politicianRepo->find($request->request->get('supportedId'))) {
$politicianSupported = $politicianRepo->find($request->request->get('supportedId'));
$user->setPoliticianSupported($politicianSupported);
}
else {
$user->setPoliticianSupported(null);
}
$manager->persist($user);
$manager->flush();
$this->addFlash("success", "Votre soutien a bien été enregistré");
return $this->redirectToRoute('owner_profile');
}
return $this->render('front/shared/owner-profile.html.twig', [
'menu' => 'profile',
'showing' => 'owner',
'user' => $user,
'type' => $user->getType(),
'posts' => $posts,
'form' => $form->createView(),
'totalPost' => $postRepo->feedByUserAccountCount($user),
'postSubmenu' => false
]);
}
#[Route('/mon-profil/mise-a-jour/partie-politique', name: 'update_political_party', methods: "POST")]
public function updatePoliticalParty(Request $request, PoliticalPartyRepository $politicalPartyRepository): Response
{
$message = "Une erreur est survenue";
if ($request->get('politicalParty'))
{
$party = $politicalPartyRepository->find($request->get('politicalParty'));
if ($party)
{
/**
* @var User $user
**/
$user = $this->getUser();
$user->setPoliticalParty($party);
$this->manager->flush();
$message = "Vos informations on bien été modifié";
}
}
$this->addFlash("success", $message);
return $this->redirectToRoute('politician_owner_informations');
}
#[Route('/verification-email', name: 'verify_email_page')]
public function verifyEmailPage(): Response
{
return $this->render('front/registration/verify-email.html.twig');
}
#[Route('/compte-verification/{token}', name: 'verify_email')]
public function verifyEmail(User $user, EntityManagerInterface $manager): Response
{
$user->setIsVerified(true)
->setStatus('online');
$manager->flush();
$this->addFlash("success", "Bienvenue sur Politicly");
return $this->redirectToRoute('owner_profile');
}
#[Route("/mot-de-passe-oublie", name:'forgot_password')]
public function forgotPassword(UserRepository $userRepository, ToUser $toUser): Response
{
$email = null;
if (isset($_POST['forgot_submit'])) {
$email = $_POST['forgot_email'];
$user = $userRepository->findOneBy(['email' => $email]);
if ($user) {
$toUser->forgotPassword($user);
$email = null;
}
$this->addFlash("success", "Envoyé");
return $this->redirectToRoute('forgot_password');
}
return $this->render('front/shared/forgot-password.html.twig', [
'email' => $email
]);
}
#[Route("/reinitialisation-mot-de-passe/{token}", name:"admin_reset_password")]
public function resetPassword($token, UserRepository $userRepository, UserPasswordEncoderInterface $encoder, Request $request, EntityManagerInterface $manager): Response
{
$user = $userRepository->findOneBy(['token' => $token]);
if ($user) {
$action = 'reset';
$newPassword = new ResetPassword();
$form = $this->createForm(ResetPasswordType::class, $newPassword);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$hashed = $encoder->encodePassword($user, $newPassword->getPassword());
$user->setPassword($hashed)
->setToken($this->generateToken());
$manager->persist($user);
$manager->flush();
$this->addFlash("success", "Votre mot de passe a bien été modifié");
return $this->redirectToRoute('user_welcome');
}
return $this->render('front/shared/reset-password.html.twig', [
'action' => $action,
'form' => $form->createView()
]);
}
else {
$action = 'expired';
return $this->render('front/shared/reset-password.html.twig', [
'action' => $action
]);
}
}
#[Route('/user/anonymisation/{slugUser}', name: 'user_anonymous', methods: "POST")]
public function anonymousAccount(User $user, EntityManagerInterface $manager, Request $request, UserPasswordHasherInterface $passwordHasher): Response
{
if ($this->getUser() !== $user) { return $this->redirectToRoute('user_logout'); }
if (!$passwordHasher->isPasswordValid($user, $request->get('password'))) {
$this->addFlash("success", "Mot de passe incorrect");
return $this->redirectToRoute('user_parameters');
}
$userAnonymous = new UserAnonymous();
$userAnonymous->setLastname($user->getLastname())
->setFirstname($user->getFirstname())
->setCover($user->getCover())
->setAvatar($user->getAvatar())
->setSlugUser($user->getSlugUser())
->setPhone($user->getPhone())
->setUser($user)
;
$manager->persist($userAnonymous);
$date = new DateTimeImmutable('+1 month');
$user->setStatus('anonymous')
->setFirstname('user anonyme')
->setLastname('user anonyme')
->setCover('default-cover.png')
->setAvatar('default-profile.png')
->setPhone(null)
->setAnonymousAt($date)
;
$manager->flush();
return $this->redirectToRoute('user_logout');
}
#[Route('/user/anonymisation/reset/{slugUser}', name: 'user_anonymous_reset')]
public function anonymousResetAccount(User $user): Response
{
if ($this->getUser() !== $user) { return $this->redirectToRoute('user_logout'); }
$user->setStatus("online")
->setAnonymousAt(null);
$this->addFlash("success", "C'est un plaisir de vous revoir parmi nous");
return $this->redirectToRoute('public_profile', ['slugUser' => $user->getSlugUser()]);
}
#[Route('/user/refuse/invitation/{slugUser}', name: 'user_refused_invitation')]
public function refuseInvitation(User $user, EntityManagerInterface $manager, FriendRepository $friendRepository): Response
{
$friend = $friendRepository->findOneBy(["sender" => $user, "receiver" => $this->getUser()]);
if ($friend) {
$friend->setStatus("refused");
$manager->flush();
}
$friendReverse = $friendRepository->findOneBy(["receiver" => $user, "sender" => $this->getUser()]);
if ($friendReverse) {
$manager->remove($friendReverse);
$manager->flush();
}
$this->addFlash("success", "L'invitation à bien été supprimée");
return $this->redirectToRoute('public_profile', ['slugUser' => $user->getSlugUser()]);
}
#[Route('/user/accept/invitation/{slugUser}', name: 'user_accept_invitation')]
public function acceptInvitation(MessageBusInterface $bus, User $user, EntityManagerInterface $manager, FriendRepository $friendRepository): Response
{
$friend = $friendRepository->findOneBy(["sender" => $user, "receiver" => $this->getUser()]);
if ($friend) {
$friend->setStatus("accepted");
$notification = new Notification;
$notification->setType('friend')
->setOwner($friend->getSender())
->setRelatedUser($friend->getReceiver())
->setContent('a accepté votre demande de connexion')
->setIsOpened(false)
->setLink($this->generateUrl('public_profile', ['slugUser' => $friend->getReceiver()->getSlugUser()]))
->setCreatedAt(new DateTime());
$notification->getOwner()->setNotificationsOpen(false);
$manager->persist($notification);
$notificationOwnerId = $notification->getOwner()->getId();
$update = new Update(
"https://example.com/notifications/$notificationOwnerId",
json_encode(['notification' => true])
);
try {
$bus->dispatch($update);
} catch (\Exception) {}
$manager->flush();
}
$this->addFlash("success", "L'invitation à bien été acceptée");
return $this->redirectToRoute('public_profile', ['slugUser' => $friend->getSender()->getSlugUser()]);
}
#[Route('/user/cancel/relation/{slugUser}', name: 'user_cancel_invitation')]
public function cancelRelation(User $user, EntityManagerInterface $manager, FriendRepository $friendRepository): Response
{
$friend = $friendRepository->findOneBy(["sender" => $user, "receiver" => $this->getUser()]);
if ($friend) {
$manager->remove($friend);
$manager->flush();
}
$friendReverse = $friendRepository->findOneBy(["receiver" => $user, "sender" => $this->getUser()]);
if ($friendReverse) {
$manager->remove($friendReverse);
$manager->flush();
}
$this->addFlash("success", "La relation à bien été supprimée");
return $this->redirectToRoute('public_profile', ['slugUser' => $user->getSlugUser()]);
}
}