feature/removegit #9
| @@ -7,7 +7,6 @@ | |||||||
|         "php": ">=8.3", |         "php": ">=8.3", | ||||||
|         "ext-ctype": "*", |         "ext-ctype": "*", | ||||||
|         "ext-iconv": "*", |         "ext-iconv": "*", | ||||||
|         "czproject/git-php": "^4.1", |  | ||||||
|         "doctrine/doctrine-bundle": "^2.9", |         "doctrine/doctrine-bundle": "^2.9", | ||||||
|         "doctrine/doctrine-migrations-bundle": "^3.2", |         "doctrine/doctrine-migrations-bundle": "^3.2", | ||||||
|         "doctrine/orm": "^2.14", |         "doctrine/orm": "^2.14", | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										54
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @@ -4,60 +4,8 @@ | |||||||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", |         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | ||||||
|         "This file is @generated automatically" |         "This file is @generated automatically" | ||||||
|     ], |     ], | ||||||
|     "content-hash": "0d9cbf5f6f95b13006484d60ccb4d67c", |     "content-hash": "59e27d83488f4238ab779a64962a039a", | ||||||
|     "packages": [ |     "packages": [ | ||||||
|         { |  | ||||||
|             "name": "czproject/git-php", |  | ||||||
|             "version": "v4.2.0", |  | ||||||
|             "source": { |  | ||||||
|                 "type": "git", |  | ||||||
|                 "url": "https://github.com/czproject/git-php.git", |  | ||||||
|                 "reference": "e257f2c3b43fe8fef19ddb5727b604416b423107" |  | ||||||
|             }, |  | ||||||
|             "dist": { |  | ||||||
|                 "type": "zip", |  | ||||||
|                 "url": "https://api.github.com/repos/czproject/git-php/zipball/e257f2c3b43fe8fef19ddb5727b604416b423107", |  | ||||||
|                 "reference": "e257f2c3b43fe8fef19ddb5727b604416b423107", |  | ||||||
|                 "shasum": "" |  | ||||||
|             }, |  | ||||||
|             "require": { |  | ||||||
|                 "php": ">=5.6.0" |  | ||||||
|             }, |  | ||||||
|             "require-dev": { |  | ||||||
|                 "nette/tester": "^2.0" |  | ||||||
|             }, |  | ||||||
|             "type": "library", |  | ||||||
|             "autoload": { |  | ||||||
|                 "classmap": [ |  | ||||||
|                     "src/" |  | ||||||
|                 ] |  | ||||||
|             }, |  | ||||||
|             "notification-url": "https://packagist.org/downloads/", |  | ||||||
|             "license": [ |  | ||||||
|                 "BSD-3-Clause" |  | ||||||
|             ], |  | ||||||
|             "authors": [ |  | ||||||
|                 { |  | ||||||
|                     "name": "Jan Pecha", |  | ||||||
|                     "email": "janpecha@email.cz" |  | ||||||
|                 } |  | ||||||
|             ], |  | ||||||
|             "description": "Library for work with Git repository in PHP.", |  | ||||||
|             "keywords": [ |  | ||||||
|                 "git" |  | ||||||
|             ], |  | ||||||
|             "support": { |  | ||||||
|                 "issues": "https://github.com/czproject/git-php/issues", |  | ||||||
|                 "source": "https://github.com/czproject/git-php/tree/v4.2.0" |  | ||||||
|             }, |  | ||||||
|             "funding": [ |  | ||||||
|                 { |  | ||||||
|                     "url": "https://www.janpecha.cz/donate/git-php/", |  | ||||||
|                     "type": "other" |  | ||||||
|                 } |  | ||||||
|             ], |  | ||||||
|             "time": "2023-07-12T09:14:30+00:00" |  | ||||||
|         }, |  | ||||||
|         { |         { | ||||||
|             "name": "doctrine/cache", |             "name": "doctrine/cache", | ||||||
|             "version": "2.2.0", |             "version": "2.2.0", | ||||||
|   | |||||||
| @@ -4,8 +4,6 @@ | |||||||
| # Put parameters here that don't need to change on each machine where the app is deployed | # Put parameters here that don't need to change on each machine where the app is deployed | ||||||
| # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration | # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration | ||||||
| parameters: | parameters: | ||||||
|     snipStorageType: 'db' # 'db' or 'git |  | ||||||
|     gitStoragePath: '%kernel.project_dir%/var/snips' |  | ||||||
|  |  | ||||||
| services: | services: | ||||||
|     # default configuration for services in *this* file |     # default configuration for services in *this* file | ||||||
| @@ -25,8 +23,3 @@ services: | |||||||
|     App\Service\LastRelease: |     App\Service\LastRelease: | ||||||
|         arguments: |         arguments: | ||||||
|             - '%kernel.project_dir%/release.json' |             - '%kernel.project_dir%/release.json' | ||||||
|  |  | ||||||
|     App\Service\SnipServiceFactory: |  | ||||||
|         arguments: |  | ||||||
|             $gitStoragePath: '%gitStoragePath%' |  | ||||||
|             $storageType: '%snipStorageType%' |  | ||||||
| @@ -67,7 +67,7 @@ task('deployment:log', function () { //https://stackoverflow.com/questions/59686 | |||||||
|     $commitDate = $commit[1]; |     $commitDate = $commit[1]; | ||||||
|  |  | ||||||
| //    $line = sprintf('%s %s branch="%s" hash="%s"', $date, $commitHashShort, $branch, $commitHash); | //    $line = sprintf('%s %s branch="%s" hash="%s"', $date, $commitHashShort, $branch, $commitHash); | ||||||
|     $projectUrlBase = 'https://git.loken.nl/ardent/AnimeRSS4'; |     $projectUrlBase = 'https://git.loken.nl/ardent/Snips'; | ||||||
|     $array = [ |     $array = [ | ||||||
|         'branch' => $branch, |         'branch' => $branch, | ||||||
|         'branchUrl' => sprintf('%s/src/branch/%s', $projectUrlBase, $branch), |         'branchUrl' => sprintf('%s/src/branch/%s', $projectUrlBase, $branch), | ||||||
|   | |||||||
| @@ -49,11 +49,12 @@ class SnipController extends AbstractController | |||||||
|         $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); |         $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); | ||||||
|  |  | ||||||
|         $snipService = $this->snipServiceFactory->create($snip); |         $snipService = $this->snipServiceFactory->create($snip); | ||||||
|         dump($snipService); |  | ||||||
|         return $this->render('snip/single.html.twig', [ |         return $this->render('snip/single.html.twig', [ | ||||||
|             'snip' => $snip, |             'snip' => $snip, | ||||||
|             'content' => $pl->parse($snipService->get()), |             'content' => $pl->parse($snipService->getActiveText()), | ||||||
|             'branch' => $snipService->getCommit(), |             'activeVersion' => $snipService->getActiveVersion(), | ||||||
|  |             'latestVersion' => $snipService->getLatestVersion(), | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -63,7 +64,7 @@ class SnipController extends AbstractController | |||||||
|         $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); |         $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); | ||||||
|  |  | ||||||
|         $response = new Response( |         $response = new Response( | ||||||
|             $pl->clean($this->snipServiceFactory->create($snip)->get()), |             $pl->clean($this->snipServiceFactory->create($snip)->getActiveText()), | ||||||
|             Response::HTTP_OK, |             Response::HTTP_OK, | ||||||
|             ['Content-Type' => 'text/html'] |             ['Content-Type' => 'text/html'] | ||||||
|         ); |         ); | ||||||
| @@ -88,7 +89,7 @@ class SnipController extends AbstractController | |||||||
|         $form = $this->createForm(SnipType::class, $snip); |         $form = $this->createForm(SnipType::class, $snip); | ||||||
|         $form->add('Save', SubmitType::class); |         $form->add('Save', SubmitType::class); | ||||||
|         if ($snip->getId()) { |         if ($snip->getId()) { | ||||||
|             $form->get('content')->setData($this->snipServiceFactory->create($snip)->get()); |             $form->get('content')->setData($this->snipServiceFactory->create($snip)->getActiveText()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         $form->handleRequest($request); |         $form->handleRequest($request); | ||||||
|   | |||||||
| @@ -3,14 +3,15 @@ | |||||||
| namespace App\Controller; | namespace App\Controller; | ||||||
| 
 | 
 | ||||||
| use App\Entity\Snip; | use App\Entity\Snip; | ||||||
|  | use App\Entity\SnipContent; | ||||||
| use App\Security\Voter\SnipVoter; | use App\Security\Voter\SnipVoter; | ||||||
| use App\Service\SnipServiceFactory; | use App\Service\SnipServiceFactory; | ||||||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||||||
| use Symfony\Component\HttpFoundation\Response; | use Symfony\Component\HttpFoundation\Response; | ||||||
| use Symfony\Component\Routing\Annotation\Route; | use Symfony\Component\Routing\Annotation\Route; | ||||||
| 
 | 
 | ||||||
| #[Route('/history/{snip}', name: 'history')]
 | #[Route('/version/{snip}', name: 'version')]
 | ||||||
| class HistoryController extends AbstractController | class VersionController extends AbstractController | ||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         private readonly SnipServiceFactory $snipServiceFactory, |         private readonly SnipServiceFactory $snipServiceFactory, | ||||||
| @@ -22,7 +23,7 @@ class HistoryController extends AbstractController | |||||||
|         $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); |         $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); | ||||||
| 
 | 
 | ||||||
|         $snipService = $this->snipServiceFactory->create($snip); |         $snipService = $this->snipServiceFactory->create($snip); | ||||||
|         return $this->render('history/index.html.twig', [ |         return $this->render('version/index.html.twig', [ | ||||||
|             'snip' => $snip, |             'snip' => $snip, | ||||||
|             'versions' => $snipService->getVersions(), |             'versions' => $snipService->getVersions(), | ||||||
|             'latestVersion' => $snipService->getLatestVersion(), |             'latestVersion' => $snipService->getLatestVersion(), | ||||||
| @@ -30,12 +31,12 @@ class HistoryController extends AbstractController | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[Route('/set/{version}', name: '_set')]
 |     #[Route('/set/{version}', name: '_set')]
 | ||||||
|     public function set(Snip $snip, string $version): Response |     public function set(Snip $snip, SnipContent $version): Response | ||||||
|     { |     { | ||||||
|         $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); |         $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); | ||||||
| 
 | 
 | ||||||
|         $this->snipServiceFactory->create($snip)->setVersion($version); |         $this->snipServiceFactory->create($snip)->setVersion($version->getId()); | ||||||
|         $this->addFlash('success', 'Snip version set to ' . $version); |         $this->addFlash('success', 'Snip version set to ' . $version->getId()); | ||||||
|         return $this->redirectToRoute('snip_single', ['snip' => $snip->getId()]); |         return $this->redirectToRoute('snip_single', ['snip' => $snip->getId()]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace App\Git; |  | ||||||
|  |  | ||||||
| use CzProject\GitPhp\Git; |  | ||||||
|  |  | ||||||
| class CustomGit extends Git |  | ||||||
| { |  | ||||||
|     public function open($directory): CustomGitRepository |  | ||||||
|     { |  | ||||||
|         return new CustomGitRepository($directory, $this->runner); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace App\Git; |  | ||||||
|  |  | ||||||
| use CzProject\GitPhp\GitRepository; |  | ||||||
| use DateTime; |  | ||||||
|  |  | ||||||
| class CustomGitRepository extends GitRepository |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * @return array<SimpleCommit> |  | ||||||
|      * @throws \CzProject\GitPhp\GitException |  | ||||||
|      */ |  | ||||||
|     public function getAllCommits(): array |  | ||||||
|     { |  | ||||||
|         $result = $this->run('log', '--pretty=%H,%cI'); |  | ||||||
|  |  | ||||||
|         if (empty($result->getOutput())) { |  | ||||||
|             return []; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $commits = []; |  | ||||||
|         foreach ($result->getOutput() as $line) { |  | ||||||
|             $parts = explode(',', $line); |  | ||||||
|             $commits[] = new SimpleCommit( |  | ||||||
|                 $parts[0], |  | ||||||
|                 new DateTime($parts[1]) |  | ||||||
|             ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return $commits; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace App\Git; |  | ||||||
|  |  | ||||||
| use DateTime; |  | ||||||
|  |  | ||||||
| class SimpleCommit |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public function __construct( |  | ||||||
|         private readonly string $hash, |  | ||||||
|         private readonly DateTime $date, |  | ||||||
|     ) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getHash(): string |  | ||||||
|     { |  | ||||||
|         return $this->hash; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getDate(): DateTime |  | ||||||
|     { |  | ||||||
|         return $this->date; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										0
									
								
								src/Repository/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								src/Repository/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,80 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace App\Service\SnipContent; |  | ||||||
|  |  | ||||||
| use App\Entity\User; |  | ||||||
| use App\Git\CustomGitRepository; |  | ||||||
| use App\Git\SimpleCommit; |  | ||||||
| use Symfony\Component\Security\Core\User\UserInterface; |  | ||||||
|  |  | ||||||
| class SnipContentGit implements SnipContentInterface |  | ||||||
| { |  | ||||||
|     private const string SNIP_FILE_NAME = 'snip.txt'; |  | ||||||
|     private const string MASTER_BRANCH_NAME = 'master'; |  | ||||||
|  |  | ||||||
|     public function __construct( |  | ||||||
|         private readonly CustomGitRepository $repo, |  | ||||||
|         private readonly ?User               $user, |  | ||||||
|     ) {} |  | ||||||
|  |  | ||||||
|     private function snipExists(): bool |  | ||||||
|     { |  | ||||||
|         return file_exists($this->getSnipPath()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private function getSnipPath(): string |  | ||||||
|     { |  | ||||||
|         return sprintf('%s/snip.txt', $this->repo->getRepositoryPath()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function update(string $snipContents): void |  | ||||||
|     { |  | ||||||
|         if (!$this->user instanceof UserInterface) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if ($this->repo->getCurrentBranchName() !== self::MASTER_BRANCH_NAME) { |  | ||||||
|             $this->repo->checkout(self::MASTER_BRANCH_NAME); |  | ||||||
|         } |  | ||||||
|         file_put_contents($this->getSnipPath(), $snipContents); |  | ||||||
|         $this->repo->addFile(self::SNIP_FILE_NAME); |  | ||||||
|         if ($this->repo->hasChanges()) { |  | ||||||
|             $this->repo->commit(sprintf('Updated snip at %s by %s', date('Y-m-d H:i:s'), $this->user)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function get(): string |  | ||||||
|     { |  | ||||||
|         if (!$this->snipExists()) { |  | ||||||
|             return ''; |  | ||||||
|         } |  | ||||||
|         return file_get_contents($this->getSnipPath()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getVersions(): array |  | ||||||
|     { |  | ||||||
|         return array_map(fn(SimpleCommit $c) => [ |  | ||||||
|             'id' => $c->getHash(), |  | ||||||
|             'name' => $c->getDate()->format('Y-m-d H:i:s'), |  | ||||||
|         ], $this->repo->getAllCommits()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function setVersion(string $version): void |  | ||||||
|     { |  | ||||||
|         $this->repo->checkout($version); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getCommit(): string |  | ||||||
|     { |  | ||||||
|         return $this->repo->getCurrentBranchName(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(): void |  | ||||||
|     { |  | ||||||
|         system("rm -rf " . escapeshellarg($this->repo->getRepositoryPath())); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getLatestVersion(): string |  | ||||||
|     { |  | ||||||
|         return self::MASTER_BRANCH_NAME; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace App\Service\SnipContent; |  | ||||||
|  |  | ||||||
| interface SnipContentInterface |  | ||||||
| { |  | ||||||
|     public function update(string $snipContents): void; |  | ||||||
|  |  | ||||||
|     public function get(): string; |  | ||||||
|  |  | ||||||
|     /** @return array{id: string, name: string} */ |  | ||||||
|     public function getVersions(): array; |  | ||||||
|  |  | ||||||
|     public function setVersion(string $version): void; |  | ||||||
|  |  | ||||||
|     public function getCommit(): string; |  | ||||||
|  |  | ||||||
|     public function getLatestVersion(): string; |  | ||||||
|  |  | ||||||
|     public function delete(): void; |  | ||||||
| } |  | ||||||
| @@ -4,14 +4,12 @@ namespace App\Service\SnipContent; | |||||||
| 
 | 
 | ||||||
| use App\Entity\Snip; | use App\Entity\Snip; | ||||||
| use App\Entity\SnipContent; | use App\Entity\SnipContent; | ||||||
| use App\Entity\User; |  | ||||||
| use Doctrine\ORM\EntityManagerInterface; | use Doctrine\ORM\EntityManagerInterface; | ||||||
| 
 | 
 | ||||||
| readonly class SnipContentDB implements SnipContentInterface | readonly class SnipContentService | ||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         private Snip                   $snip, |         private Snip                   $snip, | ||||||
|         private User                   $user, |  | ||||||
|         private EntityManagerInterface $em, |         private EntityManagerInterface $em, | ||||||
|     ) {} |     ) {} | ||||||
| 
 | 
 | ||||||
| @@ -35,12 +33,14 @@ readonly class SnipContentDB implements SnipContentInterface | |||||||
|         $this->em->flush(); |         $this->em->flush(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function get(): string |     // Shortcut to get the active text
 | ||||||
|  |     public function getActiveText(): string | ||||||
|     { |     { | ||||||
|         $contentRepo = $this->em->getRepository(SnipContent::class); |         $contentRepo = $this->em->getRepository(SnipContent::class); | ||||||
|         return $contentRepo->find($this->snip->getActiveCommit())->getText(); |         return $contentRepo->find($this->snip->getActiveCommit())->getText(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** @return array{id: string, name: string} */ | ||||||
|     public function getVersions(): array |     public function getVersions(): array | ||||||
|     { |     { | ||||||
|         // Return all snipContent entities (by parent)
 |         // Return all snipContent entities (by parent)
 | ||||||
| @@ -57,14 +57,14 @@ readonly class SnipContentDB implements SnipContentInterface | |||||||
|         $this->em->flush(); |         $this->em->flush(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function getCommit(): string |     public function getActiveVersion(): string | ||||||
|     { |     { | ||||||
|         return $this->snip->getActiveCommit(); |         return $this->snip->getActiveCommit(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function delete(): void |     public function delete(): void | ||||||
|     { |     { | ||||||
|         // Cleanup the history
 |         // Cleanup the versions
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function getLatestVersion(): string |     public function getLatestVersion(): string | ||||||
| @@ -2,10 +2,10 @@ | |||||||
|  |  | ||||||
| namespace App\Service\SnipParser\Stages; | namespace App\Service\SnipParser\Stages; | ||||||
|  |  | ||||||
|  | use App\Repository\SnipContentRepository; | ||||||
| use App\Repository\SnipRepository; | use App\Repository\SnipRepository; | ||||||
| use App\Security\Voter\SnipVoter; | use App\Security\Voter\SnipVoter; | ||||||
| use App\Service\SnipParser\Pipeline; | use App\Service\SnipParser\Pipeline; | ||||||
| use App\Service\SnipServiceFactory; |  | ||||||
| use League\Pipeline\StageInterface; | use League\Pipeline\StageInterface; | ||||||
| use Symfony\Bundle\SecurityBundle\Security; | use Symfony\Bundle\SecurityBundle\Security; | ||||||
| use Symfony\Component\DependencyInjection\Attribute\Autowire; | use Symfony\Component\DependencyInjection\Attribute\Autowire; | ||||||
| @@ -15,7 +15,7 @@ class IncludeReferenceStage implements StageInterface | |||||||
|     public function __construct( |     public function __construct( | ||||||
|         #[Autowire(lazy: true)] private readonly Security              $security, |         #[Autowire(lazy: true)] private readonly Security              $security, | ||||||
|         #[Autowire(lazy: true)] private readonly SnipRepository        $snipRepository, |         #[Autowire(lazy: true)] private readonly SnipRepository        $snipRepository, | ||||||
|         #[Autowire(lazy: true)] private readonly SnipServiceFactory $snipServiceFactory, |         #[Autowire(lazy: true)] private readonly SnipContentRepository $snipContentRepository, | ||||||
|         #[Autowire(lazy: true)] private readonly Pipeline              $pipeline, |         #[Autowire(lazy: true)] private readonly Pipeline              $pipeline, | ||||||
|     ) {} |     ) {} | ||||||
|  |  | ||||||
| @@ -26,19 +26,32 @@ class IncludeReferenceStage implements StageInterface | |||||||
|  |  | ||||||
|     private function replaceReferences(mixed $payload): string |     private function replaceReferences(mixed $payload): string | ||||||
|     { |     { | ||||||
|         // replaces all references (#n) to other snips with links |         // replaces all references ({{ID}}) with the content of the snip | ||||||
|         $pattern = '/\{\{(\d+)\}\}/'; |         $pattern = '/\{\{([A-Z0-9]+)\}\}/'; | ||||||
|  |  | ||||||
|         return preg_replace_callback($pattern, function ($matches) { |         return preg_replace_callback($pattern, function ($matches) { | ||||||
|             $snip = $this->snipRepository->find($matches[1]); |             $id = $matches[1]; | ||||||
|             if ($snip === null) { |             try { | ||||||
|                 return sprintf('<span title="not found">%s</span>', $matches[0]); |                 $content = $this->snipContentRepository->find($id); | ||||||
|  |             } catch (\Exception) { | ||||||
|  |                 $content = null; | ||||||
|  |             } | ||||||
|  |             if ($content) { | ||||||
|  |                 $snip = $content->getSnip(); | ||||||
|  |             } else { | ||||||
|  |                 $snip = $this->snipRepository->find($id); | ||||||
|  |                 if ($snip) { | ||||||
|  |                     $content = $this->snipContentRepository->find($snip->getActiveCommit()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if ($content === null) { | ||||||
|  |                 return sprintf('<span title="snip or content not found">%s</span>', $matches[0]); | ||||||
|             } |             } | ||||||
|             if (!$this->security->isGranted(SnipVoter::VIEW, $snip)) { |             if (!$this->security->isGranted(SnipVoter::VIEW, $snip)) { | ||||||
|                 return sprintf('<span title="access denied">%s</span>', $matches[0]); |                 return sprintf('<span title="access denied">%s</span>', $matches[0]); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return $this->pipeline->parse($this->snipServiceFactory->create($snip)->get()); |             return $this->pipeline->parse($content->getText()); | ||||||
|         }, $payload); |         }, $payload); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -3,48 +3,17 @@ | |||||||
| namespace App\Service; | namespace App\Service; | ||||||
|  |  | ||||||
| use App\Entity\Snip; | use App\Entity\Snip; | ||||||
| use App\Git\CustomGit; | use App\Service\SnipContent\SnipContentService; | ||||||
| use App\Service\SnipContent\SnipContentDB; |  | ||||||
| use App\Service\SnipContent\SnipContentGit; |  | ||||||
| use App\Service\SnipContent\SnipContentInterface; |  | ||||||
| use Doctrine\ORM\EntityManagerInterface; | use Doctrine\ORM\EntityManagerInterface; | ||||||
| use Symfony\Bundle\SecurityBundle\Security; |  | ||||||
|  |  | ||||||
| class SnipServiceFactory | class SnipServiceFactory | ||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         private readonly string                 $gitStoragePath, |  | ||||||
|         private readonly string                 $storageType, |  | ||||||
|         private readonly Security               $security, |  | ||||||
|         private readonly EntityManagerInterface $em, |         private readonly EntityManagerInterface $em, | ||||||
|     ) {} |     ) {} | ||||||
|  |  | ||||||
|     public function create(Snip $snip): SnipContentInterface |     public function create(Snip $snip): SnipContentService | ||||||
|     { |     { | ||||||
|         return match ($this->storageType) { |         return new SnipContentService($snip, $this->em); | ||||||
|             'git'   => $this->createGit($snip), |  | ||||||
|             'db'    => $this->createDB($snip), |  | ||||||
|             default => throw new \Exception('Unknown storage type'), |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private function createGit(Snip $snip): SnipContentGit |  | ||||||
|     { |  | ||||||
|         $git = new CustomGit(); |  | ||||||
|         $repoPath = sprintf('%s/%s', $this->gitStoragePath, $snip->getId()); |  | ||||||
|         if (!is_dir($repoPath)) { |  | ||||||
|             $repo = $git->init($repoPath); |  | ||||||
|             touch(sprintf('%s/.gitignore', $repoPath)); |  | ||||||
|             $repo->addFile('.gitignore'); |  | ||||||
|             $repo->commit('Initial commit'); |  | ||||||
|         } else { |  | ||||||
|             $repo = $git->open($repoPath); |  | ||||||
|         } |  | ||||||
|         return new SnipContentGit($repo, $this->security->getUser()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private function createDB(Snip $snip): SnipContentDB |  | ||||||
|     { |  | ||||||
|         return new SnipContentDB($snip, $this->security->getUser(), $this->em); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -10,8 +10,8 @@ | |||||||
|         <a class="btn btn-warning" href="{{ path('snip_edit', {snip: snip.id}) }}"> |         <a class="btn btn-warning" href="{{ path('snip_edit', {snip: snip.id}) }}"> | ||||||
|             <i class="fa fa-pencil" aria-hidden="true"></i> Edit |             <i class="fa fa-pencil" aria-hidden="true"></i> Edit | ||||||
|         </a> |         </a> | ||||||
|         <a class="btn btn-info" href="{{ path('history_index', {snip: snip.id}) }}"> |         <a class="btn btn-info" href="{{ path('version_index', {snip: snip.id}) }}"> | ||||||
|             <i class="fa fa-history" aria-hidden="true"></i> History |             <i class="fa fa-history" aria-hidden="true"></i> Versions | ||||||
|         </a> |         </a> | ||||||
|         <a href="{{ path('snip_delete', {snip: snip.id}) }}" class="btn btn-danger"> |         <a href="{{ path('snip_delete', {snip: snip.id}) }}" class="btn btn-danger"> | ||||||
|             <i class="fa fa-trash"></i> Delete |             <i class="fa fa-trash"></i> Delete | ||||||
| @@ -26,12 +26,15 @@ | |||||||
|             {{ include('snip/badge.html.twig', {snip: snip}) }} |             {{ include('snip/badge.html.twig', {snip: snip}) }} | ||||||
|             {{ snip }} <small class="text-muted">#{{ snip.id }}</small> |             {{ snip }} <small class="text-muted">#{{ snip.id }}</small> | ||||||
|         </h4> |         </h4> | ||||||
|         <div class="card-header"> |  | ||||||
|             <p class="card-text">Current version: {{ branch }}</p> |  | ||||||
|         </div> |  | ||||||
|         <div class="card-body"> |         <div class="card-body"> | ||||||
|             {{ content|raw }} |             {{ content|raw }} | ||||||
|         </div> |         </div> | ||||||
|  |         <div class="card-footer"> | ||||||
|  |             <p class="card-text text-muted"> | ||||||
|  |                 Current version: {{ activeVersion }} | ||||||
|  |                 {% if activeVersion == latestVersion %}(latest){% endif %} | ||||||
|  |             </p> | ||||||
|  |         </div> | ||||||
|     </div> |     </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,13 +6,13 @@ | |||||||
|     <a href="{{ path('snip_single', {snip: snip.id}) }}" class="btn btn-primary"> |     <a href="{{ path('snip_single', {snip: snip.id}) }}" class="btn btn-primary"> | ||||||
|         <i class="fa fa-arrow-left"></i> Back |         <i class="fa fa-arrow-left"></i> Back | ||||||
|     </a> |     </a> | ||||||
|     <a href="{{ path('history_set', {version: latestVersion, snip: snip.id}) }}" class="btn btn-warning"> |     <a href="{{ path('version_set', {version: latestVersion, snip: snip.id}) }}" class="btn btn-warning"> | ||||||
|         <i class="fa fa-refresh"></i> Latest |         <i class="fa fa-refresh"></i> Latest | ||||||
|     </a> |     </a> | ||||||
|     <br><br> |     <br><br> | ||||||
|     <div class="list-group"> |     <div class="list-group"> | ||||||
|         {% for version in versions %} |         {% for version in versions %} | ||||||
|             <a class="list-group-item" href="{{ path('history_set', {version: version.id, snip: snip.id}) }}"> |             <a class="list-group-item" href="{{ path('version_set', {version: version.id, snip: snip.id}) }}"> | ||||||
|                 {{ version.name }} - {{ version.id }} |                 {{ version.name }} - {{ version.id }} | ||||||
|             </a> |             </a> | ||||||
|         {% endfor %} |         {% endfor %} | ||||||
		Reference in New Issue
	
	Block a user