Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions resources/views/module_update.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ use Jefferson49\Webtrees\Module\CustomModuleManager\RequestHandlers\ReleaseNotes
null,
null,
null,
['type' => 'num', 'searchable' => false],
['type' => 'html', 'searchable' => false],
['type' => 'html', 'searchable' => false],
['type' => 'html', 'searchable' => false],
Expand All @@ -96,6 +97,7 @@ use Jefferson49\Webtrees\Module\CustomModuleManager\RequestHandlers\ReleaseNotes
<th><?= I18N::translate('Current Version') ?></th>
<th><?= I18N::translate('Latest Version') ?></th>
<th><?= I18N::translate('Update Service') ?></th>
<th><?= I18N::translate('Downloads') ?></th>
<th><?= MoreI18N::xlate('Enabled') ?></th>
<th><?= I18N::translate('Install') ?></th>
<th><?= MoreI18N::xlate('Delete') ?></th>
Expand Down Expand Up @@ -240,6 +242,12 @@ use Jefferson49\Webtrees\Module\CustomModuleManager\RequestHandlers\ReleaseNotes
<?= $module_update_service_name ?>
</td>

<!--Downloads -->
<?php $download_count = ($module_update_service instanceof GithubModuleUpdate) ? $module_update_service->getDownloadCount() : -1 ?>
<td data-sort="<?= $download_count ?>">
<?= $download_count >= 0 ? number_format($download_count) : I18N::translate('N/A') ?>
</td>

<!-- Enabled -->
<td data-sort="<?= $module_status ?>">
<?php if ($module !== null) : ?>
Expand Down
2 changes: 2 additions & 0 deletions src/CustomModuleManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class CustomModuleManager extends AbstractModule implements
public const PREF_SHOW_MENU_LIST_ITEM = 'show_menu_list_item';
public const PREF_LATEST_VERSION = 'latest';
public const PREF_IGNORE_VERSION = 'ignore';
public const PREF_DOWNLOAD_COUNT = 'dl';
public const PREF_DOWNLOAD_COUNT_TIME = 'dl_t';

//Configuraton
public const CONFIG_GITHUB_BRANCH = 'config';
Expand Down
52 changes: 52 additions & 0 deletions src/ModuleUpdates/GithubModuleUpdate.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,58 @@ public function providesReleasesInRepository(): bool {
return !$this->no_release;
}

/**
* Get the cached download count for this module.
*
* Fetches the maximum download count across the latest 3 releases' assets.
* The result is cached for 24 hours using module preferences to avoid hitting
* GitHub API rate limits on every page load.
*
* @return int The download count, or -1 if unavailable
*/
public function getDownloadCount(): int
{
$short_module_name = substr($this->module_name, 0, 25) . '_';
$cache_key = $short_module_name . CustomModuleManager::PREF_DOWNLOAD_COUNT;
$cache_time_key = $short_module_name . CustomModuleManager::PREF_DOWNLOAD_COUNT_TIME;

// Check if we have a cached value that is less than 24 hours old
$cached_time = (int) $this->custom_module_manager->getPreference($cache_time_key, '0');
$cached_count = $this->custom_module_manager->getPreference($cache_key, '');

if ($cached_count !== '' && (time() - $cached_time) < 86400) {
return (int) $cached_count;
}

// If the module does not provide releases, we cannot get download counts
if ($this->no_release) {
return -1;
}

$github_api_token = $this->custom_module_manager->getPreference(CustomModuleManager::PREF_GITHUB_API_TOKEN, '');

try {
$download_count = GithubService::getRecentReleasesMaxDownloads($this->github_repo, $github_api_token);

// Cache the result
$this->custom_module_manager->setPreference($cache_key, (string) $download_count);
$this->custom_module_manager->setPreference($cache_time_key, (string) time());

return $download_count;
} catch (GithubCommunicationError $ex) {
// If we have a stale cached value, return it rather than nothing
if ($cached_count !== '') {
return (int) $cached_count;
}

if (!CustomModuleManager::rememberGithubCommunciationError()) {
FlashMessages::addMessage(I18N::translate('Communication error with %s', self::NAME), 'danger');
}

return -1;
}
}

/**
* Get the latest release URL
*
Expand Down