add all routes existing

This commit is contained in:
Tykayn 2021-04-08 17:16:41 +02:00 committed by tykayn
parent a8c70f3a5c
commit e1ee9c9ac8
13 changed files with 1349 additions and 76 deletions

View File

@ -8,6 +8,7 @@
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "1.11.99.1",
"doctrine/annotations": "^1.12",
"doctrine/doctrine-bundle": "^2.3",
"doctrine/doctrine-migrations-bundle": "^3.1",
"doctrine/orm": "^2.8",

2
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f5dc0da6106cdc7158e5aa765c01596f",
"content-hash": "cbc3e39376e9371be37305d6cd955251",
"packages": [
{
"name": "composer/package-versions-deprecated",

106
src/Controller/AdminController.php Normal file → Executable file
View File

@ -2,17 +2,99 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Poll;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Route;
class AdminController extends AbstractController
{
#[Route('/admin', name: 'admin')]
public function index(): Response
{
return $this->render('admin/index.html.twig', [
'controller_name' => 'AdminController',
]);
}
/**
* Class DefaultController
* @package App\Controller
* @Route("/admin",name="admin_homepage")
*/
class AdminController extends FramadateController {
/**
* @Get(path ="/",
* name = "_get_default")
*/
public function indexAction() {
return $this->json( [ "message" => "welcome to the framadate admin api, ask /api/v1/doc.json for endpoints" ],
200 );
}
/**
* Delete all expired polls and their children
* @Get(
* path = "/polls/clean/{token}",
* name = "_clean_expired_polls",
* )
* token is set up in the main env file
*/
public
function cleanExpiredPolls(
string $token
) {
if ( $this->getParameter( 'admin_token' ) !== $token ) {
return $this->json( [
'message' => 'clean routine can NOT be done, your admin token is bad, and you should feel bad.',
],
403 );
}
$em = $this->getDoctrine()->getManager();
$emPoll = $this->getDoctrine()->getRepository( Poll::class );
$queryFind = $em->createQuery(
'SELECT p
FROM App\Entity\Poll p
WHERE p.expiracyDate < CURRENT_DATE()'
);
$queryDelete = $em->createQuery(
'DELETE
FROM App\Entity\Poll p
WHERE p.expiracyDate < CURRENT_DATE()'
);
$foundPolls = $queryFind->getResult();
$em->flush();
return $this->json( [
'message' => 'clean routine has been done, here are the numbers of polls deleted: ' . count( $foundPolls ),
'data' => [
'count' => count( $foundPolls ),
],
],
200 );
}
/**
* Delete all expired polls and their children
* @Get(
* path = "/polls/migrate",
* name = "_migrate_framadate",
* )
* token is set up in the main env file
*/
public
function runMigrationFromOldFramadate(
string $token
) {
// TODO
// fetch old polls and store their properties in new poll objects
$foundPolls = [];
$database_name = 'symfony';
$em = $this->getDoctrine()->getManager();
$emPoll = $this->getDoctrine()->getRepository( Poll::class );
return $this->json( [
'message' => 'migration done for: ' . count( $foundPolls ). ' - this feature is not ready to work YET.',
'data' => [
'count' => count( $foundPolls ),
],
],
200 );
}
}

View File

@ -0,0 +1,177 @@
<?php
namespace App\Controller;
use App\Entity\Comment;
use App\Entity\Owner;
use App\Entity\Poll;
use DateTime;
use FOS\RestBundle\Controller\Annotations\Delete;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\Route;
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Class DefaultController
* @package App\Controller
* @Route("/api/v1",name="api_")
*/
class CommentController extends FramadateController {
/**
* @Get(
* path = "/poll/{id}/comments",
* name = "get_poll_comment",
* requirements = {"id"="\d+"}
* )
*/
public
function getPollCommentsAction(
SerializerInterface $serializer,
Poll $poll
) {
$jsonResponse = $serializer->serialize([
'message' => 'here are your comments of the poll',
'data' => $poll->getComments()], 'json');
$response = new Response($jsonResponse);
$response->headers->set('Content-Type', 'application/json');
$response->setStatusCode(200);
return $response;
}
/**
* add a comment on a poll
* @Post(
* path = "/poll/{id}/comment",
* name = "new_comment",
* requirements = {"content"="\w+", "id"="\d+"}
* )
*/
public
function newCommentAction(
Poll $poll,
Request $request
) {
if ( ! $poll ) {
return $this->json( [ 'message' => 'poll not found' ], 404 );
}
$data = $request->getContent();
$serializer = SerializerBuilder::create()->build();
$comment = $serializer->deserialize( $data, 'App\Entity\Comment', 'json' );
$em = $this->getDoctrine()->getRepository( Owner::class );
$data = json_decode( $data, true );
if(!isset($data['email'])) {
return $this->json(["message" => "Incorrect JSON in request"], 400);
}
$foundOwner = $em->findOneByEmail( $data[ 'email' ] );
// manage existing or new Owner
if ( ! $foundOwner ) {
$foundOwner = new Owner();
$foundOwner->setPseudo( $data[ 'email' ] )
->setEmail( $data[ 'email' ] )
->setModifierToken( uniqid( '', true ) );
}
// anti flood
$seconds_limit_lastpost = 5;
$emComment = $this->getDoctrine()->getRepository( Comment::class );
$lastCommentOfOwner = $emComment->findBy( [ 'owner' => $foundOwner ], [ 'id' => 'desc' ] );
// TODO anti flood by session / IP
if ( $lastCommentOfOwner ) {
// check time of last comment
$now = new DateTime();
$now = $now->format( 'Y-m-d H:i:s' );
$date_first = strtotime( $lastCommentOfOwner[ 0 ]->getCreatedAt()->format( 'Y-m-d H:i:s' ) );
$date_second = strtotime( $now );
if ( ( $date_second - $date_first ) < $seconds_limit_lastpost ) {
return $this->json( [
'message' => 'anti flood déclenché',
'details' => 'votre deriner commentaire a été envoyé il y a moins de ' . $seconds_limit_lastpost . ' secondes',
],
403 );
}
// check similar text content
if ( $lastCommentOfOwner[ 0 ]->getText() == $comment->getText() ) {
return $this->json( [
'message' => 'anti flood déclenché',
'details' => 'votre deriner commentaire a exactement le même contenu que celui ci, il n\'a donc pas été créé',
],
403 );
}
}
$comment->setOwner( $foundOwner )
->setCreatedAt( new DateTime() )
->setPoll( $poll );
$foundOwner->addComment( $comment );
$em = $this->getDoctrine()->getManager();
$em->persist( $foundOwner );
$em->persist( $comment );
$em->flush();
if($poll->getMailOnComment()){
$this->sendCommentNotificationAction($foundOwner, $comment);
}
return $this->json( [
'message' => 'you created a comment',
'data' => [
'your_comment' => $comment->display(),
],
],
201 );
}
/**
* Erase all comments of a poll
* @Delete(
* path = "/poll/{id}/comments",
* name = "poll_comments_delete",
* requirements = {"accessToken"="\w+", "id"="\d+"}
* )
*
* @param Poll $poll
* @param $accessToken
*
* @return JsonResponse
*/
public
function deletePollCommentsAction(
Poll $poll,
$accessToken
) {
if ( $accessToken == $poll->getAdminKey() ) {
$em = $this->getDoctrine()->getManager();
$length = count( $poll->getComments() );
$em->remove( $poll->getComments() );
$em->flush();
return $this->json( [
'message' => 'boom! les ' . $length . ' commentaires du sondage ont été supprimés',
] );
} else {
return $this->json( [
'message' => 'le token d\'autorisation est invalide, vous ne pouvez pas modifier ce sondage',
] );
}
}
}

40
src/Controller/DefaultController.php Normal file → Executable file
View File

@ -2,17 +2,33 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Owner;
use App\Entity\Poll;
use App\Repository\PollRepository;
use App\Service\MailService;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Route;
use JMS\Serializer\Type\Exception\Exception;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
/**
* Class DefaultController
* @package App\Controller
* @Route("/",name="home_")
*/
class DefaultController extends FramadateController {
/**
* @Get(path ="/",
* name = "sweet_home")
*/
public function indexAction() {
$polls = $this->getDoctrine()->getRepository( Poll::class )->findAll();
return $this->render( 'pages/home.html.twig',[ ]);
}
class DefaultController extends AbstractController
{
#[Route('/', name: 'default')]
public function index(): Response
{
return $this->render('pages/home.html.twig', [
'controller_name' => 'DefaultController',
]);
}
}

15
src/Controller/FramadateController.php Executable file → Normal file
View File

@ -7,8 +7,6 @@ use App\Entity\Poll;
use JMS\Serializer\Type\Exception\Exception;
use Swift_Message;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* sending emails controller
@ -20,14 +18,16 @@ class FramadateController extends AbstractController {
private $mail_service;
// public function __construct( \Swift_Mailer $mailer ) {
// $this->mail_service = $mailer;
// }
public function __construct( \Swift_Mailer $mailer ) {
$this->mail_service = $mailer;
}
/**
* generic way to send email with html template
*
* @param $config
*
* @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
*/
public function sendMailWithVars( $config ) {
@ -69,7 +69,6 @@ class FramadateController extends AbstractController {
$numSent = $this->mail_service->send( $message );
$this->numSent = $numSent;
return 1;
}
@ -81,6 +80,7 @@ class FramadateController extends AbstractController {
*
* @return int|void
* @throws Exception
* @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
*/
public function sendOwnerPollsAction( Owner $owner ) {
@ -98,6 +98,7 @@ class FramadateController extends AbstractController {
* @param Owner $foundOwner
* @param Poll|null $poll
*
* @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
*/
public function sendCreationMailAction( Owner $foundOwner, Poll $poll = null ) {
@ -119,6 +120,7 @@ class FramadateController extends AbstractController {
* @param $comment
*
* @return int
* @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
*/
public function sendCommentNotificationAction( Owner $owner, $comment ) {
@ -139,6 +141,7 @@ class FramadateController extends AbstractController {
* @param $stackOfVotes
*
* @return int
* @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
*/
public function sendVoteNotificationAction( Owner $owner, $stackOfVotes ) {

46
src/Controller/MigrationController.php Normal file → Executable file
View File

@ -2,25 +2,31 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Poll;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Route;
/**
* Class DefaultController
* @package App\Controller
* @Route("/migration-from-v1",name="admin_homepage")
*/
class MigrationController extends FramadateController {
/**
* @Get(path ="/{unique_key}",
* name = "_migrate_from_v1")
*/
public function indexAction() {
// get env vars
// check uniq key is good
// fetch old Database
// gather objects
// create new polls
// success
// failure notice
return $this->json( [ "message" => "welcome to the framadate migration endpoint, it has yet to be done" ],
200 );
}
class MigrationController extends AbstractController
{
#[Route('/migration', name: 'migration')]
public function index(): Response
{
// TODO
// get env vars
// check uniq key is good
// fetch old Database
// gather objects
// create new polls
// success
// failure notice
return $this->render('migration/index.html.twig', [
'controller_name' => 'MigrationController',
]);
}
}

91
src/Controller/OwnerController.php Normal file → Executable file
View File

@ -2,17 +2,84 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Owner;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Route;
use JMS\Serializer\Type\Exception\Exception;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
/**
* Class DefaultController
* @package App\Controller
* @Route("/user",name="user_homepage")
*/
class OwnerController extends FramadateController {
/**
* @Get(path ="/",
* name = "get_default")
*/
public function indexAction() {
return $this->json( [ "message" => "welcome to the framadate user api, ask /api/v1/doc.json for endpoints" ],
200 );
}
/**
* Send a mail with all the data to one user
* @Get(
* path = "/{email}/polls/send-by-email",
* name = "_polls_send_by_email"
* )
*
* @param string $email
*
* @return JsonResponse
*/
public function sendPollsToUserAction( string $email ) {
$repository = $this->getDoctrine()->getRepository( Owner::class );
// find user by email
$owner = $repository->findOneByEmail( $email );
if ( $owner ) {
$templateVars = [
'owner' => $owner,
'polls' => $owner->getPolls(),
'title' => 'Mes sondages - ' . $owner->getEmail(),
];
// send email
$mailSent = 0;
try {
$mailSent = $this->sendOwnerPollsAction( $owner );
} catch ( Exception $e ) {
} catch ( TransportExceptionInterface $e ) {
}
if ( $mailSent ) {
return $this->json( [
'message' => 'mail succefully sent to user ' . $owner->getEmail(),
'data' => '',
],
200 );
}
return $this->json( [
'message' => 'no sucess sending email ' . $owner->getEmail(),
'data' => '',
],
400 );
}
return $this->json( [
'message' => 'no user found for email ' . $email,
'data' => '',
],
400 );
}
class OwnerController extends AbstractController
{
#[Route('/owner', name: 'owner')]
public function index(): Response
{
return $this->render('owner/index.html.twig', [
'controller_name' => 'OwnerController',
]);
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace App\Controller;
use App\Entity\Poll;
use App\Form\PollType;
use App\Repository\PollRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
/**
* @Route("/poll")
*/
class PollController extends AbstractController
{
/**
* @Route("/", name="poll_index", methods={"GET"})
*/
public function index(PollRepository $pollRepository): Response
{
return $this->render('poll/index.html.twig', [
'polls' => count($pollRepository->findAll()),
]);
}
/**
* @Route("/new", name="poll_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$poll = new Poll();
$form = $this->createForm(PollType::class, $poll);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($poll);
$entityManager->flush();
return $this->redirectToRoute('poll_index');
}
return $this->render('poll/new.html.twig', [
'poll' => $poll,
'form' => $form->createView(),
]);
}
/**
* on cherche un sondage par son url personnalisée
* @Route("/{id}", name="poll_show", methods={"GET"})
*/
public function show($id): Response
{
$repository = $this->getDoctrine()->getRepository(Poll::class);
$foundPoll = $repository->findOneByCustomUrl($id);
if(!$foundPoll){
return $this->json([
'message' => $id.' : not found'
], 404);
}
return $this->render('poll/show.html.twig', [
'poll' => $foundPoll,
]);
}
/**
* @Route("/{id}/edit", name="poll_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Poll $poll): Response
{
$form = $this->createForm(PollType::class, $poll);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('poll_index');
}
return $this->render('poll/edit.html.twig', [
'poll' => $poll,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="poll_delete", methods={"DELETE"})
*/
public function delete(Request $request, Poll $poll): Response
{
if ($this->isCsrfTokenValid('delete'.$poll->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($poll);
$entityManager->flush();
}
return $this->redirectToRoute('poll_index');
}
}

View File

@ -2,17 +2,215 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Entity\Choice;
use App\Entity\Owner;
use App\Entity\Poll;
use App\Entity\StackOfVotes;
use App\Entity\Vote;
use FOS\RestBundle\Controller\Annotations\Delete;
use FOS\RestBundle\Controller\Annotations\Patch;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\Route;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class VoteController extends AbstractController
{
#[Route('/vote', name: 'vote')]
public function index(): Response
{
return $this->render('vote/index.html.twig', [
'controller_name' => 'VoteController',
]);
}
/**
* Class DefaultController
* @package App\Controller
* @Route("/api/v1",name="api_")
*/
class VoteController extends FramadateController {
/**
* add a vote stack on a poll
* @Post(
* path = "/poll/{id}/answer",
* name = "new_vote_stack",
* requirements = {"content"="\w+", "poll_id"="\d+"}
* )
* @param SerializerInterface $serializer
* @param Poll $poll
* @param Request $request
*
* @return JsonResponse|Response
*/
public function newVoteStackAction(
SerializerInterface $serializer,
Poll $poll,
Request $request
) {
if ( ! $poll ) {
return $this->json( [ 'message' => 'poll not found' ], 404 );
}
$em = $this->getDoctrine()->getManager();
$data = $request->getContent();
$data = json_decode( $data, true );
$emOwner = $this->getDoctrine()->getRepository( Owner::class );
$emChoice = $this->getDoctrine()->getRepository( Choice::class );
$existingOwner = false;
$foundOwner = $emOwner->findOneByEmail( trim( $data[ 'email' ] ) );
// manage existing or new Owner
if ( ! $foundOwner ) {
$foundOwner = new Owner();
$foundOwner
->setEmail( $data[ 'email' ] )
->setPseudo( $data[ 'pseudo' ] );
} else {
$existingOwner = true;
}
// TODO anti flood
$foundOwner
->setModifierToken( $poll->generateAdminKey() );
$stack = new StackOfVotes();
$stack
->setOwner( $foundOwner )
->setPseudo( $data[ 'pseudo' ] )
->setPoll( $poll );
foreach ( $data[ 'votes' ] as $voteInfo ) {
if ( ! isset( $voteInfo[ 'value' ] ) ) {
continue;
}
$allowedValuesToAnswer = [ 'yes', 'maybe', 'no' ];
if ( ! in_array( $voteInfo[ 'value' ], $allowedValuesToAnswer ) ) {
return $this->json( [
'message' => 'answer ' . $voteInfo[ 'value' ] . ' is not allowed. should be yes, maybe, or no.',
'vote_stack' => $stack,
],
404 );
}
$vote = new Vote();
$foundChoice = $emChoice->find( $voteInfo[ 'choice_id' ] );
if ( ! $foundChoice ) {
return $this->json( [
'message' => 'choice ' . $voteInfo[ 'choice_id' ] . ' was not found',
'vote_stack' => $stack,
],
404 );
}
$vote->setPoll( $poll )
->setChoice( $foundChoice )
->setValue( $voteInfo[ 'value' ] );
$vote->setPoll( $poll );
$stack->addVote( $vote );
$poll->addVote( $vote );
$em->persist( $vote );
$em->persist( $foundChoice );
}
// find poll from choices
$poll->addStackOfVote( $stack );
$em->persist( $stack );
$em->persist( $poll );
$em->flush();
$precision = '';
if ( $existingOwner ) {
$precision = ' from an existing owner : ' . $foundOwner->getEmail();
}
$stacks = $poll->getStacksOfVotes();
if($poll->getMailOnVote()){
$this->sendVoteNotificationAction($stack->getOwner(), $stack);
}
$returnedVoteStack = $stack;
$jsonResponse = $serializer->serialize($returnedVoteStack, 'json');
$response = new Response($jsonResponse);
$response->headers->set('Content-Type', 'application/json');
$response->setStatusCode(200);
return $response;
}
/**
* update vote stack
* @Patch(
* path = "/vote-stack/{id}/token/{modifierToken}",
* name = "update_vote_stack",
* requirements = { "id"="\d+"}
* )
* @param SerializerInterface $serializer
* @param StackOfVotes $id
* @param $modifierToken
* @param Request $request
*
* @return JsonResponse|Response
*/
public
function updateVoteStackAction(
SerializerInterface $serializer,
StackOfVotes $id,
$modifierToken,
Request $request
) {
$voteStack = $id;
if ( ! $voteStack ) {
return $this->json( [ 'message' => 'vote stack not found' ], 404 );
}
$poll = $voteStack->getPoll();
// if only self users are allowed to modify a vote, check it
if ( ! $modifierToken || $voteStack->getOwner()->getModifierToken() !== $modifierToken ) {
return $this->json( [ 'message' => 'your token does not allow you to modify this vote ' ],
403 );
}
// everything is ok, we can update all the votes of the vote stack
//TODO
// match votes and choices
// update answers
// save evrything
$jsonResponse = $serializer->serialize([
'message' => 'ok',
'modifier_token' => $voteStack->getOwner()->getModifierToken(),
'vote_stack' => $voteStack,
], 'json');
$response = new Response($jsonResponse);
$response->headers->set('Content-Type', 'application/json');
$response->setStatusCode(200);
return $response;
}
/**
* @Delete(
* path = "/poll/{id}/votes/{accessToken}",
* name = "poll_votes_delete",
* requirements = {"accessToken"="\w+", "poll_id"="\d+"}
* )
* @return JsonResponse
*/
public
function deletePollVotesAction(
Poll $poll,
$accessToken
) {
if ( $accessToken == $poll->getAdminKey() ) {
$em = $this->getDoctrine()->getManager();
$length = count( $poll->getVotes() );
$em->remove( $poll->getVotes() );
$em->flush();
return $this->json( [
'message' => 'boom! les ' . $length . ' votes du sondage ont été supprimés',
],200 );
} else {
return $this->json( [
'message' => 'le token d\'autorisation est invalide, vous ne pouvez pas modifier ce sondage'
],403 );
}
}
}

View File

@ -0,0 +1,474 @@
<?php
namespace App\Controller\api;
use App\Controller\FramadateController;
use App\Entity\Choice;
use App\Entity\Owner;
use App\Entity\Poll;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\SerializerInterface;
use Swift_Mailer;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Put;
use FOS\RestBundle\Controller\Annotations\Delete;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\Route;
/**
* Class DefaultController
* @package App\Controller
* @Route("/api/v1/poll",name="api_")
*/
class PollController extends FramadateController {
/**
* @Get(
* path = "/",
* name = "get_all_polls"
* )
*/
public function getAllPollsAction() {
$repository = $this->getDoctrine()->getRepository( Poll::class );
$data = $repository->findAll();
return $this->json( [
'message' => 'here are your polls',
'poll' => count( $data ),
] );
}
/**
* @param $id
* message when the poll is not found
* @return JsonResponse
*/
public function notFoundPoll($id){
return $this->json( [
'message' => $id . ' : poll not found',
],
404 );
}
/**
* get a poll config by its custom URL, we do not want polls to be reachable by their numeric id
* @Get(
* path = "/{id}",
* name = "get_poll",
* requirements = {"id"="\w+"}
* )
*
* @param SerializerInterface $serializer
* @param Request $request
*
* @return JsonResponse|Response
*/
public function getPollConfig(
SerializerInterface $serializer,
$id,
Request $request
) {
$repository = $this->getDoctrine()->getRepository( Poll::class );
$poll = $repository->findOneByCustomUrl( $id );
if ( ! $poll ) {
return $this->notFoundPoll($id);
}
$comments = $poll->getComments();
$pass = $poll->getPassword();
$returnedPoll = [
'message' => 'your poll config for ' . $poll->getTitle(),
'password_protected' => $pass ? 'yes' : 'no',
// TODO do not render sub objects of owner, it returns too many things
'poll' => $poll,
'stacks_count' => count( $poll->getStacksOfVotes() ),
'stacks' => $poll->getStacksOfVotes(),
'choices_count' => $poll->computeAnswers(),
'choices' => $poll->getChoices(),
'comments' => $comments,
'comments_count' => count( $comments ),
];
/**
* password protected content
*/
if ( $pass ) {
// no password possibly given by this route
return $this->json( [
'message' => 'this is protected by a password,but you did not provide the encoded password parameter, and you should feel bad. ' ,
],
403 );
} else {
// free access to poll
return $this->returnPollData( $poll, $serializer );
}
}
/**
* get a poll config by its custom URL, we do not want polls to be reachable by their numeric id
* @Get(
* path = "/{id}/pass/{md5}",
* name = "get_protected_poll",
* requirements = {"id"="\w+"}
* )
*
* @param SerializerInterface $serializer
* @param Request $request
*
* @return JsonResponse|Response
*/
function getProtectedPoll($id,$md5, SerializerInterface $serializer){
$repository = $this->getDoctrine()->getRepository( Poll::class );
$poll = $repository->findOneByCustomUrl( $id );
if ( ! $poll ) {
return $this->notFoundPoll($id);
}
if ( $poll->getPassword() === $md5 ) {
// good matching pass
return $this->returnPollData( $poll, $serializer );
} else {
// wrong pass
return $this->json( [
'message' => 'this is protected by a password, your password "' . $md5 . '" is wrong, and you should feel bad',
'md5' => md5($md5),
'data' => null,
],
403 );
}
}
function returnPollData( $poll, $serializer ) {
$jsonResponse = $serializer->serialize( $poll, 'json' );
$response = new Response( $jsonResponse );
$response->headers->set( 'Content-Type', 'application/json' );
$response->setStatusCode( 200 );
return $response;
}
/**
* @Put(
* path = "/{id}/{token}",
* name = "update_poll",
* requirements = {"content"="\w+", "poll_id"="\d+"}
* )
*/
public function updatePollConfig(
Poll $poll,
string $token,
Request $request
) {
if ( $poll->getAdminKey() !== $token ) {
return $this->json( [
'message' => 'you are NOT allowed to update the poll ' . $poll->getTitle(),
],
403 );
}
// TODO check validity of request
// update only if we have the admin key
$em = $this->getDoctrine()->getManager();
$em->persist( $poll );
$em->flush();
return $this->json( [
'message' => 'you updated the poll ' . $poll->getTitle(),
],
200 );
}
/**
* @Post(
* path = "/",
* name = "new_poll",
* requirements = {"creator"="\w+"}
* )
* @param Request $request
*
* @return JsonResponse
*/
public function newPollAction( Request $request ) {
$data = $request->getContent();
$serializer = SerializerBuilder::create()->build();
try {
$newpoll = $serializer->deserialize( $data, 'App\Entity\Poll', 'json' );
} catch ( RuntimeException $e ) {
return $this->json( [ "message" => "Incorrect JSON in request" ], 400 );
}
$newpoll
->setAdminKey( $newpoll->generateAdminKey() )
->setCreationDate( new DateTime() )
->setModificationPolicy( 'nobody' );
$timeStamp = time() + ( 3600 * 24 * 90 ); // 90 days by default
$newpoll->setExpiracyDate( ( new DateTime() )->setTimestamp( $timeStamp ),
new DateTimeZone( 'Europe/Paris' ) );
$data = json_decode( $data, true );
$em = $this->getDoctrine()->getRepository( Owner::class );
$foundOwner = $em->findOneBy( [ 'email' => $data[ 'owner' ][ 'email' ] ] );
$userWasFound = false;
if ( ! $foundOwner ) {
//create a new owner
$owner = new Owner();
$owner->setPseudo( $data[ 'owner' ][ 'pseudo' ] );
$owner->setEmail( $data[ 'owner' ][ 'email' ] );
$foundOwner = $owner;
} else {
$userWasFound = true;
}
// link the owner and the poll
$newpoll->setOwner( $foundOwner );
$foundOwner->addPoll( $newpoll );
$em = $this->getDoctrine()->getManager();
$em->persist( $newpoll );
$em->persist( $foundOwner );
// emails
$newpoll->setMailOnComment( true );
$newpoll->setMailOnVote( true );
$newpoll->setHideResults( false );
// possible answers
$newpoll->setAllowedAnswers( [ 'yes' ] );
if ( $data[ 'voteChoices' ] ) {
switch ( $data[ 'voteChoices' ] ) {
case "only_yes":
default:
break;
}
}
// setup the password, converting the raw with md5 hash
if ( $data[ 'password' ] ) {
$newpoll->setPassword( $data[ 'password' ] );
}
// manage choices
// text kind of answers, dates are below
if ( $data[ 'pollType' ] == 'classic' ) {
$choices = $data[ 'dateList' ];
foreach ( $choices as $c ) {
$newChoice = new Choice();
$newChoice
->setPoll( $newpoll )
// ->setUrl( $c[ 'url' ] )
->setName( $c[ 'literal' ] );
$em->persist( $newChoice );
// TODO add also choices for each time range in a day
}
} elseif ( $data[ 'pollType' ] == 'dates' ) {
if ( $data[ 'allowSeveralHours' ] == true ) {
// different hours spans
$choices = $data[ 'dateList' ];
} else {
//TODO (Sébastien) I assume this shouldn't be empty ?
// all days have the same hour spans
}
}
$em->persist( $newpoll );
$em->flush();
$precision = '';
if ( $userWasFound ) {
$precision = 'from an existing user : ' . $foundOwner->getEmail();
}
$this->sendCreationMailAction( $foundOwner, $newpoll );
return $this->json( [
'message' => 'you created a poll ' . $precision,
'poll' => $newpoll,
'password_protected' => is_string( $newpoll->getPassword() ),
'admin_key' => $newpoll->getAdminKey(),
'owner_modifier_token' => $foundOwner->getModifierToken(),
],
201 );
}
/**
* @Get(
* path = "/mail/test-mail-poll/{emailChoice}",
* name = "test-mail-poll",
* )
*
* send the creation mail to owner
*
* @param Owner $admin_user
* @param Poll $poll
* @param Swift_Mailer $mailer
*
* @return int
* not that the email tktest_commentateur@tktest.com does not really exist
*/
// public function sendCreationMailAction( Owner $admin_user, Poll $poll, \Swift_Mailer $mailer) {
public function testSendCreationMailAction(
$emailChoice = 'tktest_commentateur@tktest.com'
) {
$em = $this->getDoctrine()->getRepository( Owner::class );
$foundOwner = $em->findOneByEmail( $emailChoice );
if ( $foundOwner ) {
$poll = $foundOwner->getPolls()[ 0 ];
$comment = $foundOwner->getComments()[ 0 ];
$sent = $this->sendOwnerPollsAction( $foundOwner, $poll );
if ( $sent ) {
return $this->json( [ "message" => "test email sent to " . $foundOwner->getEmail() . "!" ], 200 );
}
}
return $this->json( [ "message" => "user with this email was not found" ], 400 );
}
/**
* @Delete(
* path = "/{id}",
* name = "poll_delete",
* requirements = {"accessToken"="\w+", "poll_id"="\d+"}
* )
* @param Poll $poll
* @param $accessToken
*
* @return JsonResponse
*/
public
function deletePollAction(
Poll $poll,
$accessToken
) {
if ( $accessToken == $poll->getAdminKey() ) {
$em = $this->getDoctrine()->getManager();
$em->remove( $poll );
$em->flush();
return $this->json( [
'message' => 'boom! le sondage et ses objets assocités a été supprimé',
] );
} else {
return $this->json( [
'message' => 'le token d\'autorisation est invalide, vous ne pouvez pas modifier ce sondage',
] );
}
}
/**
* Checks if a slug is already taken by a poll
* @Get(
* path = "/slug/{slug}",
* name = "check_slug_is_unique",
* )
*/
public function checkSlugIsUniqueAction( string $slug ) {
$emPoll = $this->getDoctrine()->getRepository( Poll::class );
$found = $emPoll->findOneByCustomUrl( $slug );
$elaborated_message_version = false;
if ( $found ) {
if ( ! $elaborated_message_version ) {
return $this->json( null,
204 );
}
// we should use an other slug
return $this->json( [
'message' => ' NO, this slug is already taken on this Framadate instance ',
'data' => [
'slug' => $slug,
],
],
204 );
}
if ( ! $elaborated_message_version ) {
return $this->json( null,
404 );
}
return $this->json( [
'message' => ' yes this slug is available on this Framadate instance ',
'data' => [
'slug' => $slug,
],
],
404 );
}
/**
* Get Admin poll config
* @Get(
* path = "/admin/{token}",
* name = "get_admin_config",
* )
*
* @param SerializerInterface $serializer
* @param $token
*
* @return JsonResponse|Response
*/
public function getAdministrationConfig( SerializerInterface $serializer, $token ) {
$emPoll = $this->getDoctrine()->getRepository( Poll::class );
$pollFound = $emPoll->findOneByAdminKey( $token );
if ( $pollFound ) {
$poll = $pollFound;
$comments = $poll->getComments();
$stacks = $poll->getStacksOfVotes();
$returnedPoll = [
'message' => 'your poll config',
'poll' => $poll,
'stacks_count' => count( $stacks ),
'stacks' => $stacks,
'choices_count' => $poll->computeAnswers(),
'choices' => $poll->getChoices(),
'comments' => $comments,
'comments_count' => count( $comments ),
'token' => $token,
];
$jsonResponse = $serializer->serialize( $returnedPoll, 'json' );
$response = new Response( $jsonResponse );
$response->headers->set( 'Content-Type', 'application/json' );
$response->setStatusCode( 200 );
return $response;
}
return $this->json( [
'message' => 'You are not allowed to do anything with this token',
'data' => [
'token' => $token,
],
],
403 );
}
}

View File

@ -8,8 +8,8 @@
<li>
<a class="btn button rounded bg-purple-200 p-2" href="/">
<i class="fa fa-home"></i>
<img src="{{ WEBSITE_LOGO }}" alt="logo">
{{ WEBSITE_NAME }}
{# <img src="{{ WEBSITE_LOGO }}" alt="logo">#}
{# {{ WEBSITE_NAME }}#}
</a>
</li>

145
update.sh Executable file
View File

@ -0,0 +1,145 @@
#!/bin/bash
# script d'update de framadate api, fait pour fonctionner avec le sous module git funky framadate
# bash colors
cecho() {
local code="\033["
case "$1" in
black | bk) color="${code}0;30m";;
red | r) color="${code}1;31m";;
green | g) color="${code}1;32m";;
yellow | y) color="${code}1;33m";;
blue | b) color="${code}1;34m";;
purple | p) color="${code}1;35m";;
cyan | c) color="${code}1;36m";;
gray | gr) color="${code}0;37m";;
*) local text="$1"
esac
[ -z "$text" ] && local text="$color$2${code}0m"
echo -e "$text"
}
cecho g "######################"
cecho g " time to update the framadate setup"
cecho g "######################"
COMMAND_BUILD="build:prod:demobliss"
# git reset --hard
git pull origin master
composer install
php bin/console doctrine:schema:update --force
cecho g "######################"
cecho g " update the funky frontend submodule "
cecho g "############################################"
cecho g " verification des besoins de l'application "
cecho g "############################################"
cecho g " yarn, git, php, node et une base de données"
cecho g "############################################${reset}"
# True if $1 is an executable in $PATH
# Works in both {ba,z}sh
function is_bin_in_path {
if [[ -n $ZSH_VERSION ]]; then
builtin whence -p "$1" &> /dev/null
else # bash:
builtin type -P "$1" &> /dev/null
fi
}
if [ ! type yarn &> /dev/null ]; then
cecho red " ❌ la commande yarn est introuvable"
exit 1
fi
cecho g " ✅ yarn"
if [ ! type node &> /dev/null ]; then
cecho red " ❌ la commande node est introuvable"
exit 1
fi
cecho g " ✅ node"
if [ ! type git &> /dev/null ]; then
cecho g " ❌ la commande git est introuvable"
exit 1
fi
cecho g " ✅ git"
if [ ! -f .env ]; then
cecho g " ❌ fichier d'environnement de symfony /.env"
exit 1
fi
cecho g " ✅ fichier d'environnement de symfony /.env ou /.env.local"
if [ ! -f bin/console ]; then
cecho g " ❌ fichier console de symfony"
exit 1
fi
cecho g " ✅ fichier console de symfony /bin/console "
if [ ! -d "funky-framadate-front" ]; then
# initiate sub directory for funky front
git submodule add -f https://framagit.org/framasoft/framadate/funky-framadate-front
git submodule init
fi
git config --global diff.submodule log
git submodule update
cecho g "######################"
cecho g " check dependencies of the frontend with yarn "
cecho g "######################"
cd funky-framadate-front
cecho g "######################"
cecho g " debug info : version of programs"
cecho g " "
cecho b " git current branch "
git show-branch
cecho b " node version "
node -v
cecho b " yarn version "
yarn -v
cecho g " "
cecho b "##############################################"
cecho b " update of the funky part, clean of local repo"
cecho g " "
git reset --hard
git remote -v
git fetch
git pull
yarn
cecho g "######################"
cecho g " building the frontend, should take around 20 seconds "
cecho g " "
cecho y " npm run $COMMAND_BUILD "
cecho g " "
cecho y " start: $(date) "
cecho g "######################"
npm run $COMMAND_BUILD
cecho g "######################"
cecho g " copying built files in the public folder of the symfony project "
cecho g "######################"
cd ../public
rm ./*.js
rm ./*.css
cd ../funky-framadate-front
cp -r dist/framadate/* ../public/
COUNT_FILES=$(ls -larth ../public |wc -l)
cd ..
cecho b " $COUNT_FILES fichiers de build copiés dans /public"
cecho g "##################################################################"
cecho b " renaming unieque name of JS chunks to common names for templates "
cd public
mv runtime* runtime.js
mv main* main.js
mv polyfills-es5* es5-polyfills.js
mv polyfills* other-polyfills.js
mv scripts* scripts.js
mv styles* styles.css
cecho b " finished at ------- $(date) ------- "
cecho g "##################################################################"
cecho g " "
cecho b " done. you can now see your homepage updated "
cecho g " "
cecho g "##################################################################"