diff --git a/.env b/.env index 105d50b..7864012 100644 --- a/.env +++ b/.env @@ -77,6 +77,9 @@ APP_APPROVED=0 # Default Yggdrasil filters status for new users APP_YGGDRASIL=1 +# Default posters status for new users +APP_POSTERS=1 + # Build-in trackers append to downloads APP_TRACKERS=http://[201:23b4:991a:634d:8359:4521:5576:15b7]:2023/announce|http://[200:1e2f:e608:eb3a:2bf:1e62:87ba:e2f7]/announce|http://[316:c51a:62a3:8b9::5]/announce @@ -86,6 +89,9 @@ APP_CRAWLERS=201:23b4:991a:634d:8359:4521:5576:15b7|30a:5fad::e # Max torrent filesize for uploads APP_TORRENT_FILE_SIZE_MAX=1024000 +# Max torrent poster filesize for uploads +APP_TORRENT_POSTER_FILE_SIZE_MAX=10240000 + # Store wanted torrent files in /app/var/ftp by /app/crontab/torrent/scrape/{key} APP_TORRENT_WANTED_FTP_ENABLED=1 APP_TORRENT_WANTED_FTP_FOLDER=/yggtracker diff --git a/config/services.yaml b/config/services.yaml index bb2762b..110b2a6 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -17,7 +17,9 @@ parameters: app.sensitive: '%env(APP_SENSITIVE)%' app.approved: '%env(APP_APPROVED)%' app.yggdrasil: '%env(APP_YGGDRASIL)%' + app.posters: '%env(APP_POSTERS)%' app.torrent.size.max: '%env(APP_TORRENT_FILE_SIZE_MAX)%' + app.torrent.poster.size.max: '%env(APP_TORRENT_POSTER_FILE_SIZE_MAX)%' app.torrent.wanted.ftp.enabled: '%env(APP_TORRENT_WANTED_FTP_ENABLED)%' app.torrent.wanted.ftp.folder: '%env(APP_TORRENT_WANTED_FTP_FOLDER)%' app.torrent.wanted.ftp.approved: '%env(APP_TORRENT_WANTED_FTP_APPROVED_ONLY)%' diff --git a/migrations/Version20231029184600.php b/migrations/Version20231029184600.php new file mode 100644 index 0000000..634e2a1 --- /dev/null +++ b/migrations/Version20231029184600.php @@ -0,0 +1,35 @@ +addSql('CREATE TABLE torrent_poster (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, torrent_id INTEGER NOT NULL, user_id INTEGER NOT NULL, added INTEGER NOT NULL, approved BOOLEAN NOT NULL, md5file VARCHAR(32) NOT NULL)'); + $this->addSql('ALTER TABLE user ADD COLUMN posters BOOLEAN NOT NULL DEFAULT 1'); + $this->addSql('ALTER TABLE torrent ADD COLUMN torrent_poster_id BOOLEAN NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE torrent_poster'); + $this->addSql('ALTER TABLE user DROP COLUMN posters'); + $this->addSql('ALTER TABLE torrent DROP COLUMN torrent_poster_id'); + } +} diff --git a/public/asset/default/css/framework.css b/public/asset/default/css/framework.css index 7fb4b66..1c31c9c 100644 --- a/public/asset/default/css/framework.css +++ b/public/asset/default/css/framework.css @@ -197,29 +197,36 @@ a.button-green:hover { } .border-color-default { - border: 1px #5d627d solid; + border: 1px rgba(93, 98, 125, .6) solid; } .border-bottom-default { - border-bottom: 1px #5d627d solid; + border-bottom: 1px rgba(93, 98, 125, .6) solid; } .border-top-default { - border-top: 1px #5d627d solid; + border-top: 1px rgba(93, 98, 125, .6) solid; } .border-bottom-dashed { - border-bottom: 1px #5d627d dashed; + border-bottom: 1px rgba(93, 98, 125, .6) dashed; } .border-top-dashed { - border-top: 1px #5d627d dashed; + border-top: 1px rgba(93, 98, 125, .6) dashed; } .border-width-2-px { border-width: 2px; } +.background-poster { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + background-blend-mode: soft-light; +} + .background-color-night { background-color: #34384f; } @@ -503,6 +510,10 @@ a:visited.background-color-hover-night-light:hover { /* responsive rules */ +.height-148-px { + height: 148px; +} + .width-100 { width: 100%; } diff --git a/src/Controller/ActivityController.php b/src/Controller/ActivityController.php index c4e147d..06bdec1 100644 --- a/src/Controller/ActivityController.php +++ b/src/Controller/ActivityController.php @@ -1463,6 +1463,7 @@ class ActivityController extends AbstractController $this->getParameter('app.theme'), $this->getParameter('app.sensitive'), $this->getParameter('app.yggdrasil'), + $this->getParameter('app.posters'), $this->getParameter('app.approved') ); diff --git a/src/Controller/TorrentController.php b/src/Controller/TorrentController.php index 0191315..f5c02d9 100644 --- a/src/Controller/TorrentController.php +++ b/src/Controller/TorrentController.php @@ -106,6 +106,22 @@ class TorrentController extends AbstractController // Init page $page = $request->get('page') ? (int) $request->get('page') : 1; + // Poster + if ($user->isPosters() && $torrent->getTorrentPosterId()) + { + $poster = $request->getScheme() . '://' . + $request->getHttpHost() . + $request->getBasePath() . + $torrentService->getImageUriByTorrentPosterId( + $torrent->getTorrentPosterId() + ); + } + + else + { + $poster = false; + } + // Render template return $this->render('default/torrent/info.html.twig', [ @@ -155,7 +171,7 @@ class TorrentController extends AbstractController ) ] ], - 'star' => + 'star' => [ 'exist' => (bool) $torrentService->findTorrentStar( $torrent->getId(), @@ -165,7 +181,8 @@ class TorrentController extends AbstractController $torrent->getId() ) ], - 'contributors' => $contributors + 'contributors' => $contributors, + 'poster' => $poster ], 'file' => [ @@ -284,6 +301,22 @@ class TorrentController extends AbstractController arsort($keywords); + // Poster + if ($user->isPosters() && $torrent->getTorrentPosterId()) + { + $poster = $request->getScheme() . '://' . + $request->getHttpHost() . + $request->getBasePath() . + $torrentService->getImageUriByTorrentPosterId( + $torrent->getTorrentPosterId() + ); + } + + else + { + $poster = false; + } + // Push torrent $torrents[] = [ @@ -351,6 +384,7 @@ class TorrentController extends AbstractController $torrent->getId() ) ], + 'poster' => $poster ]; } @@ -447,6 +481,22 @@ class TorrentController extends AbstractController arsort($keywords); + // Poster + if ($user->isPosters() && $torrent->getTorrentPosterId()) + { + $poster = $request->getScheme() . '://' . + $request->getHttpHost() . + $request->getBasePath() . + $torrentService->getImageUriByTorrentPosterId( + $torrent->getTorrentPosterId() + ); + } + + else + { + $poster = false; + } + // Push torrent $torrents[] = [ @@ -471,15 +521,6 @@ class TorrentController extends AbstractController 'peers' => (int) $torrent->getPeers(), 'leechers' => (int) $torrent->getLeechers(), ], - 'user' => - [ - 'id' => $torrent->getUserId(), - 'identicon' => $userService->identicon( - $userService->getUser( - $torrent->getUserId() - )->getAddress() - ) - ], 'keywords' => $keywords, 'download' => [ @@ -514,6 +555,7 @@ class TorrentController extends AbstractController $torrent->getId() ) ], + 'poster' => $poster ]; } @@ -1773,6 +1815,379 @@ class TorrentController extends AbstractController ); } + // Torrent poster + #[Route( + '/{_locale}/torrent/{torrentId}/edit/poster/{torrentPosterId}', + name: 'torrent_poster_edit', + requirements: + [ + '_locale' => '%app.locales%', + 'torrentId' => '\d+', + 'torrentPosterId' => '\d+', + ], + defaults: + [ + 'torrentPosterId' => null, + ], + methods: + [ + 'GET', + 'POST' + ] + )] + public function editPoster( + Request $request, + TranslatorInterface $translator, + UserService $userService, + TorrentService $torrentService, + ActivityService $activityService + ): Response + { + // Init user + $user = $this->initUser( + $request, + $userService, + $activityService + ); + + if (!$user->isStatus()) + { + // @TODO + throw new \Exception( + $translator->trans('Access denied') + ); + } + + // Init torrent + if (!$torrent = $torrentService->getTorrent($request->get('torrentId'))) + { + throw $this->createNotFoundException(); + } + + // Init poster value + if ($request->get('torrentPosterId')) + { + if ($torrentPoster = $torrentService->getTorrentPoster($request->get('torrentPosterId'))) + { + $torrentPosterCurrent = + [ + 'id' => $torrentPoster->getId(), + 'userId' => $torrentPoster->getUserId(), + 'value' => 'src' // @TODO + ]; + } + + else + { + throw $this->createNotFoundException(); + } + } + else + { + if ($torrentPoster = $torrentService->findLastTorrentPosterByTorrentId($torrent->getId())) + { + $torrentPosterCurrent = + [ + 'id' => $torrentPoster->getId(), + 'userId' => $torrentPoster->getUserId(), + 'value' => 'src' // @TODO + ]; + } + + else + { + $torrentPosterCurrent = + [ + 'id' => null, + 'userId' => null, + 'value' => false, + ]; + } + } + + // Init edition history + $editions = []; + foreach ($torrentService->findTorrentPosterByTorrentId($torrent->getId()) as $torrentPosterEdition) + { + $editions[] = + [ + 'id' => $torrentPosterEdition->getId(), + 'added' => $torrentPosterEdition->getAdded(), + 'approved' => $torrentPosterEdition->isApproved(), + 'active' => $torrentPosterEdition->getId() == $torrentPosterCurrent['id'], + 'user' => + [ + 'id' => $torrentPosterEdition->getUserId(), + 'identicon' => $userService->identicon( + $userService->getUser( + $torrentPosterEdition->getUserId() + )->getAddress() + ), + ], + 'poster' => + $request->getScheme() . '://' . + $request->getHttpHost() . + $request->getBasePath() . + $torrentService->getImageUriByTorrentPosterId( + $torrentPosterEdition->getId() + ) + ]; + } + + // Init form + $form = + [ + 'poster' => + [ + 'error' => [] + ] + ]; + + // Process request + if ($request->isMethod('post')) + { + if ($file = $request->files->get('poster')) + { + //// Validate poster file + if (filesize($file->getPathName()) > $this->getParameter('app.torrent.poster.size.max')) + { + $form['poster']['error'][] = $translator->trans('Poster file out of size limit'); + } + + //// Validate image format + if (!@getimagesize($file->getPathName())) + { + $form['poster']['error'][] = $translator->trans('Image file not supported'); + } + } + + else + { + $form['poster']['error'][] = $translator->trans('Poster file required'); + } + + // Request is valid + if (empty($form['poster']['error'])) + { + // Save data + $torrentPoster = $torrentService->addTorrentPoster( + $file->getPathName(), + $torrent->getId(), + $user->getId(), + time(), + $user->isApproved() + ); + + // Add activity event + /* @TODO + $activityService->addEventTorrentPosterAdd( + $user->getId(), + $torrent->getId(), + time(), + $torrentPoster->getId() + ); + */ + + // Redirect to info page created + return $this->redirectToRoute( + 'torrent_info', + [ + '_locale' => $request->get('_locale'), + 'torrentId' => $torrent->getId() + ] + ); + } + } + + // Render form template + return $this->render( + 'default/torrent/edit/poster.html.twig', + [ + 'torrentId' => $torrent->getId(), + 'editions' => $editions, + 'form' => $form, + 'session' => + [ + 'moderator' => $user->isModerator(), + 'owner' => $torrentPosterCurrent['userId'] === $user->getId(), + ] + ] + ); + } + + #[Route( + '/{_locale}/torrent/{torrentId}/approve/poster/{torrentPosterId}', + name: 'torrent_poster_approve', + requirements: + [ + '_locale' => '%app.locales%', + 'torrentId' => '\d+', + 'torrentPosterId' => '\d+', + ], + methods: + [ + 'GET' + ] + )] + public function approvePoster( + Request $request, + TranslatorInterface $translator, + UserService $userService, + TorrentService $torrentService, + ActivityService $activityService + ): Response + { + // Init user + $user = $this->initUser( + $request, + $userService, + $activityService + ); + + // Init torrent + if (!$torrent = $torrentService->getTorrent($request->get('torrentId'))) + { + throw $this->createNotFoundException(); + } + + // Init torrent poster + if (!$torrentPoster = $torrentService->getTorrentPoster($request->get('torrentPosterId'))) + { + throw $this->createNotFoundException(); + } + + // Check permissions + if (!$user->isModerator()) + { + // @TODO + throw new \Exception( + $translator->trans('Access denied') + ); + } + + // Add activity event + if (!$torrentPoster->isApproved()) + { + /* @TODO + $activityService->addEventTorrentPosterApproveAdd( + $user->getId(), + $torrent->getId(), + time(), + $torrentPoster->getId() + ); + */ + } + + else + { + /* @TODO + $activityService->addEventTorrentPosterApproveDelete( + $user->getId(), + $torrent->getId(), + time(), + $torrentPoster->getId() + ); + */ + } + + // Update approved + $torrentService->toggleTorrentPosterApproved( + $torrentPoster->getId() + ); + + // Redirect + return $this->redirectToRoute( + 'torrent_poster_edit', + [ + '_locale' => $request->get('_locale'), + 'torrentId' => $torrent->getId(), + 'torrentPosterId' => $torrentPoster->getId(), + ] + ); + } + + #[Route( + '/{_locale}/torrent/{torrentId}/delete/poster/{torrentPosterId}', + name: 'torrent_poster_delete', + requirements: + [ + '_locale' => '%app.locales%', + 'torrentId' => '\d+', + 'torrentPosterId' => '\d+', + ], + methods: + [ + 'GET' + ] + )] + public function deletePoster( + Request $request, + TranslatorInterface $translator, + UserService $userService, + TorrentService $torrentService, + ActivityService $activityService + ): Response + { + // Init user + $user = $this->initUser( + $request, + $userService, + $activityService + ); + + // Init torrent + if (!$torrent = $torrentService->getTorrent($request->get('torrentId'))) + { + throw $this->createNotFoundException(); + } + + // Init torrent poster + if (!$torrentPoster = $torrentService->getTorrentPoster($request->get('torrentPosterId'))) + { + throw $this->createNotFoundException(); + } + + // Check permissions + if (!($user->isModerator() || $user->getId() === $torrentPoster->getUserId())) + { + // @TODO + throw new \Exception( + $translator->trans('Access denied') + ); + } + + // Add activity event + /* @TODO + $activityService->addEventTorrentPosterDelete( + $user->getId(), + $torrent->getId(), + time(), + $torrentPoster->getId() + ); + */ + + // Update approved + $torrentService->deleteTorrentPoster( + $torrentPoster->getId() + ); + + // Redirect + return $this->redirectToRoute( + 'torrent_poster_edit', + [ + '_locale' => $request->get('_locale'), + 'torrentId' => $torrent->getId(), + 'torrentPosterId' => $torrentPoster->getId(), + ] + ); + } + + + + + + + // Torrent star #[Route( '/{_locale}/torrent/{torrentId}/star/toggle', @@ -2519,6 +2934,7 @@ class TorrentController extends AbstractController $this->getParameter('app.theme'), $this->getParameter('app.sensitive'), $this->getParameter('app.yggdrasil'), + $this->getParameter('app.posters'), $this->getParameter('app.approved') ); diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 4b75626..d6dea1f 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -117,6 +117,11 @@ class UserController extends AbstractController $request->get('yggdrasil') === 'true' ); + // Update posters + $user->setPosters( + $request->get('posters') === 'true' + ); + // Save changes to DB $userService->save($user); @@ -137,6 +142,7 @@ class UserController extends AbstractController 'id' => $user->getId(), 'sensitive' => $user->isSensitive(), 'yggdrasil' => $user->isYggdrasil(), + 'posters' => $user->isPosters(), 'locale' => $user->getLocale(), 'locales' => $user->getLocales(), 'events' => $user->getEvents(), @@ -543,6 +549,11 @@ class UserController extends AbstractController true ); + $torrentService->setTorrentPostersApprovedByUserId( + $userTarget->getId(), + true + ); + // @TODO make event for each item } @@ -613,6 +624,7 @@ class UserController extends AbstractController $this->getParameter('app.theme'), $this->getParameter('app.sensitive'), $this->getParameter('app.yggdrasil'), + $this->getParameter('app.posters'), $this->getParameter('app.approved') ); diff --git a/src/Entity/Torrent.php b/src/Entity/Torrent.php index ef34679..0252a8e 100644 --- a/src/Entity/Torrent.php +++ b/src/Entity/Torrent.php @@ -51,6 +51,9 @@ class Torrent #[ORM\Column(nullable: true)] private ?int $leechers = null; + #[ORM\Column(nullable: true)] + private ?int $torrentPosterId = null; + public function getId(): ?int { return $this->id; @@ -206,4 +209,16 @@ class Torrent return $this; } + + public function getTorrentPosterId(): ?int + { + return $this->torrentPosterId; + } + + public function setTorrentPosterId(int $torrentPosterId): static + { + $this->torrentPosterId = $torrentPosterId; + + return $this; + } } diff --git a/src/Entity/TorrentPoster.php b/src/Entity/TorrentPoster.php index c866dea..495fae3 100644 --- a/src/Entity/TorrentPoster.php +++ b/src/Entity/TorrentPoster.php @@ -25,9 +25,6 @@ class TorrentPoster #[ORM\Column] private ?bool $approved = null; - #[ORM\Column(length: 255)] - private ?string $color = null; - #[ORM\Column(length: 32)] private ?string $md5file = null; @@ -91,18 +88,6 @@ class TorrentPoster return $this; } - public function getColor(): ?string - { - return $this->color; - } - - public function setColor(string $color): static - { - $this->color = $color; - - return $this; - } - public function getMd5file(): ?string { return $this->md5file; diff --git a/src/Entity/User.php b/src/Entity/User.php index 7339f65..9f346a7 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -47,6 +47,9 @@ class User #[ORM\Column] private ?bool $yggdrasil = null; + #[ORM\Column] + private ?bool $posters = null; + public function getId(): ?int { return $this->id; @@ -190,4 +193,16 @@ class User return $this; } + + public function isPosters(): ?bool + { + return $this->posters; + } + + public function setPosters(bool $posters): static + { + $this->posters = $posters; + + return $this; + } } diff --git a/src/Service/TorrentService.php b/src/Service/TorrentService.php index 62cd0c5..90ea870 100644 --- a/src/Service/TorrentService.php +++ b/src/Service/TorrentService.php @@ -5,6 +5,7 @@ namespace App\Service; use App\Entity\Torrent; use App\Entity\TorrentLocales; use App\Entity\TorrentSensitive; +use App\Entity\TorrentPoster; use App\Entity\TorrentStar; use App\Entity\TorrentDownloadFile; use App\Entity\TorrentDownloadMagnet; @@ -12,6 +13,7 @@ use App\Entity\TorrentDownloadMagnet; use App\Repository\TorrentRepository; use App\Repository\TorrentLocalesRepository; use App\Repository\TorrentSensitiveRepository; +use App\Repository\TorrentPosterRepository; use App\Repository\TorrentStarRepository; use App\Repository\TorrentDownloadFileRepository; use App\Repository\TorrentDownloadMagnetRepository; @@ -214,10 +216,93 @@ class TorrentService ); } + public function getImageUriByTorrentPosterId( + int $torrentPosterId, + int $quality = 100, + int $width = 748, + int $height = 0, + float $opacity = 1, + bool $grayscale = false, + string $format = 'webp' + ): string + { + $uri = sprintf( + '/posters/%s.%s', + implode('/', str_split($torrentPosterId)), + $format + ); + + $filename = sprintf( + '%s/public/posters/%s.%s', + $this->kernelInterface->getProjectDir(), + implode('/', str_split($torrentPosterId)), + $format + ); + + if (file_exists($filename)) + { + return $uri; + } + + $path = explode('/', $filename); + + array_pop($path); + + @mkdir(implode('/', $path), 0755, true); + + $image = new \Imagick(); + + $image->readImage( + $this->getStorageFilepathByTorrentPosterId( + $torrentPosterId + ) + ); + + $image->setImageFormat($format); + $image->setImageCompressionQuality($quality); + + if ($width || $height) + { + $image->adaptiveResizeImage( + $width, + $height + ); + } + + if ($grayscale) + { + $image->setImageType( + \Imagick::IMGTYPE_GRAYSCALE + ); + } + + if ($opacity) + { + $image->setImageOpacity( + $opacity + ); + } + + $image->writeImage( + $filename + ); + + return $uri; + } + + public function getStorageFilepathByTorrentPosterId(int $torrentPosterId): string + { + return sprintf( + '%s/var/posters/%s', + $this->kernelInterface->getProjectDir(), + implode('/', str_split($torrentPosterId)) + ); + } + public function getStorageFilepathByTorrentId(int $torrentId): string { return sprintf( - '%s/var/torrents/%s.torrent', + '%s/var/torrents/%s.torrent', // @TODO remove extension as not required in background storage $this->kernelInterface->getProjectDir(), implode('/', str_split($torrentId)) ); @@ -932,6 +1017,209 @@ class TorrentService } } + // Torrent poster + public function getTorrentPoster( + int $torrentPosterId + ): ?TorrentPoster + { + return $this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->find( + $torrentPosterId + ); + } + + public function findTorrentPosterByMd5File( + string $md5file + ): ?Torrent + { + return $this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->findOneBy( + [ + 'md5file' => $md5file + ] + ); + } + + public function findLastTorrentPosterByTorrentId( + int $torrentId + ): ?TorrentPoster + { + return $this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->findOneBy( + [ + 'torrentId' => $torrentId + ], + [ + 'id' => 'DESC' + ] + ); + } + + public function findTorrentPosterByTorrentId( + int $torrentId + ): array + { + return $this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->findBy( + [ + 'torrentId' => $torrentId + ], + [ + 'id' => 'DESC' + ] + ); + } + + public function toggleTorrentPosterApproved( + int $torrentPosterId + ): ?TorrentPoster + { + $torrentPoster = $this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->find($torrentPosterId); + + $torrentPoster->setApproved( + !$torrentPoster->isApproved() // toggle current value + ); + + $this->entityManagerInterface->persist($torrentPoster); + $this->entityManagerInterface->flush(); + + $this->updateTorrentPoster( + $torrentPoster->getTorrentId() + ); + + return $torrentSensitive; + } + + public function deleteTorrentPoster( + int $torrentPosterId + ): ?TorrentPoster + { + // Remove torrent file from permanent storage + $filesystem = new Filesystem(); + $filesystem->remove( + $this->getStorageFilepathByTorrentPosterId( + $torrentPosterId + ) + ); + + // Remove from DB + $torrentPoster = $this->getTorrentPoster( + $torrentPosterId + ); + + $this->entityManagerInterface->remove($torrentPoster); + $this->entityManagerInterface->flush(); + + // Update torrent + $this->updateTorrentPoster( + $torrentPoster->getTorrentId() + ); + + return $torrentSensitive; + } + + public function addTorrentPoster( + string $filename, + int $torrentId, + int $userId, + int $added, + bool $approved + ): ?TorrentPoster + { + // Add new DB record + $torrentPoster = new TorrentPoster(); + + $torrentPoster->setTorrentId($torrentId); + $torrentPoster->setUserId($userId); + $torrentPoster->setAdded($added); + $torrentPoster->setApproved($approved); + $torrentPoster->setMd5file( + md5_file($filename) + ); + + $this->entityManagerInterface->persist($torrentPoster); + $this->entityManagerInterface->flush(); + + // Save file in permanent storage + $filesystem = new Filesystem(); + $filesystem->copy( + $filename, + $this->getStorageFilepathByTorrentPosterId( + $torrentPoster->getId() + ) + ); + + // Update torrent info + $this->updateTorrentPoster( + $torrentId + ); + + return $torrentPoster; + } + + public function setTorrentPostersApprovedByUserId( + int $userId, + bool $value + ): void + { + foreach ($this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->findBy( + [ + 'userId' => $userId + ]) as $torrentPoster) + { + $torrentPoster->setApproved( + $value + ); + + $this->entityManagerInterface->persist($torrentPoster); + $this->entityManagerInterface->flush(); + + $this->updateTorrentPoster( + $torrentPoster->getTorrentId(), + ); + } + } + + public function updateTorrentPoster( + int $torrentId, + ): void + { + if ($torrent = $this->getTorrent($torrentId)) + { + if ($torrentPoster = $this->entityManagerInterface + ->getRepository(TorrentPoster::class) + ->findOneBy( + [ + 'torrentId' => $torrentId, + 'approved' => true, + ], + [ + 'id' => 'DESC' + ] + )) + { + $torrent->setTorrentPosterId( + $torrentPoster->getId() + ); + + $this->entityManagerInterface->persist($torrent); + $this->entityManagerInterface->flush(); + } + } + } + + + + + // Torrent star public function findTorrentStar( int $torrentId, diff --git a/src/Service/UserService.php b/src/Service/UserService.php index 2459d5d..eeba420 100644 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -32,6 +32,7 @@ class UserService string $theme, bool $sensitive = true, bool $yggdrasil = true, + bool $posters = true, bool $approved = false, bool $moderator = false, bool $status = true @@ -84,6 +85,10 @@ class UserService $yggdrasil ); + $user->setPosters( + $posters + ); + $this->entityManagerInterface->persist($user); $this->entityManagerInterface->flush(); diff --git a/templates/default/torrent/edit/poster.html.twig b/templates/default/torrent/edit/poster.html.twig new file mode 100644 index 0000000..a987a22 --- /dev/null +++ b/templates/default/torrent/edit/poster.html.twig @@ -0,0 +1,84 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{ 'Edit torrent poster' | trans }} - {{ 'Torrent' | trans }} #{{ torrentId }} - {{ name }}{% endblock %} +{% block main_content %} +
+
+

+ {{'Edit poster for torrent' | trans }} + #{{ torrentId }} +

+
+
+
+ {% for error in form.poster.error %} +
+ {{ error }} +
+ {% endfor %} + +
+
+ +
+
+ {% for edition in editions %} +
+ {% if edition.active %} + {{ edition.added | format_ago }} + {% else %} + + {{ edition.added | format_ago }} + + {% endif %} + {{ 'by' | trans }} + + {{'identicon'|trans }} + +
+ {% if session.moderator or session.owner %} + + + + + + + {% endif %} + {% if edition.approved %} + {% if session.moderator %} + + + + + + {% else %} + + + + + + {% endif %} + {% else %} + {% if session.moderator %} + + + + + + {% else %} + + + + + + {% endif %} + {% endif %} +
+
+ {% endfor %} +{% endblock %} diff --git a/templates/default/torrent/info.html.twig b/templates/default/torrent/info.html.twig index 46e939f..1004759 100644 --- a/templates/default/torrent/info.html.twig +++ b/templates/default/torrent/info.html.twig @@ -29,7 +29,8 @@ {% endif %} {% endblock %} {% block main_content %} -
+

{{ file.name }} {#{{ 'Torrent' | trans }} #{{ torrent.id }}#} @@ -364,6 +365,22 @@ {% endif %}

+
+ + + + + + {{ 'Poster' | trans }} +
+
+ {% if torrent.poster %} + {{ 'Yes' | trans }} + {% else %} + {{ 'No' | trans }} + {% endif %} +
+
diff --git a/templates/default/torrent/list.html.twig b/templates/default/torrent/list.html.twig index c0824d8..404f3eb 100644 --- a/templates/default/torrent/list.html.twig +++ b/templates/default/torrent/list.html.twig @@ -24,7 +24,8 @@
{% if torrents %} {% for torrent in torrents %} -
+

@@ -86,15 +87,6 @@

{% endif %}
- {# - - {{ torrent.added | format_ago }} - {{ 'by' | trans }} - - {{ 'identicon' | trans }} - - - #} {{ torrent.file.size | format_bytes }} diff --git a/templates/default/user/settings.html.twig b/templates/default/user/settings.html.twig index 857c555..62fe207 100644 --- a/templates/default/user/settings.html.twig +++ b/templates/default/user/settings.html.twig @@ -58,6 +58,23 @@
+ + + {{ 'Posters' | trans }} + + +
+ {% if user.posters %} + + {% else %} + + {% endif %} + +
+ + {{ 'Search' | trans }}