Skip to content

Commit

Permalink
Merge branch 'master' of github.com:szepeviktor/composer-envato
Browse files Browse the repository at this point in the history
  • Loading branch information
szepeviktor committed Mar 16, 2023
2 parents d3d1448 + abea32d commit 453e010
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 27 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Viktor Szépe

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"szepeviktor/composer-theme-fusion": "Composer plugin for ThemeFusion"
},
"extra": {
"class": "SzepeViktor\\Composer\\Envato\\EnvatoPlugin"
"class": "SzepeViktor\\Composer\\Envato\\EnvatoPlugin",
"plugin-modifies-downloads": true
},
"autoload": {
"psr-4": {
Expand Down
71 changes: 59 additions & 12 deletions src/EnvatoApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public function __construct(IOInterface $io, Config $config, string $token)
$this->token = $token;
}

/**
* Query the Envato API for the item's current version.
*
* @return non-empty-string
*/
public function getVersion(int $itemId): string
{
$response = $this->httpDownloader->get(
Expand All @@ -41,11 +46,14 @@ public function getVersion(int $itemId): string
if ($response->getStatusCode() === 200) {
$versionData = \json_decode($response->getBody() ?? '', true);
// TODO Check JSON
if (is_array($versionData) && \array_key_exists('wordpress_theme_latest_version', $versionData)) {
return $versionData['wordpress_theme_latest_version'];
}
if (is_array($versionData) && \array_key_exists('wordpress_plugin_latest_version', $versionData)) {
return $versionData['wordpress_plugin_latest_version'];
if (\is_array($versionData)) {
if (\array_key_exists('wordpress_theme_latest_version', $versionData)) {
return $versionData['wordpress_theme_latest_version'];
}

if (\array_key_exists('wordpress_plugin_latest_version', $versionData)) {
return $versionData['wordpress_plugin_latest_version'];
}
}
}

Expand All @@ -54,24 +62,63 @@ public function getVersion(int $itemId): string
}

/**
* Return the Envato API URL to retrieve the item's download URL.
*
* @param int $itemId The item ID to lookup.
* @param string|null $version Optional version to append to the URL.
* This is used to by the plugin for the download's cache key in Composer.
* @return non-empty-string
*/
public function getDownloadRequestUrl(int $itemId, ?string $version = null): string
{
$query = ['item_id' => $itemId];

if ($version !== null) {
$query['version'] = $version;
}

return self::API_BASE_URL . '/market/buyer/download?' . \http_build_query($query);
}

/**
* Query the Envato API to retrieve the item's download URL.
*
* @param int|string $itemIdOrApiUrl The item ID to lookup or the API URL to query.
* @return non-empty-string|null
*/
public function getDownloadUrl(int $itemId): ?string
public function getDownloadUrl($itemIdOrApiUrl): ?string
{
if (
\is_int($itemIdOrApiUrl) &&
$itemIdOrApiUrl > 0
) {
$apiUrl = $this->getDownloadRequestUrl($itemIdOrApiUrl);
} elseif (
\is_string($itemIdOrApiUrl) &&
\strpos($itemIdOrApiUrl, self::API_BASE_URL . '/market/buyer/download') !== false
) {
$apiUrl = $itemIdOrApiUrl;
} else {
return null;
}

$response = $this->httpDownloader->get(
self::API_BASE_URL . '/market/buyer/download?' . \http_build_query(['item_id' => $itemId]),
$apiUrl,
['http' => ['header' => ['Authorization: Bearer ' . $this->token]]]
);

// TODO HTTP 429 response. Included in this response is a HTTP header Retry-After
if ($response->getStatusCode() === 200) {
$urlData = \json_decode($response->getBody() ?? '', true);
// TODO Check JSON
if (is_array($urlData) && \array_key_exists('wordpress_theme', $urlData)) {
return $urlData['wordpress_theme'];
}
if (is_array($urlData) && \array_key_exists('wordpress_plugin', $urlData)) {
return $urlData['wordpress_plugin'];
if (\is_array($urlData)) {
if (\array_key_exists('wordpress_theme', $urlData)) {
return $urlData['wordpress_theme'];
}

if (\array_key_exists('wordpress_plugin', $urlData)) {
return $urlData['wordpress_plugin'];
}
}
}

Expand Down
11 changes: 7 additions & 4 deletions src/EnvatoConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class EnvatoConfig
public const ENV_VAR_TOKEN = 'ENVATO_TOKEN';

/**
* @var array<mixed>
* @var array{token?:string, packages?:array{item-id:int|string|null, type:string|null}}
*/
protected $config;

Expand All @@ -40,6 +40,9 @@ public function __construct(Config $composerConfig)
;
}

/**
* @phpstan-assert-if-true !array{} $this->config
*/
public function isValid(): bool
{
return $this->valid;
Expand All @@ -60,9 +63,9 @@ public function getPackageList(): array
return \array_map(
static function ($name, $data) {
return [
'name' => (string)$name,
'itemId' => $data['item-id'] ?? 0,
'type' => $data['type'] ?? 'wordpress-theme',
'name' => (string)$name,
'itemId' => (int)($data['item-id'] ?? 0),
'type' => (string)($data['type'] ?? 'wordpress-theme'),
];
},
\array_keys($this->config['packages']),
Expand Down
27 changes: 18 additions & 9 deletions src/EnvatoPackage.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ public function getVersion(): string
return $this->version;
}

// Query Envato API
$this->prettyVersion = $this->api->getVersion($this->itemId);
$versionParser = new VersionParser();
$this->version = $versionParser->normalize($this->prettyVersion);
$this->processItemVersion();

return $this->version;
}
Expand All @@ -68,10 +65,7 @@ public function getPrettyVersion(): string
return $this->prettyVersion;
}

// Query Envato API
$this->prettyVersion = $this->api->getVersion($this->itemId);
$versionParser = new VersionParser();
$this->version = $versionParser->normalize($this->prettyVersion);
$this->processItemVersion();

return $this->prettyVersion;
}
Expand All @@ -93,7 +87,11 @@ public function getDistUrl(): ?string
return $this->distUrl;
}

$this->distUrl = $this->api->getDownloadUrl($this->itemId);
/**
* Use the Envato API URL to retrieve the item's download URL
* as the package's dist URL to serve as its cache key.
*/
$this->distUrl = $this->api->getDownloadRequestUrl($this->itemId, $this->getPrettyVersion());

return $this->distUrl;
}
Expand All @@ -105,4 +103,15 @@ public function isAbandoned()
{
return false;
}

/**
* Retrieve the item's version from the Envato API.
*/
protected function processItemVersion(): void
{
// Query Envato API
$this->prettyVersion = $this->api->getVersion($this->itemId);
$versionParser = new VersionParser();
$this->version = $versionParser->normalize($this->prettyVersion);
}
}
39 changes: 38 additions & 1 deletion src/EnvatoPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
namespace SzepeViktor\Composer\Envato;

use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PluginInterface;
use Composer\Plugin\PreFileDownloadEvent;
use Composer\Repository\ArrayRepository;

/**
* Composer Plugin for Envato Marketplace.
*/
class EnvatoPlugin implements PluginInterface
class EnvatoPlugin implements PluginInterface, EventSubscriberInterface
{
/**
* @var Composer
Expand Down Expand Up @@ -63,6 +66,16 @@ public function uninstall(Composer $composer, IOInterface $io)
{
}

/**
* @return array<key-of<PluginEvents::*>, (string|array{string, int})>
*/
public static function getSubscribedEvents()
{
return [
PluginEvents::PRE_FILE_DOWNLOAD => [ 'handlePreDownloadEvent', -1 ],
];
}

protected function generateRepository(): ArrayRepository
{
$api = $this->api;
Expand All @@ -81,4 +94,28 @@ static function ($packageConfig) use ($api) {
$this->config->getPackageList()
));
}

/**
* Retrieve the item's download URL from the Envato API
* and use the item's dist URL as the cache key.
*/
public function handlePreDownloadEvent(PreFileDownloadEvent $event): void
{
if (! $this->config->isValid() || $event->getType() !== 'package') {
return;
}

$processedUrl = $event->getProcessedUrl();
$downloadUrl = $this->api->getDownloadUrl($processedUrl);

// Submit changes to Composer, if any
if (
\is_string($downloadUrl) &&
$downloadUrl !== '' &&
$downloadUrl !== $processedUrl
) {
$event->setProcessedUrl($downloadUrl);
$event->setCustomCacheKey($processedUrl);
}
}
}

0 comments on commit 453e010

Please sign in to comment.