František Špaček 2 years ago
parent b02b80c612
commit e3f51c95e3

@ -30,6 +30,10 @@ security:
check_path: users_login check_path: users_login
logout: logout:
path: users_logout path: users_logout
json_login:
check_path: api_users_login
username_path: email
password_path: password
# Easy way to control access for large sections of your site # Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used # Note: Only the *first* access control that matches will be used

@ -166,10 +166,14 @@ class ChartLoader {
let tooltipPos = obj[0].getTooltipPos() let tooltipPos = obj[0].getTooltipPos()
// Adjust tooltip position to fit within the chart div // Adjust tooltip position to fit within the chart div
if (tooltipPos.right.x + this.tooltip.clientWidth <= this.parent.clientWidth - 2) if (tooltipPos.right.x + this.tooltip.clientWidth <= this.parent.clientWidth - 2) {
this.tooltip.className = "tooltip leftArrow"
this.tooltip.style.left = tooltipPos.right.x + 5 + "px" this.tooltip.style.left = tooltipPos.right.x + 5 + "px"
else }
else {
this.tooltip.className = "tooltip rightArrow"
this.tooltip.style.left = tooltipPos.left.x - this.tooltip.clientWidth + "px" this.tooltip.style.left = tooltipPos.left.x - this.tooltip.clientWidth + "px"
}
// Check if the tooltip extends beyond the bottom edge of the chart div // Check if the tooltip extends beyond the bottom edge of the chart div
if (tooltipPos.right.y + this.tooltip.clientHeight <= parent.clientHeight - 2) if (tooltipPos.right.y + this.tooltip.clientHeight <= parent.clientHeight - 2)

@ -214,9 +214,14 @@ class PieSlice extends Circle {
* @returns {Object} An object containing x and y coordinates for the tooltip position. * @returns {Object} An object containing x and y coordinates for the tooltip position.
*/ */
getTooltipPos() { getTooltipPos() {
let angle = (this.sAngle + this.eAngle) / 2
let pos = {
x: this.x + Math.cos(angle) * this.r,
y: this.y + Math.sin(angle) * this.r
}
return { return {
right: this.getCenter(), right: pos,
left: this.getCenter() left: pos
} }
} }
} }

@ -48,8 +48,8 @@ body {
/* Styles for legend items */ /* Styles for legend items */
#chartLegend div { #chartLegend div {
display: inline; display: inline;
margin: 0 10px 0 10px; /* Spacing between legend items */ margin: 0 1rem 0 1rem; /* Spacing between legend items */
width: 50px; width: 5rem;
} }
/* Styles for the tooltip */ /* Styles for the tooltip */
@ -59,8 +59,9 @@ body {
background-color: white; background-color: white;
border: 1px solid grey; border: 1px solid grey;
text-align: center; text-align: center;
padding: 5px; padding: 0.5rem;
border-radius: 3px; border-radius: 0.1rem;
/*box-shadow: 0.2rem 0.2rem 0.2rem lightgrey;*/
z-index: 1; /* Ensure tooltip appears above other elements */ z-index: 1; /* Ensure tooltip appears above other elements */
} }
@ -76,7 +77,7 @@ body {
} }
/* Styles for tooltip arrow */ /* Styles for tooltip arrow */
#tooltip::after { .leftArrow::after {
content: ""; /* Create a pseudo-element */ content: ""; /* Create a pseudo-element */
position: absolute; /* Position relative to its containing block */ position: absolute; /* Position relative to its containing block */
top: 50%; /* Position vertically centered */ top: 50%; /* Position vertically centered */
@ -86,3 +87,14 @@ body {
border-style: solid; /* Solid border */ border-style: solid; /* Solid border */
border-color: transparent white transparent transparent; /* Arrow color */ border-color: transparent white transparent transparent; /* Arrow color */
} }
.rightArrow::before {
content: ""; /* Create a pseudo-element */
position: absolute; /* Position relative to its containing block */
top: 50%; /* Position vertically centered */
left: 100%; /* Position to the left of the tooltip */
margin-top: -0.5rem; /* Adjust vertical position */
border-width: 0.5rem; /* Size of the arrow */
border-style: solid; /* Solid border */
border-color: transparent transparent transparent white; /* Arrow color */
}

@ -25,6 +25,7 @@ main form {
text-align: center; text-align: center;
overflow: scroll; overflow: scroll;
flex-basis: 25%; flex-basis: 25%;
margin-right: 0.5rem;
} }
#settings_div h1{ #settings_div h1{
@ -172,28 +173,26 @@ div[id^="chart_metadata_group"] {
} }
/* Media query for smaller screens */ /* Media query for smaller screens */
@media (max-width: 950px) { @media (max-width: 760px) {
#mainDiv { #mainDiv {
display: block flex-direction: column-reverse;
} }
#chartDiv { #chartDiv {
width: 100%; width: auto;
flex-basis: 60%;
} }
#settings_div { #settings_div {
width: 100%; margin-top: 1rem;
display: block width: auto;
flex-basis: 40%;
} }
#tableDiv { #tableDiv {
width: 100% width: 100%
} }
#shareDiv {
width: 100%
}
#secondaryDiv { #secondaryDiv {
display: block display: block
} }

@ -17,16 +17,21 @@ body {
padding: 0; padding: 0;
} }
button, #createChart { button,
#createChart {
background-color: var(--main-dark); background-color: var(--main-dark);
border: none; border: none;
color: white; color: white;
padding: 10px 15px; padding: 1rem 1.5rem;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
font-size: 16px; margin: 0.3rem;
margin: 5px; font-size: 1rem;
}
#createChart {
font-size: 1.5rem;
} }
button:hover { button:hover {
@ -52,7 +57,8 @@ header nav {
justify-content: flex-end; justify-content: flex-end;
} }
header #homepageLink:hover, header #chartsLink:hover { header #homepageLink:hover,
header #chartsLink:hover {
background-color: var(--main-highlight); background-color: var(--main-highlight);
} }
@ -123,7 +129,8 @@ h2 {
flex-direction: column; flex-direction: column;
} }
.loginDiv #user div, .loginDiv form > div { .loginDiv #user div,
.loginDiv form>div {
width: auto; width: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -133,10 +140,27 @@ h2 {
color: red; color: red;
} }
.loginDiv #logoutBtn { .loginDiv #logoutBtn,
#deleteBtn {
color: red; color: red;
} }
#accountButtonsDiv {
height: 6rem;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
#logoutBtn {
margin-bottom: 2rem;
}
#logoutBtn:hover,
#deleteBtn:hover {
color: darkred;
}
#myCharts { #myCharts {
height: 100%; height: 100%;
width: 100%; width: 100%;
@ -162,7 +186,7 @@ h2 {
flex-direction: column; flex-direction: column;
} }
#myChartList span{ #myChartList span {
width: 80%; width: 80%;
margin: 10px 10%; margin: 10px 10%;
/*border: 1px solid var(--main-dark);*/ /*border: 1px solid var(--main-dark);*/
@ -170,7 +194,7 @@ h2 {
display: flex; display: flex;
} }
#myChartList span a{ #myChartList span a {
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
height: 100%; height: 100%;
@ -187,7 +211,7 @@ h2 {
background-color: var(--main-highlight); background-color: var(--main-highlight);
} }
#myChartList #removeChart{ #myChartList #removeChart {
color: red; color: red;
display: inline-block; display: inline-block;
text-align: middle; text-align: middle;
@ -195,7 +219,7 @@ h2 {
transition: 300ms; transition: 300ms;
} }
#myChartList #removeChart:hover{ #myChartList #removeChart:hover {
background-color: var(--main-highlight); background-color: var(--main-highlight);
color: red; color: red;
transition: 300ms; transition: 300ms;

@ -11,30 +11,27 @@ use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
#[Rest\Route(path: '/api/charts', name: 'api_charts')] #[Rest\Route(path: '/api/charts', name: 'api_charts_')]
class ChartRestController extends AbstractRestController class ChartRestController extends AbstractRestController
{ {
#[Rest\Get('/', name: '_list')] #[Rest\Get('/', name: 'list')]
public function list(DocumentManager $dm, Request $request) : Response public function list(DocumentManager $dm, Request $request) : Response
{ {
$charts = \array_map(fn(Chart $entity) => ChartOutput::fromEntity($entity)->id, $dm->getRepository(Chart::class)->findAll()); $charts = \array_map(fn(Chart $entity) => ChartOutput::fromEntity($entity)->id, iterator_to_array($this->getUser()->getCharts()));
return $this->respond($charts, Response::HTTP_OK); return $this->respond($charts, Response::HTTP_OK);
} }
#[Rest\Get('/{id}', name: '_detail')]//, requirements: ['id' => '\d+'])] #[Rest\Get('/{id}', name: 'detail')]
public function detail(DocumentManager $dm, Chart $chart): Response public function detail(DocumentManager $dm, Chart $chart): Response
{ {
//$chart = $this->findOrFail($dm, $id);
$chartDto = ChartOutput::fromEntity($chart); $chartDto = ChartOutput::fromEntity($chart);
return $this->respond( $chartDto, Response::HTTP_OK); return $this->respond( $chartDto, Response::HTTP_OK);
} }
#[Rest\Put('/insert', name: '_insert')] #[Rest\Post('/insert', name: 'insert')]
public function insert(DocumentManager $dm, Request $request): Response public function insert(DocumentManager $dm, Request $request): Response
{ {
//$chart = $newChart->toEntity();
$data = json_decode($request->getContent()); $data = json_decode($request->getContent());
$chart = new Chart(); $chart = new Chart();
$chart->setName($data->name); $chart->setName($data->name);
@ -46,15 +43,25 @@ class ChartRestController extends AbstractRestController
return $this->respond( $chart->getName(), Response::HTTP_OK); return $this->respond( $chart->getName(), Response::HTTP_OK);
} }
/*private function findOrFail(DocumentManager $dm, int $id): Chart #[Rest\Post('/{id}/update', name: 'update')]
public function update(DocumentManager $dm, Request $request, Chart $chart): Response
{ {
//$chart = $dm->getRepository(Chart::class)->findOneBy(['code' => $id]); $data = json_decode($request->getContent());
$chart = $dm->getRepository(Chart::class)->findOneBy(['_id' => $id]); $chart->setName($data->name);
$chart->setMetadata($data->metadata);
$chart->setTable($data->table);
$dm->persist($chart);
$dm->flush();
return $this->respond( $chart->getName(), Response::HTTP_OK);
}
if ($chart === null) { #[Rest\Delete('/{id}/remove', name:'remove')]
throw $this->createNotFoundException("Chart was not found"); public function remove(DocumentManager $dm, Request $request, Chart $chart): Response
} {
$dm->remove($chart);
$dm->flush();
return $chart ; return $this->respond( $chart->getName(), Response::HTTP_OK);
}*/ }
} }

@ -0,0 +1,23 @@
<?php
namespace App\Api\Controller;
use App\Document\User;
use Doctrine\ODM\MongoDB\DocumentManager;
use App\Api\Controller\AbstractRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
#[Rest\Route(path: '/api/users', name: 'api_users_')]
class UserRestController extends AbstractRestController
{
#[Rest\Post('/login', name: 'login')]
public function login(DocumentManager $dm, #[CurrentUser] ?User $user): Response
{
return $this->json([
'user' => $user ? $user->getId() : null,
]);
}
}

@ -4,6 +4,7 @@ namespace App\Controller;
use App\Document\Chart; use App\Document\Chart;
use App\Form\Type\ChartType; use App\Form\Type\ChartType;
use App\Form\Type\DeleteType;
use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\DocumentManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -63,11 +64,22 @@ class ChartController extends AbstractController
} }
#[Route('/{id}/remove', name: 'remove')] #[Route('/{id}/remove', name: 'remove')]
public function removeAction(DocumentManager $dm, Chart $chart) : Response public function removeAction(DocumentManager $dm, Request $request, Chart $chart) : Response
{ {
$dm->remove($chart); $form = $this->createForm(DeleteType::class, $chart);
//$this->getUser()->removeChart($chart); $form->handleRequest($request);
$dm->flush();
return $this->redirectToRoute('charts_list'); if ($form->isSubmitted() && $form->isValid()) {
$dm->remove($chart);
//$this->getUser()->removeChart($chart);
$dm->flush();
return $this->redirectToRoute('charts_list');
}
return $this->render('chart/remove.html.twig', [
'form' =>$form->createView(),
'entity' => $chart
]);
} }
} }

@ -14,4 +14,9 @@ class IndexController extends AbstractController
return $this->render('index.html.twig'); return $this->render('index.html.twig');
} }
#[Route('/docs', name: 'docs')]
public function docsAction(): Response
{
return $this->render('docs.html.twig');
}
} }

@ -5,6 +5,7 @@ namespace App\Controller;
use App\Document\User; use App\Document\User;
use App\Form\Type\UserType; use App\Form\Type\UserType;
use App\Form\Type\LoginType; use App\Form\Type\LoginType;
use App\Form\Type\DeleteType;
use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\DocumentManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
@ -30,6 +31,9 @@ class UserController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData(); $user = $form->getData();
if ($dm->getRepository(User::class)->findOneBy(['email'=> $user->getEmail()]))
throw $this->createAccessDeniedException('Email již někdo používá');
$hashedPassword = $passwordHasher->hashPassword($user, $user->getPassword()); $hashedPassword = $passwordHasher->hashPassword($user, $user->getPassword());
$user->setPassword($hashedPassword); $user->setPassword($hashedPassword);
@ -83,4 +87,24 @@ class UserController extends AbstractController
'form' => $form->createView() 'form' => $form->createView()
]); ]);
} }
#[Route('/{id}/remove', name: 'remove')]
public function removeAction(DocumentManager $dm, Request $request, User $user) : Response
{
$form = $this->createForm(DeleteType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user->getCharts()->clear();
$dm->remove($user);
$dm->flush();
return $this->redirectToRoute('userss_list');
}
return $this->render('user/remove.html.twig', [
'form' =>$form->createView(),
'entity' => $user
]);
}
} }

@ -0,0 +1,29 @@
<?php
namespace App\Form\Type;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class DeleteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$resolver = new OptionsResolver();
$this->configureOptions($resolver);
$builder
->add('button', SubmitType::class, [
'label'=> 'Smazat',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
/*$resolver
->setRequired('entity')
->setAllowedTypes('entity', 'string');*/
}
}

@ -117,6 +117,7 @@
<div id="logo"> <div id="logo">
<a href="/">EasyCharts</a> <a href="/">EasyCharts</a>
</div> </div>
<nav></nav>
<div id="user"> <div id="user">
<a href="/users/login">Přihlásit</a> <a href="/users/login">Přihlásit</a>
</div> </div>

@ -0,0 +1,16 @@
{% extends 'base.html.twig' %}
{% block title %}
Smazat graf
{% endblock %}
{% block body %}
{{ parent() }}
<main>
<div id="myCharts">
<h1>Smazání grafu</h1>
<p>Opravdu chcete smazat graf: {{ entity.name }} ?</p>
{{ form(form) }}
</div>
</main>
{% endblock %}

@ -0,0 +1,16 @@
{% extends 'base.html.twig' %}
{% block title %}
Dokumentace
{% endblock %}
{% block body %}
{{ parent() }}
<h1>Interaktivní grafy</h1>
<section>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus odio neque est voluptatum
repellat animi dicta aliquam ipsa culpa commodi.
</p>
</section>
{% endblock %}

@ -3,7 +3,10 @@
<a href={{ path('homepage') }} id="homepageLink">Index</a> <a href={{ path('homepage') }} id="homepageLink">Index</a>
</div> </div>
<nav> <nav>
<a href={{ path('charts_list') }} id="chartsLink">Charts</a> <a href={{ path('docs') }}>Dokumentace</a>
{% if app.user %}
<a href={{ path('charts_list') }} id="chartsLink">Moje grafy</a>
{% endif %}
</nav> </nav>
<div id="user"> <div id="user">
{% if app.user %} {% if app.user %}

@ -1,7 +1,7 @@
{% extends 'base.html.twig' %} {% extends 'base.html.twig' %}
{% block title %} {% block title %}
Home Domovská stránka
{% endblock %} {% endblock %}
{% block body %} {% block body %}

@ -14,7 +14,10 @@
<button type="submit">Změnit heslo</button> <button type="submit">Změnit heslo</button>
{{ form_end(form, {'render_rest': false}) }} {{ form_end(form, {'render_rest': false}) }}
<a id="logoutBtn" href="{{ path('users_logout') }}">Odhlásit se</a> <div id="accountButtonsDiv">
<a id="logoutBtn" href="{{ path('users_logout') }}">Odhlásit se</a>
<a id="deleteBtn" href="{{ path('users_remove', {'id': app.user.id}) }}">Smazat uživatelský účet</a>
</div>
</div> </div>
</main> </main>
{% endblock %} {% endblock %}

@ -0,0 +1,16 @@
{% extends 'base.html.twig' %}
{% block title %}
Smazat uživatele
{% endblock %}
{% block body %}
{{ parent() }}
<main>
<div id="myCharts">
<h1>Smazání uživatelského účtu</h1>
<p>Opravdu chcete smazat účet: {{ entity.email }} ?</p>
{{ form(form) }}
</div>
</main>
{% endblock %}
Loading…
Cancel
Save

Powered by TurnKey Linux.