Skip to content
Merged
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
30 changes: 30 additions & 0 deletions install.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* GitHub Installer - Installation
*
* Erstellt die Datenbank-Tabelle fΓΌr GitHub-Cache
*/

// Tabelle fΓΌr GitHub-Item-Cache erstellen
$table = rex_sql_table::get(rex::getTable('github_installer_items'));

$table
->addColumn(new rex_sql_column('id', 'int(10) unsigned', false, null, 'auto_increment'))
->addColumn(new rex_sql_column('item_type', 'varchar(50)', false))
->addColumn(new rex_sql_column('item_key', 'varchar(255)', false))
->addColumn(new rex_sql_column('item_name', 'varchar(255)', false))
->addColumn(new rex_sql_column('repo_owner', 'varchar(255)', false))
->addColumn(new rex_sql_column('repo_name', 'varchar(255)', false))
->addColumn(new rex_sql_column('repo_branch', 'varchar(255)', false, 'main'))
->addColumn(new rex_sql_column('repo_path', 'varchar(500)', false))
->addColumn(new rex_sql_column('installed_at', 'datetime', false))
->addColumn(new rex_sql_column('github_last_update', 'datetime', true))
->addColumn(new rex_sql_column('github_last_commit_sha', 'varchar(255)', true))
->addColumn(new rex_sql_column('github_last_commit_message', 'text', true))
->addColumn(new rex_sql_column('github_cache_updated_at', 'datetime', true))
->setPrimaryKey('id')
->addIndex(new rex_sql_index('unique_item', ['item_type', 'item_key'], rex_sql_index::UNIQUE))
->addIndex(new rex_sql_index('item_type', ['item_type']))
->addIndex(new rex_sql_index('repo_lookup', ['repo_owner', 'repo_name']))
->ensure();
14 changes: 9 additions & 5 deletions lang/de_de.lang
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,18 @@ modules_install = Installieren
modules_install_confirm = Modul "{0}" installieren?
modules_installed_success = Modul erfolgreich installiert
modules_install_error = Fehler beim Installieren des Moduls
modules_update = Neu laden
modules_update_confirm = Modul "{0}" neu laden?
modules_updated_success = Modul erfolgreich neu geladen
modules_update_error = Fehler beim Neu-Laden des Moduls
modules_update = Aktualisieren
modules_update_confirm = Modul "{0}" aktualisieren?
modules_reload = Neu laden
modules_updated_success = Modul erfolgreich aktualisiert
modules_update_error = Fehler beim Aktualisieren des Moduls
module_name = Name
module_title = Titel
module_description = Beschreibung
module_version = Version
module_author = Autor
module_key = Key
module_sync_status = Sync-Status
module_assets = Assets
module_assets_target = Ziel-Verzeichnis
module_actions = Aktionen
Expand Down Expand Up @@ -92,7 +94,8 @@ templates_install = Installieren
templates_install_confirm = Template "{0}" installieren?
templates_installed_success = Template erfolgreich installiert
templates_install_error = Fehler beim Installieren des Templates
templates_update = Neu laden
templates_update = Aktualisieren
templates_reload = Neu laden
templates_update_confirm = Template "{0}" neu laden?
templates_updated_success = Template erfolgreich neu geladen
templates_update_error = Fehler beim Neu-Laden des Templates
Expand All @@ -102,6 +105,7 @@ template_description = Beschreibung
template_version = Version
template_author = Autor
template_key = Key
template_sync_status = Sync-Status
template_assets = Assets
template_assets_target = Ziel-Verzeichnis
template_actions = Aktionen
Expand Down
12 changes: 10 additions & 2 deletions lang/en_gb.lang
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,18 @@ modules_install = Install
modules_install_confirm = Install module "{0}"?
modules_installed_success = Module installed successfully
modules_install_error = Error installing module
modules_update = Update
modules_update_confirm = Update module "{0}"?
modules_reload = Reload
modules_updated_success = Module updated successfully
modules_update_error = Error updating module
module_name = Name
module_title = Title
module_description = Description
module_version = Version
module_author = Author
module_key = Key
module_sync_status = Sync Status
module_assets = Assets
module_assets_target = Target Directory
module_actions = Actions
Expand Down Expand Up @@ -80,13 +86,14 @@ templates_title = Templates
templates_select_repo = Select Repository
templates_choose_repo = -- Choose Repository --
templates_no_repos = No repositories configured. Please add repositories first.
templates_loading = Loading templates...
templates_loading = Loading Templates...
templates_no_templates = No templates found in this repository
templates_install = Install
templates_install_confirm = Install template "{0}"?
templates_installed_success = Template installed successfully
templates_install_error = Error installing template
templates_update = Reload
templates_update = Update
templates_reload = Reload
templates_update_confirm = Reload template "{0}"?
templates_updated_success = Template successfully reloaded
templates_update_error = Error reloading template
Expand All @@ -96,6 +103,7 @@ template_description = Description
template_version = Version
template_author = Author
template_key = Key
template_sync_status = Sync Status
template_assets = Assets
template_assets_target = Target Directory
template_actions = Actions
Expand Down
32 changes: 32 additions & 0 deletions lib/GitHubApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,36 @@ public function uploadFile(string $owner, string $repo, string $path, string $co
{
return $this->createOrUpdateFile($owner, $repo, $path, $content, $message, $branch);
}

/**
* Letztes Commit-Datum fΓΌr eine Datei/Ordner abrufen
*
* @param string $owner Repository Owner
* @param string $repo Repository Name
* @param string $path Pfad zur Datei/Ordner
* @param string $branch Branch Name
* @return string|null Datum im Format 'Y-m-d H:i:s' oder null bei Fehler
*/
public function getLastCommitDate(string $owner, string $repo, string $path, string $branch = 'main'): ?string
{
try {
$endpoint = "repos/{$owner}/{$repo}/commits";
$endpoint .= "?path=" . urlencode($path);
$endpoint .= "&sha=" . urlencode($branch);
$endpoint .= "&per_page=1";

$commits = $this->makeRequest($endpoint);

if (!empty($commits) && isset($commits[0]['commit']['committer']['date'])) {
$githubDate = $commits[0]['commit']['committer']['date'];
// GitHub gibt ISO 8601 zurΓΌck: 2024-11-16T10:30:00Z
$timestamp = strtotime($githubDate);
return date('Y-m-d H:i:s', $timestamp);
}
} catch (\Exception $e) {
// Bei Fehler null zurΓΌckgeben
}

return null;
}
}
241 changes: 241 additions & 0 deletions lib/GitHubItemCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
<?php

namespace FriendsOfREDAXO\GitHubInstaller;

/**
* GitHub Item Cache Manager
*
* Verwaltet den Cache fΓΌr GitHub-Items (Module, Templates, Actions)
* um API-Anfragen zu minimieren
*/
class GitHubItemCache
{
private const CACHE_LIFETIME = 3600; // 1 Stunde Standard

/**
* Speichert oder aktualisiert GitHub-Item-Informationen
*
* @param string $itemType Type: 'module', 'template', 'action'
* @param string $itemKey REDAXO key field
* @param string $itemName Item name
* @param string $repoOwner GitHub owner
* @param string $repoName GitHub repository
* @param string $repoBranch Branch name
* @param string $repoPath Path in repository
* @param string|null $githubLastUpdate Last commit date (Y-m-d H:i:s)
* @param string|null $commitSha Commit SHA
* @param string|null $commitMessage Commit message
*/
public static function save(
string $itemType,
string $itemKey,
string $itemName,
string $repoOwner,
string $repoName,
string $repoBranch,
string $repoPath,
?string $githubLastUpdate = null,
?string $commitSha = null,
?string $commitMessage = null
): void {
$sql = \rex_sql::factory();
$sql->setTable(\rex::getTable('github_installer_items'));

// PrΓΌfen ob bereits vorhanden
$existing = self::get($itemType, $itemKey);

$sql->setValue('item_type', $itemType);
$sql->setValue('item_key', $itemKey);
$sql->setValue('item_name', $itemName);
$sql->setValue('repo_owner', $repoOwner);
$sql->setValue('repo_name', $repoName);
$sql->setValue('repo_branch', $repoBranch);
$sql->setValue('repo_path', $repoPath);

if ($githubLastUpdate) {
$sql->setValue('github_last_update', $githubLastUpdate);
}
if ($commitSha) {
$sql->setValue('github_last_commit_sha', $commitSha);
}
if ($commitMessage) {
$sql->setValue('github_last_commit_message', $commitMessage);
}

$sql->setValue('github_cache_updated_at', date('Y-m-d H:i:s'));

if ($existing) {
// Update
$sql->setWhere('id = :id', ['id' => $existing['id']]);
$sql->update();
} else {
// Insert
$sql->setValue('installed_at', date('Y-m-d H:i:s'));
$sql->insert();
}
}

/**
* Holt GitHub-Item-Informationen aus dem Cache
*
* @param string $itemType Type: 'module', 'template', 'action'
* @param string $itemKey REDAXO key field
* @return array|null Item data oder null wenn nicht gefunden
*/
public static function get(string $itemType, string $itemKey): ?array
{
$sql = \rex_sql::factory();
$sql->setQuery(
'SELECT * FROM ' . \rex::getTable('github_installer_items') . '
WHERE item_type = :type AND item_key = :key',
['type' => $itemType, 'key' => $itemKey]
);

if ($sql->getRows() > 0) {
return [
'id' => $sql->getValue('id'),
'item_type' => $sql->getValue('item_type'),
'item_key' => $sql->getValue('item_key'),
'item_name' => $sql->getValue('item_name'),
'repo_owner' => $sql->getValue('repo_owner'),
'repo_name' => $sql->getValue('repo_name'),
'repo_branch' => $sql->getValue('repo_branch'),
'repo_path' => $sql->getValue('repo_path'),
'installed_at' => $sql->getValue('installed_at'),
'github_last_update' => $sql->getValue('github_last_update'),
'github_last_commit_sha' => $sql->getValue('github_last_commit_sha'),
'github_last_commit_message' => $sql->getValue('github_last_commit_message'),
'github_cache_updated_at' => $sql->getValue('github_cache_updated_at'),
];
}

return null;
}

/**
* PrΓΌft ob der Cache fΓΌr ein Item noch gΓΌltig ist
*
* @param string $itemType Type: 'module', 'template', 'action'
* @param string $itemKey REDAXO key field
* @param int $cacheLifetime Cache-Lebensdauer in Sekunden
* @return bool True wenn Cache noch gΓΌltig
*/
public static function isCacheValid(string $itemType, string $itemKey, int $cacheLifetime = self::CACHE_LIFETIME): bool
{
$item = self::get($itemType, $itemKey);

if (!$item || !$item['github_cache_updated_at']) {
return false;
}

$cacheTime = strtotime($item['github_cache_updated_at']);
$now = time();

return ($now - $cacheTime) < $cacheLifetime;
}

/**
* Aktualisiert die GitHub-Informationen fΓΌr ein Item
*
* @param string $itemType Type: 'module', 'template', 'action'
* @param string $itemKey REDAXO key field
* @param GitHubApi $github GitHub API instance
* @return bool True wenn erfolgreich aktualisiert
*/
public static function refreshGitHubData(string $itemType, string $itemKey, GitHubApi $github): bool
{
$item = self::get($itemType, $itemKey);

if (!$item) {
return false;
}

try {
// Letztes Commit-Datum holen
$lastUpdate = $github->getLastCommitDate(
$item['repo_owner'],
$item['repo_name'],
$item['repo_path'],
$item['repo_branch']
);

if ($lastUpdate) {
$sql = \rex_sql::factory();
$sql->setTable(\rex::getTable('github_installer_items'));
$sql->setValue('github_last_update', $lastUpdate);
$sql->setValue('github_cache_updated_at', date('Y-m-d H:i:s'));
$sql->setWhere('id = :id', ['id' => $item['id']]);
$sql->update();

return true;
}
} catch (\Exception $e) {
error_log("GitHub Cache Refresh Error: " . $e->getMessage());
}

return false;
}

/**
* LΓΆscht einen Cache-Eintrag
*
* @param string $itemType Type: 'module', 'template', 'action'
* @param string $itemKey REDAXO key field
*/
public static function delete(string $itemType, string $itemKey): void
{
$sql = \rex_sql::factory();
$sql->setQuery(
'DELETE FROM ' . \rex::getTable('github_installer_items') . '
WHERE item_type = :type AND item_key = :key',
['type' => $itemType, 'key' => $itemKey]
);
}

/**
* Holt alle Items eines bestimmten Typs
*
* @param string $itemType Type: 'module', 'template', 'action'
* @return array Liste von Items
*/
public static function getAllByType(string $itemType): array
{
$sql = \rex_sql::factory();
$sql->setQuery(
'SELECT * FROM ' . \rex::getTable('github_installer_items') . '
WHERE item_type = :type',
['type' => $itemType]
);

$items = [];
while ($sql->hasNext()) {
$items[] = [
'id' => $sql->getValue('id'),
'item_type' => $sql->getValue('item_type'),
'item_key' => $sql->getValue('item_key'),
'item_name' => $sql->getValue('item_name'),
'repo_owner' => $sql->getValue('repo_owner'),
'repo_name' => $sql->getValue('repo_name'),
'repo_branch' => $sql->getValue('repo_branch'),
'repo_path' => $sql->getValue('repo_path'),
'installed_at' => $sql->getValue('installed_at'),
'github_last_update' => $sql->getValue('github_last_update'),
'github_last_commit_sha' => $sql->getValue('github_last_commit_sha'),
'github_last_commit_message' => $sql->getValue('github_last_commit_message'),
'github_cache_updated_at' => $sql->getValue('github_cache_updated_at'),
];
$sql->next();
}

return $items;
}

/**
* Leert den gesamten Cache
*/
public static function clearAll(): void
{
$sql = \rex_sql::factory();
$sql->setQuery('TRUNCATE TABLE ' . \rex::getTable('github_installer_items'));
}
}
Loading
Loading