diff --git a/config/services.yaml b/config/services.yaml index 1bccbb7..41f446e 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -12,10 +12,9 @@ parameters: app.page.title.length.max: '%env(APP_PAGE_TITLE_LENGTH_MAX)%' app.page.description.length.min: '%env(APP_PAGE_DESCRIPTION_LENGTH_MIN)%' app.page.description.length.max: '%env(APP_PAGE_DESCRIPTION_LENGTH_MAX)%' - app.page.torrent.quantity.min: '%env(APP_PAGE_TORRENT_QUANTITY_MIN)%' - app.page.torrent.quantity.max: '%env(APP_PAGE_TORRENT_QUANTITY_MAX)%' - app.page.torrent.size.min: '%env(APP_PAGE_TORRENT_SIZE_MIN)%' - app.page.torrent.size.max: '%env(APP_PAGE_TORRENT_SIZE_MAX)%' + app.page.torrent.file.quantity.min: '%env(APP_PAGE_TORRENT_FILE_QUANTITY_MIN)%' + app.page.torrent.file.quantity.max: '%env(APP_PAGE_TORRENT_FILE_QUANTITY_MAX)%' + app.torrent.size.max: '%env(APP_TORRENT_FILE_SIZE_MAX)%' services: # default configuration for services in *this* file diff --git a/public/asset/default/css/common.css b/public/asset/default/css/common.css index f7a537f..f285013 100644 --- a/public/asset/default/css/common.css +++ b/public/asset/default/css/common.css @@ -64,8 +64,9 @@ input:focus { color: #fff; } -textarea { - min-height: 160px; +textarea, +select[multiple="multiple"] { + min-height: 260px; } /* @TODO improve focus out diff --git a/src/Controller/TorrentController.php b/src/Controller/TorrentController.php new file mode 100644 index 0000000..7140055 --- /dev/null +++ b/src/Controller/TorrentController.php @@ -0,0 +1,181 @@ + '\d+' + ], + methods: + [ + 'GET' + ] + )] + public function info( + Request $request, + UserService $userService, + TorrentService $torrentService + ): Response + { + // Init user + $user = $userService->init( + $request->getClientIp() + ); + + return $this->render('default/torrent/info.html.twig', [ + 'title' => 'test' + ]); + } + + #[Route( + '/{_locale}/submit/torrent', + name: 'torrent_submit', + methods: + [ + 'GET', + 'POST' + ] + )] + public function submit( + Request $request, + TranslatorInterface $translator, + UserService $userService, + TorrentService $torrentService + ): Response + { + // Init user + $user = $userService->init( + $request->getClientIp() + ); + + if (!$user->isStatus()) + { + // @TODO + throw new \Exception( + $translator->trans('Access denied') + ); + } + + // Init form + $form = + [ + 'locales' => + [ + 'error' => [], + 'attribute' => + [ + 'value' => $request->get('locales') ? $request->get('locales') : [$request->get('_locale')], + 'placeholder' => $translator->trans('Content language') + ] + ], + 'torrent' => + [ + 'error' => [], + 'attribute' => + [ + 'value' => null, // is local file, there is no values passed + 'placeholder' => $translator->trans('Select torrent file') + ] + ], + 'sensitive' => + [ + 'error' => [], + 'attribute' => + [ + 'value' => $request->get('sensitive'), + 'placeholder' => $translator->trans('Apply sensitive filters for this publication'), + ] + ] + ]; + + // Process request + if ($request->isMethod('post')) + { + /// Locales + $locales = []; + if ($request->get('locales')) + { + foreach ((array) $request->get('locales') as $locale) + { + if (in_array($locale, explode('|', $this->getParameter('app.locales')))) + { + $locales[] = $locale; + } + } + } + + //// At least one valid locale required + if (!$locales) + { + $form['locales']['error'][] = $translator->trans('At least one locale required'); + } + + /// Torrent + if ($file = $request->files->get('torrent')) + { + //// Validate torrent file + if (filesize($file->getPathName()) > $this->getParameter('app.torrent.size.max')) + { + $form['torrent']['error'][] = $translator->trans('Torrent file out of size limit'); + } + + if (empty($torrentService->getTorrentFilenameByFilepath($file->getPathName()))) + { + $form['torrent']['error'][] = $translator->trans('Could not parse torrent file'); + } + } + + else + { + $form['torrent']['error'][] = $translator->trans('Torrent file required'); + } + + // Request is valid + if (empty($form['torrent']['error']) && empty($form['locales']['error'])) + { + // Save data + $torrent = $torrentService->submit( + $file->getPathName(), + $user->getId(), + time(), + (array) $locales, + (bool) $request->get('sensitive'), + $user->isApproved() + ); + + // Redirect to info page created + return $this->redirectToRoute( + 'torrent_info', + [ + '_locale' => $request->get('_locale'), + 'id' => $torrent->getId() + ] + ); + } + } + + // Render form template + return $this->render( + 'default/torrent/submit.html.twig', + [ + 'locales' => explode('|', $this->getParameter('app.locales')), + 'form' => $form, + ] + ); + } +} diff --git a/src/Entity/Torrent.php b/src/Entity/Torrent.php new file mode 100644 index 0000000..20aba38 --- /dev/null +++ b/src/Entity/Torrent.php @@ -0,0 +1,103 @@ +id; + } + + public function setId(string $id): static + { + $this->id = $id; + + return $this; + } + + public function getFilename(): ?string + { + return $this->filename; + } + + public function setFilename(string $filename): static + { + $this->filename = $filename; + + return $this; + } + + public function getKeywords(): ?string + { + return $this->keywords; + } + + public function setKeywords(?string $keywords): static + { + $this->keywords = $keywords; + + return $this; + } + + public function getSeeders(): ?int + { + return $this->seeders; + } + + public function setSeeders(?int $seeders): static + { + $this->seeders = $seeders; + + return $this; + } + + public function getPeers(): ?int + { + return $this->peers; + } + + public function setPeers(?int $peers): static + { + $this->peers = $peers; + + return $this; + } + + public function getLeechers(): ?int + { + return $this->leechers; + } + + public function setLeechers(?int $leechers): static + { + $this->leechers = $leechers; + + return $this; + } +} diff --git a/src/Entity/TorrentLocales.php b/src/Entity/TorrentLocales.php new file mode 100644 index 0000000..5e6c10f --- /dev/null +++ b/src/Entity/TorrentLocales.php @@ -0,0 +1,103 @@ +id; + } + + public function setId(string $id): static + { + $this->id = $id; + + return $this; + } + + public function getTorrentId(): ?int + { + return $this->torrentId; + } + + public function setTorrentId(int $torrentId): static + { + $this->torrentId = $torrentId; + + return $this; + } + + public function getUserId(): ?int + { + return $this->userId; + } + + public function setUserId(int $userId): static + { + $this->userId = $userId; + + return $this; + } + + public function getAdded(): ?int + { + return $this->added; + } + + public function setAdded(int $added): static + { + $this->added = $added; + + return $this; + } + + public function getValue(): array + { + return $this->value; + } + + public function setValue(array $value): static + { + $this->value = $value; + + return $this; + } + + public function isApproved(): ?bool + { + return $this->approved; + } + + public function setApproved(bool $approved): static + { + $this->approved = $approved; + + return $this; + } +} diff --git a/src/Entity/TorrentSensitive.php b/src/Entity/TorrentSensitive.php new file mode 100644 index 0000000..9c1560f --- /dev/null +++ b/src/Entity/TorrentSensitive.php @@ -0,0 +1,103 @@ +id; + } + + public function setId(string $id): static + { + $this->id = $id; + + return $this; + } + + public function getTorrentId(): ?int + { + return $this->torrentId; + } + + public function setTorrentId(int $torrentId): static + { + $this->torrentId = $torrentId; + + return $this; + } + + public function getUserId(): ?int + { + return $this->userId; + } + + public function setUserId(int $userId): static + { + $this->userId = $userId; + + return $this; + } + + public function getAdded(): ?int + { + return $this->added; + } + + public function setAdded(int $added): static + { + $this->added = $added; + + return $this; + } + + public function isValue(): ?bool + { + return $this->value; + } + + public function setValue(bool $value): static + { + $this->value = $value; + + return $this; + } + + public function isApproved(): ?bool + { + return $this->approved; + } + + public function setApproved(bool $approved): static + { + $this->approved = $approved; + + return $this; + } +} diff --git a/src/Repository/TorrentLocalesRepository.php b/src/Repository/TorrentLocalesRepository.php new file mode 100644 index 0000000..8ba7b73 --- /dev/null +++ b/src/Repository/TorrentLocalesRepository.php @@ -0,0 +1,23 @@ + + * + * @method TorrentLocales|null find($id, $lockMode = null, $lockVersion = null) + * @method TorrentLocales|null findOneBy(array $criteria, array $orderBy = null) + * @method TorrentLocales[] findAll() + * @method TorrentLocales[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class TorrentLocalesRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, TorrentLocales::class); + } +} diff --git a/src/Repository/TorrentRepository.php b/src/Repository/TorrentRepository.php new file mode 100644 index 0000000..53b6358 --- /dev/null +++ b/src/Repository/TorrentRepository.php @@ -0,0 +1,23 @@ + + * + * @method Torrent|null find($id, $lockMode = null, $lockVersion = null) + * @method Torrent|null findOneBy(array $criteria, array $orderBy = null) + * @method Torrent[] findAll() + * @method Torrent[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class TorrentRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Torrent::class); + } +} diff --git a/src/Repository/TorrentSensitiveRepository.php b/src/Repository/TorrentSensitiveRepository.php new file mode 100644 index 0000000..e21c7e6 --- /dev/null +++ b/src/Repository/TorrentSensitiveRepository.php @@ -0,0 +1,23 @@ + + * + * @method TorrentSensitive|null find($id, $lockMode = null, $lockVersion = null) + * @method TorrentSensitive|null findOneBy(array $criteria, array $orderBy = null) + * @method TorrentSensitive[] findAll() + * @method TorrentSensitive[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class TorrentSensitiveRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, TorrentSensitive::class); + } +} diff --git a/src/Service/TorrentService.php b/src/Service/TorrentService.php new file mode 100644 index 0000000..df14e9f --- /dev/null +++ b/src/Service/TorrentService.php @@ -0,0 +1,163 @@ +entityManager = $entityManager; + } + + public function decodeTorrentByFilepath(string $filepath): array + { + $decoder = new \BitTorrent\Decoder(); + + return $decoder->decodeFile($filepath); + } + + public function getTorrentFilenameByFilepath(string $filepath): string + { + $data = $this->decodeTorrentByFilepath($filepath); + + if (!empty($data['info']['name'])) + { + return $data['info']['name']; + } + + return $data['info']['name']; + } + + public function getTorrentKeywordsByFilepath(string $filepath): string + { + $data = $this->decodeTorrentByFilepath($filepath); + + if (!empty($data['info']['name'])) + { + return mb_strtolower( + preg_replace( + '/[\s]+/', + ' ', + preg_replace( + '/[\W]+/', + ' ', + $data['info']['name'] + ) + ) + ); + } + + return ''; + } + + public function submit( + string $filepath, + int $userId, + int $added, + array $locales, + bool $sensitive, + bool $approved + ): ?Torrent + { + $torrent = $this->saveTorrent( + $this->getTorrentFilenameByFilepath($filepath), + $this->getTorrentKeywordsByFilepath($filepath) + ); + + if (!empty($locales)) + { + $this->saveTorrentLocales( + $torrent->getId(), + $userId, + $added, + $locales, + $approved + ); + } + + $this->saveTorrentSensitive( + $torrent->getId(), + $userId, + $added, + $sensitive, + $approved + ); + + return $torrent; + } + + public function saveTorrent( + string $filepath, + string $keywords + ): ?Torrent + { + $torrent = new Torrent(); + + $torrent->setFilename($filepath); + $torrent->setKeywords($keywords); + + $this->entityManager->persist($torrent); + $this->entityManager->flush(); + + return $torrent; + } + + public function saveTorrentLocales( + int $torrentId, + int $userId, + int $added, + array $value, + bool $approved + ): ?TorrentLocales + { + $torrentLocales = new TorrentLocales(); + + $torrentLocales->setTorrentId($torrentId); + $torrentLocales->setUserId($userId); + $torrentLocales->setAdded($added); + $torrentLocales->setValue($value); + $torrentLocales->setApproved($approved); + + $this->entityManager->persist($torrentLocales); + $this->entityManager->flush(); + + return $torrentLocales; + } + + public function saveTorrentSensitive( + int $torrentId, + int $userId, + int $added, + bool $value, + bool $approved + ): ?TorrentSensitive + { + $torrentSensitive = new TorrentSensitive(); + + $torrentSensitive->setTorrentId($torrentId); + $torrentSensitive->setUserId($userId); + $torrentSensitive->setAdded($added); + $torrentSensitive->setValue($value); + $torrentSensitive->setApproved($approved); + + $this->entityManager->persist($torrentSensitive); + $this->entityManager->flush(); + + return $torrentSensitive; + } +} \ No newline at end of file diff --git a/templates/default/torrent/info.html.twig b/templates/default/torrent/info.html.twig new file mode 100644 index 0000000..3389f18 --- /dev/null +++ b/templates/default/torrent/info.html.twig @@ -0,0 +1,2 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{ title }} - {{ name }}{% endblock %} \ No newline at end of file diff --git a/templates/default/torrent/submit.html.twig b/templates/default/torrent/submit.html.twig new file mode 100644 index 0000000..1b9444e --- /dev/null +++ b/templates/default/torrent/submit.html.twig @@ -0,0 +1,80 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{'Submit torrent'|trans }} - {{ name }}{% endblock %} +{% block main_content %} +