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
59 changes: 59 additions & 0 deletions app/Components/Forms/BaseForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace App\Components\Forms;

use Nette\Application\UI\Form;

class BaseForm extends Form
{
/**
* File upload form
*/

protected function createComponentFileUploadForm(): Form
{
$form = new Form();
$form->addMultiUpload('file', 'Nahrát soubor:');
$form->addSubmit('submit', 'Nahrát');
/*$form->onSuccess[] = [$this, 'formSucceded'];*/
$form->onRender[] = fn(Form $form) => $this->styleForm($form);
return $form;
}

/**
* Style form using bootstrap
* Code from: https://github.com/nette/forms/blob/master/examples/bootstrap5-rendering.php
*/
final protected function styleForm(Form $form): void
{
/** @var DefaultFormRenderer $renderer */
$renderer = $form->getRenderer();

Check failure on line 32 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

PHPDoc tag `@var` with type App\Components\Forms\DefaultFormRenderer is not subtype of native type Nette\Forms\FormRenderer.

Check failure on line 32 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

PHPDoc tag `@var` for variable $renderer contains unknown class App\Components\Forms\DefaultFormRenderer.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tento oficialny návod od nette je fakt zlý.

Prekopírval som do nette-fks-utils FormControl z FKSDB. Teda by som to nahradil tým.

https://github.com/fykosak/nette-fks-utils/tree/dev-form-control

$renderer->wrappers['controls']['container'] = null;

Check failure on line 33 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.

Check failure on line 33 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.
$renderer->wrappers['pair']['container'] = 'div class="mb-3 row"';

Check failure on line 34 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.

Check failure on line 34 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.
$renderer->wrappers['label']['container'] = 'div class="col-sm-3 col-form-label"';

Check failure on line 35 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.

Check failure on line 35 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.
$renderer->wrappers['control']['container'] = 'div class=col-sm-9';

Check failure on line 36 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.

Check failure on line 36 in app/Components/Forms/BaseForm.php

View workflow job for this annotation

GitHub Actions / PHPStan 8.1

Access to property $wrappers on an unknown class App\Components\Forms\DefaultFormRenderer.
$renderer->wrappers['control']['description'] = 'span class=form-text';
$renderer->wrappers['control']['errorcontainer'] = 'span class=invalid-feedback';
$renderer->wrappers['control']['.error'] = 'is-invalid';
$renderer->wrappers['error']['container'] = 'div class="alert alert-danger"';

foreach ($form->getControls() as $control) {
$type = $control->getOption('type');
if ($type === 'button') {
$control->getControlPrototype()->addClass(
empty($usedPrimary) ? 'btn btn-primary' : 'btn btn-secondary'
);
$usedPrimary = true;
} elseif (in_array($type, ['text', 'textarea', 'select', 'datetime', 'file'], true)) {
$control->getControlPrototype()->addClass('form-control');
} elseif (in_array($type, ['checkbox', 'radio'], true)) {
$control->getControlPrototype()->addClass('form-check-input');
$control->getContainerPrototype()->setName('div')->addClass('form-check');
} elseif ($type === 'color') {
$control->getControlPrototype()->addClass('form-control form-control-color');
}
}
}
}
33 changes: 33 additions & 0 deletions app/Models/Authentication/Authenticator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace App\Models\Authentication;

use Jumbojett\OpenIDConnectClient;

class Authenticator {
public function __construct(
readonly private string $providerUrl,
readonly private string $clientId,
readonly private string $clientSecret,
readonly public string $requiredGroup
) {}

public function authenticateOIDC(): UserModel
{
$oidc = new OpenIDConnectClient($this->providerUrl,
$this->clientId,
$this->clientSecret);

$oidc->setRedirectURL('http://localhost:8080/admin'); // TODO smazat před použitím

$oidc->authenticate();

$personId = (int) $oidc->requestUserInfo('person_id');
$name = $oidc->requestUserInfo('name');
$groups = $oidc->requestUserInfo('groups');

return new UserModel($personId, $name, $groups);
}
}
26 changes: 26 additions & 0 deletions app/Models/Authentication/UserModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace App\Models\Authentication;

use Nette\Security\IIdentity;

class UserModel implements IIdentity
{
public function __construct(
readonly public int $id,
readonly public string $name,
readonly public array $groups
) {}

public function getId(): int
{
return $this->id;
}

public function getRoles(): array
{
return [];
}
}
43 changes: 43 additions & 0 deletions app/Modules/Vyfuk/Core/styles/admin.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* Admin layout styles */
body {
background-color: $panel-color-light;
}

/* Files */
.file-editor-container {
max-width: 50rem;
width: fit-content;
}

.file-editor{
width: 100%;
padding: 0.35rem;
}

/* Files and media event selector */
.event-selector {
.dropdown-toggle {
min-width: 16rem;
max-width: 100%;
text-align: left;
white-space: wrap;
}

.dropdown-menu {
min-width: 16rem;
max-width: 100%;
max-height: 14rem;
overflow: auto;
text-align: left;
}
}

.file-upload-container {
max-width: 50rem;
width: fit-content;
}

.file-upload {
width: 100%;
padding: 0.35rem;
}
1 change: 1 addition & 0 deletions app/Modules/Vyfuk/Core/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ $flag-icons-path: '/node_modules/flag-icons/flags';
@import "./events";
@import "./problems";
@import "./sponsors";
@import "./admin";

@import '../../../../Components/Problem/problem';
@import '../../../../Components/Problem/vyfuk';
Expand Down
18 changes: 17 additions & 1 deletion app/Modules/Vyfuk/Core/styles/other.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
color: $text-on-primary;
}

.btn-outline-warning:hover, .btn-outline-warning:focus-visible, .btn-outline-warning:active, .btn-outline-warning.active, .open>.dropdown-toggle.btn-outline-warning {
color: white !important;
}

.btn-danger {
color: white;
}

.btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, .open>.dropdown-toggle.btn-danger {
color: white !important;
}

.btn-outline-danger:hover, .btn-outline-danger:focus-visible, .btn-outline-danger:active, .btn-outline-danger.active, .open>.dropdown-toggle.btn-outline-danger {
color: white !important;
}

// Custom links
a {
text-decoration: none;
Expand All @@ -17,7 +33,7 @@ a:hover {
color: $text-on-primary !important;
}

.btn-outline-primary:hover, .btn-outline-primary:focus, .btn-outline-primary:active, .btn-outline-primary.active, .open>.dropdown-toggle.btn-outline-primary {
.btn-outline-primary:hover, .btn-outline-primary:focus, .btn-outline-primary:focus-visible, .btn-outline-primary:active, .btn-outline-primary.active, .open>.dropdown-toggle.btn-outline-primary {
color: $text-on-primary !important;
}

Expand Down
6 changes: 3 additions & 3 deletions app/Modules/Vyfuk/Core/templates/@layout.latte
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
<link
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css"
integrity="sha384-tGBVFh2h9Zcme3k9gJLbGqDpD+jRd419j/6N32rharcTZa1X6xgxug6pFMGonjxU"
crossorigin="anonymous">
{block head}{/block}

<!-- Google tag (gtag.js) -->
Expand Down
163 changes: 163 additions & 0 deletions app/Modules/Vyfuk/DefaultModule/AdminPresenter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<?php

declare(strict_types=1);

namespace App\Modules\Vyfuk\DefaultModule;

use Fykosak\Utils\UI\Navigation\NavItem;
use Fykosak\Utils\UI\PageTitle;
use App\Models\Authentication\Authenticator;
use App\Models\Authentication\UserModel;
use Nette\Application\ForbiddenRequestException;
use App\Models\Downloader\EventService;

use Nette\Utils\Finder;

class AdminPresenter extends BasePresenter
{
protected Authenticator $authenticator;
protected EventService $eventService;

/** @persistent */
public ?int $eventId = null;

public function injectService(Authenticator $authenticator, EventService $eventService): void
{
$this->authenticator = $authenticator;
$this->eventService = $eventService;
}

public function getMediaDir(): string
{
$mediaDir = $this->getContext()->getParameters()['mediaDir'];
return $mediaDir;
}

public function checkRequirements($element): void
{
parent::checkRequirements($element);

if (!$this->getUser()->isLoggedIn()) {
$user = $this->authenticator->authenticateOIDC();
$this->getUser()->login($user);
}

if (!in_array($this->authenticator->requiredGroup, $this->getLoggedUser()->groups)) {
throw new ForbiddenRequestException();
}
}

public function getLoggedUser(): ?UserModel
{
return $this->getUser()->getIdentity();
}

public function actionLogout(): void
{
$this->getUser()->logout();
$this->redirect(':Default:Admin:page');
}

public function renderMedia(): void
{
$this->template->events = array_reverse($this->eventService->getEvents([10, 11, 12, 18]));

$event = $this->eventId ? $this->eventService->getEvent($this->eventId) : $this->eventService->getNewest([10, 11, 12, 18]);
$this->template->selectedEvent = $event;

$this->template->media = $this->getMedia($event->eventId);
}

public function getMedia($eventId): array
{
$mediaDir = $this->getMediaDir();
$media = [];

try {
$iterator = Finder::findFiles('*.jpg', '*.jpeg', '*.png', '*.JPG', '*.gif', '*.bmp', '*.webp')->in($mediaDir . '/photos/event/' . $eventId)->getIterator();
} catch (\Exception $e) {
return [];
}

foreach ($iterator as $file) {
$name = pathinfo($file->getPathname())['filename'];
$media[] = $name;
};

return $media;
}

public function renderFiles(): void
{
$this->template->events = array_reverse($this->eventService->getEvents([10, 11, 12, 18]));

$event = $this->eventId ? $this->eventService->getEvent($this->eventId) : $this->eventService->getNewest([10, 11, 12, 18]);
$this->template->selectedEvent = $event;

$this->template->files = $this->getFiles($event->eventId);
}

public function getFiles($eventId): array
{
$mediaDir = $this->getMediaDir();
$files = [];

try {
$iterator = Finder::findFiles('*.pdf')->in($mediaDir . '/download/event/' . $eventId)->getIterator();
} catch (\Exception $e) {
return [];
}

foreach ($iterator as $file) {
$name = $file->getBasename('.pdf');
$path = '/media' . substr($file->getPathname(), strlen($mediaDir));
$files[] = [
'path' => $path,
'name' => $name,
];
};

return $files;
}

public function render(): void
{
// Nothing to do here yet
}

/**
* @return NavItem[]
*/
protected function getNavItems(): array
{
$items = [];

$items[] = new NavItem(
new PageTitle('Správa novinek', 'fa-solid fa-newspaper'),
':Default:Admin:news'
);

$items[] = new NavItem(
new PageTitle('Správa souborů', 'fa-solid fa-file-pen'),
':Default:Admin:files'
);

$items[] = new NavItem(
new PageTitle('Správa fotek', 'fa-solid fa-images'),
':Default:Admin:media'
);

$items[] = new NavItem(
new PageTitle(sprintf('%s (#%d)', $this->getLoggedUser()->name, $this->getLoggedUser()->id), 'fa-solid fa-user-gear'),
':Default:Admin:default'
);

$items[] = new NavItem(
new PageTitle('Odhlásit se', 'fa-solid fa-arrow-right-from-bracket'),
':Default:Admin:logout'
);

return $items;
}

}
Loading
Loading