parent
bfdceb4a1f
commit
d286d6291e
@ -1,33 +0,0 @@
|
||||
# In all environments, the following files are loaded if they exist,
|
||||
# the latter taking precedence over the former:
|
||||
#
|
||||
# * .env contains default values for the environment variables needed by the app
|
||||
# * .env.local uncommitted file with local overrides
|
||||
# * .env.$APP_ENV committed environment-specific defaults
|
||||
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||
#
|
||||
# Real environment variables win over .env files.
|
||||
#
|
||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||
#
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=prod
|
||||
APP_SECRET=597b0529ac702d27dcb9089f7e69c362
|
||||
# Base website url, should contain https:// and having no trailing slash. example: BASE_URL=https://framadate.org
|
||||
BASE_URL=https://framadate-api.cipherbliss.com
|
||||
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
|
||||
#TRUSTED_HOSTS='^localhost|example\.com$'
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
|
||||
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11"
|
||||
# IMPORTANT: You MUST also configure your db driver and server_version in config/packages/doctrine.yaml
|
||||
# CHANGE THIS TO SUIT YOUR PRODUCTION ENV
|
||||
DATABASE_URL=mysql://root:plopplop01@127.0.0.1:5432/symfony
|
||||
|
||||
###< doctrine/doctrine-bundle ###
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Welcome to your app's main JavaScript file!
|
||||
*
|
||||
* We recommend including the built version of this JavaScript file
|
||||
* (and its CSS file) in your base layout (base.html.twig).
|
||||
*/
|
||||
|
||||
// any CSS you import will output into a single css file (app.css in this case)
|
||||
import './styles/app.scss';
|
||||
|
||||
// Need jQuery? Install it with "yarn add jquery", then uncomment to import it.
|
||||
// import $ from 'jquery';
|
||||
|
||||
console.log('Hello Webpack Encore! Edit me in assets/app.js');
|
@ -0,0 +1,3 @@
|
||||
@import 'pages/libs';
|
||||
@import 'pages/global';
|
||||
@import 'pages/home';
|
@ -0,0 +1,3 @@
|
||||
body {
|
||||
background-color: lightgray;
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
@import '~font-awesome/css/font-awesome.min.css';
|
||||
@import '~tailwindcss/dist/tailwind.min.css';
|
@ -0,0 +1,3 @@
|
||||
framework:
|
||||
assets:
|
||||
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
|
@ -0,0 +1,4 @@
|
||||
#webpack_encore:
|
||||
# Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
||||
# Available in version 1.2
|
||||
#cache: true
|
@ -0,0 +1,2 @@
|
||||
#webpack_encore:
|
||||
# strict_mode: false
|
@ -0,0 +1,25 @@
|
||||
webpack_encore:
|
||||
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
|
||||
output_path: '%kernel.project_dir%/public/build'
|
||||
# If multiple builds are defined (as shown below), you can disable the default build:
|
||||
# output_path: false
|
||||
|
||||
# if using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
|
||||
# crossorigin: 'anonymous'
|
||||
|
||||
# preload all rendered script and link tags automatically via the http2 Link header
|
||||
# preload: true
|
||||
|
||||
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
|
||||
# strict_mode: false
|
||||
|
||||
# if you have multiple builds:
|
||||
# builds:
|
||||
# pass "frontend" as the 3rg arg to the Twig functions
|
||||
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
|
||||
|
||||
# frontend: '%kernel.project_dir%/public/frontend/build'
|
||||
|
||||
# Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
||||
# Put in config/packages/prod/webpack_encore.yaml
|
||||
# cache: true
|
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "date-poll-api",
|
||||
"version": "1.0.0",
|
||||
"description": "API date to make surveys, kind of the new Framadate",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
"test": "tests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@symfony/webpack-encore": "^0.31.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"tailwindcss": "^1.9.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"node-sass": "^4.14.1",
|
||||
"sass-loader": "^9.0.0",
|
||||
"webpack-notifier": "1.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev-server": "encore dev-server",
|
||||
"dev": "encore dev",
|
||||
"watch": "encore dev --watch",
|
||||
"build": "encore production"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://framagit.org/tykayn/date-poll-api.git"
|
||||
},
|
||||
"keywords": [
|
||||
"survey",
|
||||
"poll",
|
||||
"sondage",
|
||||
"api",
|
||||
"symfony"
|
||||
],
|
||||
"author": "tykayn",
|
||||
"license": "AGPL-3.0-or-later"
|
||||
}
|
@ -0,0 +1,412 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\api;
|
||||
|
||||
use App\Controller\FramadateController;
|
||||
use App\Entity\Choice;
|
||||
use App\Entity\Owner;
|
||||
use App\Entity\Poll;
|
||||
use FOS\RestBundle\Controller\Annotations\Delete;
|
||||
use FOS\RestBundle\Controller\Annotations\Get;
|
||||
use FOS\RestBundle\Controller\Annotations\Post;
|
||||
use FOS\RestBundle\Controller\Annotations\Put;
|
||||
use FOS\RestBundle\Controller\Annotations\Route;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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' => $data,
|
||||
],
|
||||
200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get(
|
||||
* path = "/{id}",
|
||||
* name = "get_poll",
|
||||
* requirements = {"poll_id"="\d+"}
|
||||
* )
|
||||
* @param SerializerInterface $serializer
|
||||
* @param Poll $poll
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse|Response
|
||||
*/
|
||||
public function getPollConfig(
|
||||
SerializerInterface $serializer,
|
||||
Poll $poll,
|
||||
Request $request
|
||||
) {
|
||||
$pass = $poll->getPassword();
|
||||
$data = $request->getContent();
|
||||
$data = json_decode( $data, true );
|
||||
|
||||
$comments = $poll->getComments();
|
||||
|
||||
$returnedPoll = [
|
||||
'message' => 'your poll config',
|
||||
'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 && $pass !== md5( $data[ 'password_input' ] ) ) {
|
||||
return $this->json( [
|
||||
'message' => 'your password ' . $data[ 'password_input' ] . ' is wrong, and you should feel bad',
|
||||
'data' => null,
|
||||
],
|
||||
403 );
|
||||
} else {
|
||||
$jsonResponse = $serializer->serialize( $returnedPoll, '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',
|
||||
] );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is 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 );
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Poll;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class PollType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('title')
|
||||
->add('customUrl')
|
||||
->add('description')
|
||||
->add('creationDate')
|
||||
->add('expiracyDate')
|
||||
->add('kind')
|
||||
->add('allowedAnswers')
|
||||
->add('modificationPolicy')
|
||||
->add('mailOnComment')
|
||||
->add('mailOnVote')
|
||||
->add('hideResults')
|
||||
->add('showResultEvenIfPasswords')
|
||||
->add('password')
|
||||
->add('adminKey')
|
||||
->add('owner')
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Poll::class,
|
||||
]);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% block body %}
|
||||
|
||||
<section class="home">
|
||||
<h1>Accueil</h1>
|
||||
<div>
|
||||
{{ polls|length }} sondages
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
@ -0,0 +1,5 @@
|
||||
<form method="post" action="{{ path('poll_delete', {'id': poll.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ poll.id) }}">
|
||||
<button class="btn">Delete</button>
|
||||
</form>
|
@ -0,0 +1,4 @@
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form) }}
|
||||
<button class="btn">{{ button_label|default('Save') }}</button>
|
||||
{{ form_end(form) }}
|
@ -0,0 +1,13 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Edit Poll{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Edit Poll</h1>
|
||||
|
||||
{{ include('poll/_form.html.twig', {'button_label': 'Update'}) }}
|
||||
|
||||
<a href="{{ path('poll_index') }}">back to list</a>
|
||||
|
||||
{{ include('poll/_delete_form.html.twig') }}
|
||||
{% endblock %}
|
@ -0,0 +1,61 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Poll index{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Poll index</h1>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Title</th>
|
||||
<th>CustomUrl</th>
|
||||
<th>Description</th>
|
||||
<th>CreationDate</th>
|
||||
<th>ExpiracyDate</th>
|
||||
<th>Kind</th>
|
||||
<th>AllowedAnswers</th>
|
||||
<th>ModificationPolicy</th>
|
||||
<th>MailOnComment</th>
|
||||
<th>MailOnVote</th>
|
||||
<th>HideResults</th>
|
||||
<th>ShowResultEvenIfPasswords</th>
|
||||
<th>Password</th>
|
||||
<th>AdminKey</th>
|
||||
<th>actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for poll in polls %}
|
||||
<tr>
|
||||
<td>{{ poll.id }}</td>
|
||||
<td>{{ poll.title }}</td>
|
||||
<td>{{ poll.customUrl }}</td>
|
||||
<td>{{ poll.description }}</td>
|
||||
<td>{{ poll.creationDate ? poll.creationDate|date('Y-m-d H:i:s') : '' }}</td>
|
||||
<td>{{ poll.expiracyDate ? poll.expiracyDate|date('Y-m-d H:i:s') : '' }}</td>
|
||||
<td>{{ poll.kind }}</td>
|
||||
<td>{{ poll.allowedAnswers ? poll.allowedAnswers|join(', ') : '' }}</td>
|
||||
<td>{{ poll.modificationPolicy }}</td>
|
||||
<td>{{ poll.mailOnComment ? 'Yes' : 'No' }}</td>
|
||||
<td>{{ poll.mailOnVote ? 'Yes' : 'No' }}</td>
|
||||
<td>{{ poll.hideResults ? 'Yes' : 'No' }}</td>
|
||||
<td>{{ poll.showResultEvenIfPasswords ? 'Yes' : 'No' }}</td>
|
||||
<td>{{ poll.password }}</td>
|
||||
<td>{{ poll.adminKey }}</td>
|
||||
<td>
|
||||
<a href="{{ path('poll_show', {'id': poll.id}) }}">show</a>
|
||||
<a href="{{ path('poll_edit', {'id': poll.id}) }}">edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="16">no records found</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<a href="{{ path('poll_new') }}">Create new</a>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}New Poll{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Create new Poll</h1>
|
||||
|
||||
{{ include('poll/_form.html.twig') }}
|
||||
|
||||
<a href="{{ path('poll_index') }}">back to list</a>
|
||||
{% endblock %}
|
@ -0,0 +1,78 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Poll{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Poll</h1>
|
||||
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<td>{{ poll.id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<td>{{ poll.title }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>CustomUrl</th>
|
||||
<td>{{ poll.customUrl }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<td>{{ poll.description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>CreationDate</th>
|
||||
<td>{{ poll.creationDate ? poll.creationDate|date('Y-m-d H:i:s') : '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>ExpiracyDate</th>
|
||||
<td>{{ poll.expiracyDate ? poll.expiracyDate|date('Y-m-d H:i:s') : '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Kind</th>
|
||||
<td>{{ poll.kind }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>AllowedAnswers</th>
|
||||
<td>{{ poll.allowedAnswers ? poll.allowedAnswers|join(', ') : '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>ModificationPolicy</th>
|
||||
<td>{{ poll.modificationPolicy }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>MailOnComment</th>
|
||||
<td>{{ poll.mailOnComment ? 'Yes' : 'No' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>MailOnVote</th>
|
||||
<td>{{ poll.mailOnVote ? 'Yes' : 'No' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>HideResults</th>
|
||||
<td>{{ poll.hideResults ? 'Yes' : 'No' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>ShowResultEvenIfPasswords</th>
|
||||
<td>{{ poll.showResultEvenIfPasswords ? 'Yes' : 'No' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Password</th>
|
||||
<td>{{ poll.password }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>AdminKey</th>
|
||||
<td>{{ poll.adminKey }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<a href="{{ path('poll_index') }}">back to list</a>
|
||||
|
||||
<a href="{{ path('poll_edit', {'id': poll.id}) }}">edit</a>
|
||||
|
||||
{{ include('poll/_delete_form.html.twig') }}
|
||||
{% endblock %}
|
@ -0,0 +1,14 @@
|
||||
{% block footer %}
|
||||
<footer>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/">
|
||||
<i class="fa fa-home"></i>
|
||||
</a>
|
||||