Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
framework:
secret: '%env(APP_SECRET)%'
handle_all_throwables: true
#csrf_protection: true
csrf_protection: true
http_method_override: false

# Enables session support. Note that the session will ONLY be started if you read or write from it.
Expand Down
1 change: 1 addition & 0 deletions config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ security:
logout:
path: app_logout
target: dashboard
enable_csrf: true


access_control:
Expand Down
46 changes: 8 additions & 38 deletions public/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,10 @@ if (shareModal) {
// Button that triggered the modal
const button = event.relatedTarget

// Grab calendar shares url and add url
// Grab calendar shares URL and share target.
let shareesUrl = button.getAttribute('data-sharees-href');
let targetUrl = button.getAttribute('data-href');

// When adding the sharee, catch the click to add the query parameter
const addShareeButton = document.getElementById('shareModal-addSharee');
addShareeButton.addEventListener("click", function(e) {
const writeAccess = document.getElementById('shareModal-writeAccess').checked ? 'true' : 'false';
const principalId = document.getElementById('shareModal-member').value;

e.preventDefault()
window.location = targetUrl + "?principalId=" + principalId + "&write=" + writeAccess
});
document.getElementById('shareModal-addForm').setAttribute('action', targetUrl)

const noneElement = document.getElementById('shareModal-none')

Expand Down Expand Up @@ -53,8 +44,8 @@ if (shareModal) {
badge[0].classList.add('bg-success')
badge[0].classList.remove('bg-info')
}
let revokeButton = clone.querySelectorAll("a.revoke");
revokeButton[0].href = element.revokeUrl;
let revokeForm = clone.querySelectorAll("form.revoke");
revokeForm[0].setAttribute('action', element.revokeUrl);

shares.appendChild(clone);
});
Expand All @@ -71,37 +62,16 @@ deleteModals.forEach(element => {
// Button that triggered the modal
const button = event.relatedTarget

// Grab real target url for deletion
// Grab the target URL for deletion.
let targetUrl = button.getAttribute('data-href');
let modalFlavour = button.getAttribute('data-flavour');

// Put it into the modal's OK button
const deleteCTA = document.getElementById(`deleteModal-${modalFlavour}-cta`);
console.log("setting href to " + targetUrl)
deleteCTA.setAttribute('href', targetUrl);
// Put it into the modal's confirmation form.
const deleteForm = document.getElementById(`deleteModal-${modalFlavour}-form`);
deleteForm.setAttribute('action', targetUrl);
})
})



// Global account delegation modal
const addDelegateModal = document.getElementById('addDelegateModal')
if (addDelegateModal) {
addDelegateModal.addEventListener('show.bs.modal', event => {
// When adding the sharee, catch the click to add the query parameter
const addDelegateButton = document.getElementById('addDelegateModal-cta');
addDelegateButton.addEventListener("click", function(e) {
const targetUrl = addDelegateButton.getAttribute('data-href');
const writeAccess = document.getElementById('addDelegateModal-writeAccess').checked ? 'true' : 'false';
const principalId = document.getElementById('addDelegateModal-member').value;

e.preventDefault()
window.location = targetUrl + "?principalId=" + principalId + "&write=" + writeAccess
});

})
}

// Color swatch: update it live (not working in IE ¯\_(ツ)_/¯ but it's just a nice to have)
const colorPicker = document.getElementById('calendar_instance_calendarColor');
if (colorPicker) {
Expand Down
10 changes: 6 additions & 4 deletions src/Controller/Admin/AddressBookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/addressbooks', name: 'addressbook_')]
class AddressBookController extends AbstractController
{
#[Route('/{userId}', name: 'index')]
#[Route('/{userId}', name: 'index', methods: ['GET'])]
public function addressBooks(ManagerRegistry $doctrine, int $userId): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand All @@ -38,8 +39,8 @@ public function addressBooks(ManagerRegistry $doctrine, int $userId): Response
]);
}

#[Route('/{userId}/new', name: 'create')]
#[Route('/{userId}/edit/{id}', name: 'edit', requirements: ['id' => "\d+"])]
#[Route('/{userId}/new', name: 'create', methods: ['GET', 'POST'])]
#[Route('/{userId}/edit/{id}', name: 'edit', methods: ['GET', 'POST'], requirements: ['id' => "\d+"])]
public function addressbookCreate(ManagerRegistry $doctrine, Request $request, int $userId, ?int $id, TranslatorInterface $trans, BirthdayService $birthdayService): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -106,7 +107,8 @@ public function addressbookCreate(ManagerRegistry $doctrine, Request $request, i
]);
}

#[Route('/{userId}/delete/{id}', name: 'delete', requirements: ['id' => "\d+"])]
#[Route('/{userId}/delete/{id}', name: 'delete', methods: ['POST'], requirements: ['id' => "\d+"])]
#[IsCsrfTokenValid('delete-addressbooks')]
public function addressbookDelete(ManagerRegistry $doctrine, int $userId, string $id, TranslatorInterface $trans, BirthdayService $birthdayService): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down
24 changes: 14 additions & 10 deletions src/Controller/Admin/CalendarController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/calendars', name: 'calendar_')]
class CalendarController extends AbstractController
{
#[Route('/{userId}', name: 'index')]
#[Route('/{userId}', name: 'index', methods: ['GET'])]
public function calendars(ManagerRegistry $doctrine, UrlGeneratorInterface $router, int $userId): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -75,8 +76,8 @@ public function calendars(ManagerRegistry $doctrine, UrlGeneratorInterface $rout
]);
}

#[Route('/{userId}/new', name: 'create')]
#[Route('/{userId}/edit/{id}', name: 'edit', requirements: ['id' => "\d+"])]
#[Route('/{userId}/new', name: 'create', methods: ['GET', 'POST'])]
#[Route('/{userId}/edit/{id}', name: 'edit', methods: ['GET', 'POST'], requirements: ['id' => "\d+"])]
public function calendarEdit(ManagerRegistry $doctrine, Request $request, int $userId, ?int $id, TranslatorInterface $trans): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -170,7 +171,7 @@ public function calendarEdit(ManagerRegistry $doctrine, Request $request, int $u
]);
}

#[Route('/{userId}/shares/{calendarid}', name: 'shares', requirements: ['calendarid' => "\d+"])]
#[Route('/{userId}/shares/{calendarid}', name: 'shares', methods: ['GET'], requirements: ['calendarid' => "\d+"])]
public function calendarShares(ManagerRegistry $doctrine, int $userId, string $calendarid, TranslatorInterface $trans): Response
{
$instances = $doctrine->getRepository(CalendarInstance::class)->findSharedInstancesOfInstance($calendarid, true);
Expand All @@ -190,19 +191,20 @@ public function calendarShares(ManagerRegistry $doctrine, int $userId, string $c
return new JsonResponse($response);
}

#[Route('/{userId}/share/{instanceid}', name: 'share_add', requirements: ['instanceid' => "\d+"])]
#[Route('/{userId}/share/{instanceid}', name: 'share_add', methods: ['POST'], requirements: ['instanceid' => "\d+"])]
#[IsCsrfTokenValid('calendar-share')]
public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, int $userId, string $instanceid, TranslatorInterface $trans): Response
{
$instance = $doctrine->getRepository(CalendarInstance::class)->findOneById($instanceid);
if (!$instance) {
throw $this->createNotFoundException('Calendar not found');
}

if (!is_numeric($request->get('principalId'))) {
if (!is_numeric($request->request->get('principalId'))) {
throw new BadRequestHttpException();
}

$newShareeToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->get('principalId'));
$newShareeToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->request->get('principalId'));
if (!$newShareeToAdd) {
throw $this->createNotFoundException('Member not found');
}
Expand All @@ -211,7 +213,7 @@ public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, in
// already existing first, so we can update it:
$existingSharedInstance = $doctrine->getRepository(CalendarInstance::class)->findSharedInstanceOfInstanceFor($instance->getCalendar()->getId(), $newShareeToAdd->getUri());

$writeAccess = ('true' === $request->get('write') ? SharingPlugin::ACCESS_READWRITE : SharingPlugin::ACCESS_READ);
$writeAccess = ('true' === $request->request->get('write') ? SharingPlugin::ACCESS_READWRITE : SharingPlugin::ACCESS_READ);

$entityManager = $doctrine->getManager();

Expand All @@ -237,7 +239,8 @@ public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, in
return $this->redirectToRoute('calendar_index', ['userId' => $userId]);
}

#[Route('/{userId}/delete/{id}', name: 'delete', requirements: ['id' => "\d+"])]
#[Route('/{userId}/delete/{id}', name: 'delete', methods: ['POST'], requirements: ['id' => "\d+"])]
#[IsCsrfTokenValid('delete-calendars')]
public function calendarDelete(ManagerRegistry $doctrine, int $userId, string $id, TranslatorInterface $trans): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -283,7 +286,8 @@ public function calendarDelete(ManagerRegistry $doctrine, int $userId, string $i
return $this->redirectToRoute('calendar_index', ['userId' => $userId]);
}

#[Route('/{userId}/revoke/{id}', name: 'revoke', requirements: ['id' => "\d+"])]
#[Route('/{userId}/revoke/{id}', name: 'revoke', methods: ['POST'], requirements: ['id' => "\d+"])]
#[IsCsrfTokenValid('delete-revoke')]
public function calendarRevoke(ManagerRegistry $doctrine, int $userId, string $id, TranslatorInterface $trans): Response
{
$instance = $doctrine->getRepository(CalendarInstance::class)->findOneById($id);
Expand Down
2 changes: 1 addition & 1 deletion src/Controller/Admin/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class DashboardController extends AbstractController
{
#[Route('/dashboard', name: 'dashboard')]
#[Route('/dashboard', name: 'dashboard', methods: ['GET'])]
public function dashboard(ManagerRegistry $doctrine): Response
{
$usersCount = $doctrine->getRepository(User::class)->count([]);
Expand Down
29 changes: 17 additions & 12 deletions src/Controller/Admin/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/users', name: 'user_')]
class UserController extends AbstractController
{
#[Route('/', name: 'index')]
#[Route('/', name: 'index', methods: ['GET'])]
public function users(ManagerRegistry $doctrine): Response
{
$results = $doctrine->getRepository(Principal::class)->findAllMainPrincipalsWithUserIds();
Expand All @@ -32,8 +33,8 @@ public function users(ManagerRegistry $doctrine): Response
]);
}

#[Route('/new', name: 'create')]
#[Route('/edit/{userId}', name: 'edit')]
#[Route('/new', name: 'create', methods: ['GET', 'POST'])]
#[Route('/edit/{userId}', name: 'edit', methods: ['GET', 'POST'])]
public function userCreate(ManagerRegistry $doctrine, Utils $utils, Request $request, ?int $userId, TranslatorInterface $trans): Response
{
if ($userId) {
Expand Down Expand Up @@ -124,7 +125,8 @@ public function userCreate(ManagerRegistry $doctrine, Utils $utils, Request $req
]);
}

#[Route('/delete/{userId}', name: 'delete')]
#[Route('/delete/{userId}', name: 'delete', methods: ['POST'])]
#[IsCsrfTokenValid('delete-users')]
public function userDelete(ManagerRegistry $doctrine, int $userId, TranslatorInterface $trans): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -198,7 +200,7 @@ public function userDelete(ManagerRegistry $doctrine, int $userId, TranslatorInt
return $this->redirectToRoute('user_index');
}

#[Route('/delegates/{userId}', name: 'delegates')]
#[Route('/delegates/{userId}', name: 'delegates', methods: ['GET'])]
public function userDelegates(ManagerRegistry $doctrine, int $userId): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -226,7 +228,8 @@ public function userDelegates(ManagerRegistry $doctrine, int $userId): Response
]);
}

#[Route('/delegation/{userId}/{toggle}', name: 'delegation_toggle', requirements: ['toggle' => '(on|off)'])]
#[Route('/delegation/{userId}/{toggle}', name: 'delegation_toggle', methods: ['POST'], requirements: ['toggle' => '(on|off)'])]
#[IsCsrfTokenValid('delegation-toggle')]
public function userToggleDelegation(ManagerRegistry $doctrine, int $userId, string $toggle): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
Expand Down Expand Up @@ -270,10 +273,11 @@ public function userToggleDelegation(ManagerRegistry $doctrine, int $userId, str
return $this->redirectToRoute('user_delegates', ['userId' => $userId]);
}

#[Route('/delegates/{userId}/add', name: 'delegate_add')]
#[Route('/delegates/{userId}/add', name: 'delegate_add', methods: ['POST'])]
#[IsCsrfTokenValid('delegate-add')]
public function userDelegateAdd(ManagerRegistry $doctrine, Request $request, int $userId): Response
{
if (!is_numeric($request->get('principalId'))) {
if (!is_numeric($request->request->get('principalId'))) {
throw new BadRequestHttpException();
}

Expand All @@ -284,14 +288,14 @@ public function userDelegateAdd(ManagerRegistry $doctrine, Request $request, int

$principalUri = Principal::PREFIX.$user->getUsername();

$newMemberToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->get('principalId'));
$newMemberToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->request->get('principalId'));

if (!$newMemberToAdd) {
throw $this->createNotFoundException('Member not found');
}

// Depending on write access or not, attach to the correct principal
if ('true' === $request->get('write')) {
if ('true' === $request->request->get('write')) {
// Let's check that there wasn't a read proxy first
$principalProxyRead = $doctrine->getRepository(Principal::class)->findOneByUri($principalUri.Principal::READ_PROXY_SUFFIX);
if (!$principalProxyRead) {
Expand All @@ -315,8 +319,9 @@ public function userDelegateAdd(ManagerRegistry $doctrine, Request $request, int
return $this->redirectToRoute('user_delegates', ['userId' => $userId]);
}

#[Route('/delegates/{userId}/remove/{principalProxyId}/{delegateId}', name: 'delegate_remove', requirements: ['principalProxyId' => "\d+", 'delegateId' => "\d+"])]
public function userDelegateRemove(ManagerRegistry $doctrine, Request $request, int $userId, int $principalProxyId, int $delegateId): Response
#[Route('/delegates/{userId}/remove/{principalProxyId}/{delegateId}', name: 'delegate_remove', methods: ['POST'], requirements: ['principalProxyId' => "\d+", 'delegateId' => "\d+"])]
#[IsCsrfTokenValid('delete-delegates')]
public function userDelegateRemove(ManagerRegistry $doctrine, int $userId, int $principalProxyId, int $delegateId): Response
{
$user = $doctrine->getRepository(User::class)->findOneById($userId);
if (!$user) {
Expand Down
4 changes: 2 additions & 2 deletions src/Controller/SecurityController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class SecurityController extends AbstractController
{
#[Route('/login', name: 'app_login')]
#[Route('/login', name: 'app_login', methods: ['GET', 'POST'])]
public function login(AuthenticationUtils $authenticationUtils): Response
{
// if ($this->getUser()) {
Expand All @@ -24,7 +24,7 @@ public function login(AuthenticationUtils $authenticationUtils): Response
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}

#[Route('/logout', name: 'app_logout')]
#[Route('/logout', name: 'app_logout', methods: ['POST'])]
public function logout()
{
throw new \Exception('This method can be blank - it will be intercepted by the logout key on your firewall');
Expand Down
15 changes: 8 additions & 7 deletions templates/_partials/add_delegate_modal.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,29 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ "close"|trans }}"></button>
</div>
<div class="modal-body">
<form>
<form method="post" action="{{ path('user_delegate_add', {userId: userId}) }}" id="addDelegateModal-form">
<input type="hidden" name="_token" value="{{ csrf_token('delegate-add') }}">
<div class="form-group">
<label for="member" class="col-form-label">{{ "calendars.delegates.member"|trans }}</label>
<select class="form-control" id="addDelegateModal-member">
<label for="addDelegateModal-member" class="col-form-label">{{ "calendars.delegates.member"|trans }}</label>
<select class="form-control" id="addDelegateModal-member" name="principalId">
{% for principal in principals %}
<option value="{{ principal.id}}">{{ principal.displayName }} ({{ principal.email }})</option>
{% endfor %}
</select>
<small class="form-text text-muted">{{ "delegates.member.help"|trans }}</small>
</div>
<div class="form-check form-switch mt-2">
<input class="form-check-input" type="checkbox" value="" id="addDelegateModal-writeAccess">
<label class="form-check-label" for="write">
<input class="form-check-input" type="checkbox" name="write" value="true" id="addDelegateModal-writeAccess">
<label class="form-check-label" for="addDelegateModal-writeAccess">
{{ "calendars.delegates.write.give"|trans }}
</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ "cancel"|trans }}</button>
<a data-href="{{ path('user_delegate_add', {userId: userId}) }}" href="#" class="btn btn-primary" id="addDelegateModal-cta">{{ "add"|trans }}</a>
<button type="submit" form="addDelegateModal-form" class="btn btn-primary">{{ "add"|trans }}</button>
</div>
</div>
</div>
</div>
</div>
Loading