Skip to content

Commit

Permalink
Allow to freeze updates for a new release after expire a user license
Browse files Browse the repository at this point in the history
  • Loading branch information
vtsykun committed Dec 22, 2019
1 parent 8ec1160 commit bb9ffe7
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 46 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ Features
--------

- Compatible with composer.
- Support update webhook for GitHub, Bitbucket and GitLab.
- Customers user and groups.
- Limit access by vendor and versions.
- Expire access time for user.
- Expire access for user.
- Allow to freeze updates for the new releases after expire a customers license.
- Mirroring for packages' zip files and downloads its from your host.
- Allow to add ssh keys from UI and use multiple SSH Keys settings for different github/git accounts.

What was changed in this fork?
-----------------------------
- Disable anonymously access, registrations, added groups and permissions.
- Support MySQL and PostgresSQL.
- Support Symfony 3.4
- Removed HWIOBundle, NelmioCorsBundle, NelmioSecurityBundle, Algolia, GoogleAnalytics dependencies.
- Removed HWIOBundle, Algolia, GoogleAnalytics and other not used dependencies.

Demo
-------
Expand Down
7 changes: 6 additions & 1 deletion src/Packagist/WebBundle/Controller/ProviderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,17 @@ public function providersAction($hash)
public function packageAction($package)
{
$package = \explode('$', $package);
$manager = $this->container->get('packagist.package_manager');
if (\count($package) !== 2) {
$package = $manager->getPackageJson($this->getUser(), $package[0]);
if ($package) {
return new Response(\json_encode($package), 200, ['Content-Type' => 'application/json']);
}
return $this->createNotFound();
}

$manager = $this->container->get('packagist.package_manager');
$package = $manager->getPackageJson($this->getUser(), $package[0], $package[1]);
$package = $manager->getCachedPackageJson($this->getUser(), $package[0], $package[1]);
if (!$package) {
return $this->createNotFound();
}
Expand Down
30 changes: 30 additions & 0 deletions src/Packagist/WebBundle/Entity/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ class User extends BaseUser
protected $groups;

/**
* @var Package[]
*
* @ORM\ManyToMany(targetEntity="Package", mappedBy="maintainers")
*/
private $packages;

/**
* @var Author[]
*
* @ORM\OneToMany(targetEntity="Packagist\WebBundle\Entity\Author", mappedBy="owner")
*/
private $authors;
Expand Down Expand Up @@ -121,6 +125,14 @@ class User extends BaseUser
*/
private $expiresAt;

/**
* Disable to updates a new release after this date expired
*
* @ORM\Column(name="expired_updates_at", type="date", nullable=true)
* @var \DateTime
*/
private $expiredUpdatesAt;

public function __construct()
{
$this->packages = new ArrayCollection();
Expand Down Expand Up @@ -366,4 +378,22 @@ public function isAdmin()
{
return $this->hasRole('ROLE_ADMIN') || $this->isSuperAdmin();
}

/**
* @return \DateTime|null
*/
public function getExpiredUpdatesAt()
{
return $this->expiredUpdatesAt;
}

/**
* @param \DateTime $expiredUpdatesAt
* @return $this
*/
public function setExpiredUpdatesAt($expiredUpdatesAt)
{
$this->expiredUpdatesAt = $expiredUpdatesAt;
return $this;
}
}
40 changes: 40 additions & 0 deletions src/Packagist/WebBundle/Form/Extension/TooltipExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Packagist\WebBundle\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TooltipExtension extends AbstractTypeExtension
{
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefined('tooltip');
}

/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
if (isset($options['tooltip'])) {
$view->vars['tooltip'] = $options['tooltip'];
}
}

/**
* {@inheritdoc}
*/
public function getExtendedType()
{
return FormType::class;
}
}
3 changes: 2 additions & 1 deletion src/Packagist/WebBundle/Form/Type/CredentialType.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public function configureOptions(OptionsResolver $resolver)
return $credentials->getName() . ($credentials->getFingerprint() ?
(' (' . $credentials->getFingerprint() . ')') : '');
},
'label' => 'SSH Credentials (optional, uses for Git to set GIT_SSH_COMMAND)',
'label' => 'SSH Credentials',
'tooltip' => 'Optional, support only for Git 2.3+, to use other IdentityFile from env. GIT_SSH_COMMAND. By default will be used system ssh key',
'required' => false,
]);
}
Expand Down
9 changes: 7 additions & 2 deletions src/Packagist/WebBundle/Form/Type/CustomerUserType.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
])
->add('expiresAt', DateType::class, [
'required' => false,
'attr' => ['class' => 'js-datepicker'],
'widget' => 'single_text',
'label' => 'Access expiration date'
'label' => 'Access expiration date',
])
->add('expiredUpdatesAt', DateType::class, [
'required' => false,
'widget' => 'single_text',
'label' => 'Update expiration',
'tooltip' => 'A new release updates will be frozen after this date. But the user can uses the versions released before'
])
->add('groups', EntityType::class, [
'choice_label' => 'name',
Expand Down
30 changes: 20 additions & 10 deletions src/Packagist/WebBundle/Model/PackageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Packagist\WebBundle\Model;

use Doctrine\Common\Cache\ApcuCache;
use Doctrine\Common\Cache\Cache;
use Packagist\WebBundle\Composer\PackagistFactory;
use Packagist\WebBundle\Entity\User;
Expand Down Expand Up @@ -39,7 +38,7 @@ public function __construct(
InMemoryDumper $dumper,
AuthorizationCheckerInterface $authorizationChecker,
PackagistFactory $packagistFactory,
Cache $cache = null
Cache $cache
) {
$this->doctrine = $doctrine;
$this->mailer = $mailer;
Expand All @@ -50,10 +49,6 @@ public function __construct(
$this->authorizationChecker = $authorizationChecker;
$this->dumper = $dumper;
$this->packagistFactory = $packagistFactory;
if ($cache === null) {
$cache = new ApcuCache();
$cache->setNamespace('package_manager');
}
$this->cache = $cache;
}

Expand Down Expand Up @@ -196,14 +191,29 @@ public function getProvidersJson(?User $user, $hash)
return $providers;
}

/**
* @param null|User|object $user
* @param string $package
*
* @return array
*/
public function getPackageJson(?User $user, string $package)
{
if ($user && $this->authorizationChecker->isGranted('ROLE_ADMIN')) {
$user = null;
}

return $this->dumper->dumpPackage($user, $package);
}

/**
* @param User|null|object $user
* @param string $package
* @param string $hash
*
* @return mixed
*/
public function getPackageJson(?User $user, string $package, string $hash)
public function getCachedPackageJson(?User $user, string $package, string $hash)
{
list($root, $providers, $packages) = $this->dumpInMemory($user);

Expand All @@ -216,19 +226,19 @@ public function getPackageJson(?User $user, string $package, string $hash)
return $packages[$package];
}

private function dumpInMemory(User $user = null, $cache = true)
private function dumpInMemory(User $user = null, bool $cache = true)
{
if ($user && $this->authorizationChecker->isGranted('ROLE_ADMIN')) {
$user = null;
}

$cacheKey = (string) ($user ? $user->getId() : 0);
$cacheKey = 'user_' . ($user ? $user->getId() : 0);
if ($cache && $this->cache->contains($cacheKey)) {
return $this->cache->fetch($cacheKey);
}

$data = $this->dumper->dump($user);
$this->cache->save($cacheKey, $data, 120);
$this->cache->save($cacheKey, $data, 600);
return $data;
}
}
88 changes: 59 additions & 29 deletions src/Packagist/WebBundle/Package/InMemoryDumper.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<?php

declare(strict_types=1);

namespace Packagist\WebBundle\Package;

use Doctrine\Persistence\ManagerRegistry;
use Packagist\WebBundle\Entity\Group;
use Packagist\WebBundle\Entity\Package;
use Packagist\WebBundle\Entity\User;
use Packagist\WebBundle\Entity\Version;
use Packagist\WebBundle\Security\Acl\PackagesAclChecker;
Expand All @@ -21,11 +25,57 @@ public function __construct(ManagerRegistry $registry, PackagesAclChecker $check
$this->checker = $checker;
}

public function dump(User $user = null)
/**
* @param User|null $user
* @return array
*/
public function dump(User $user = null): array
{
return $this->dumpRootPackages($user);
}

/**
* @param null|User $user
* @param string|Package $package
*
* @return array
*/
public function dumpPackage(?User $user, $package): array
{
if (is_string($package)) {
$package = $this->registry
->getRepository(Package::class)
->findOneBy(['name' => $package]);
}

if (!$package instanceof Package) {
return [];
}

if ($user !== null && $this->checker->isGrantedAccessForPackage($user, $package) === false) {
return [];
}

$versionIds = $packageData = [];
/** @var Version $version */
foreach ($package->getVersions() as $version) {
if ($user === null || $this->checker->isGrantedAccessForVersion($user, $version)) {
$versionIds[$version->getId()] = $version;
}
}

$versionRepo = $this->registry->getRepository(Version::class);
$versionData = $versionRepo->getVersionData(\array_keys($versionIds));
foreach ($versionIds as $version) {
$packageData[$version->getVersion()] = \array_merge(
$version->toArray($versionData),
['uid' => $version->getId()]
);
}

return $packageData;
}

private function dumpRootPackages(User $user = null)
{
list($providers, $packagesData) = $this->dumpUserPackages($user);
Expand All @@ -46,41 +96,21 @@ private function dumpRootPackages(User $user = null)
return [$rootFile, $providers, $packagesData];
}

private function dumpUserPackages(User $user = null)
private function dumpUserPackages(User $user = null): array
{
$packages = $user ? $this->registry->getRepository('PackagistWebBundle:Group')->getAllowedPackagesForUser($user) :
$this->registry->getRepository('PackagistWebBundle:Package')->findAll();
$packages = $user ?
$this->registry->getRepository(Group::class)
->getAllowedPackagesForUser($user) :
$this->registry->getRepository(Package::class)->findAll();

$versionRepo = $this->registry->getRepository('PackagistWebBundle:Version');

$providers = [];
$packagesData = [];
$providers = $packagesData = $packagesData = [];
foreach ($packages as $package) {
if ($user !== null && $this->checker->isGrantedAccessForPackage($user, $package) === false) {
if (!$packageData = $this->dumpPackage($user, $package)) {
continue;
}

/** @var Version[] $versionIds */
$versionIds = [];
$packageData = [];
foreach ($package->getVersions() as $version) {
if ($user === null || $this->checker->isGrantedAccessForVersion($user, $version)) {
$versionIds[$version->getId()] = $version;
}
}

$versionData = $versionRepo->getVersionData(\array_keys($versionIds));
foreach ($versionIds as $version) {
$packageData[$version->getVersion()] = \array_merge(
$version->toArray($versionData),
['uid' => $version->getId()]
);
}

$packageData = [
'packages' => [
$package->getName() => $packageData
]
'packages' => [$package->getName() => $packageData]
];
$packagesData[$package->getName()] = $packageData;
$providers[$package->getName()] = [
Expand Down
11 changes: 11 additions & 0 deletions src/Packagist/WebBundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ services:
- '@packagist.in_memory_dumper'
- '@security.authorization_checker'
- '@packagist_factory'
- '@packagist_cache'

Packagist\WebBundle\Model\PackageManager:
alias: packagist.package_manager
Expand Down Expand Up @@ -231,3 +232,13 @@ services:
- '@fos_user.user_manager'
tags:
- { name: console.command }

# Form extensions
Packagist\WebBundle\Form\Extension\TooltipExtension:
tags:
- { name: form.type_extension, extended_type: 'Symfony\Component\Form\Extension\Core\Type\FormType' }

packagist_cache:
parent: doctrine_cache.abstract.file_system
arguments:
- '%kernel.cache_dir%/packagist'
2 changes: 2 additions & 0 deletions src/Packagist/WebBundle/Resources/public/js/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@
scrollTo(0, $($(e.target).attr('href')).offset().top - 65);
}, 0);
});

$('[data-toggle="popover"]').popover();
})(jQuery, humane);
Loading

0 comments on commit bb9ffe7

Please sign in to comment.