mirror of
https://github.com/danielbrendel/hortusfox-web.git
synced 2026-05-02 03:39:51 -05:00
#120 Theme import
This commit is contained in:
@@ -91,6 +91,7 @@ return [
|
||||
array('/admin/media/background', 'POST', 'admin@upload_media_background'),
|
||||
array('/admin/media/overlay/alpha', 'POST', 'admin@save_overlay_alpha'),
|
||||
array('/admin/mail/save', 'POST', 'admin@save_mail_settings'),
|
||||
array('/admin/themes/import', 'POST', 'admin@import_theme'),
|
||||
array('/admin/cronjob/token', 'POST', 'admin@generate_cronjob_token'),
|
||||
|
||||
/** Cronjob Controller */
|
||||
|
||||
@@ -405,4 +405,27 @@ class AdminController extends BaseController {
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles URL: /admin/themes/import
|
||||
*
|
||||
* @param Asatru\Controller\ControllerArg $request
|
||||
* @return Asatru\View\JsonHandler
|
||||
*/
|
||||
public function import_theme($request)
|
||||
{
|
||||
try {
|
||||
$themes = ThemeModule::startImport();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'themes' => $themes
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -266,5 +266,7 @@ return [
|
||||
'all_in_good_standing' => 'Alles Ok',
|
||||
'theme' => 'Theme',
|
||||
'themes' => 'Themes',
|
||||
'confirm_generate_new_token' => 'Soll ein neues Token erstellt werden? Das vorherige Token wird dadurch ungültig.'
|
||||
'confirm_generate_new_token' => 'Soll ein neues Token erstellt werden? Das vorherige Token wird dadurch ungültig.',
|
||||
'themes_hint' => 'Hier können neue Themes importiert werden. Wähle das ZIP-Archiv mit deinem Theme aus und sobald der Import erfolgreich war, ist das Theme dann für alle im Arbeitsraum verfügbar. Hinweis: Falls das ZIP-Archiv mehrere Themes enthält, wird das System versuchen, alle zu importieren.',
|
||||
'theme_import_successful' => 'Der Import war erfolgreich. Importierte Themes: {count}'
|
||||
];
|
||||
+3
-1
@@ -266,5 +266,7 @@ return [
|
||||
'all_in_good_standing' => 'All fine',
|
||||
'theme' => 'Theme',
|
||||
'themes' => 'Themes',
|
||||
'confirm_generate_new_token' => 'Generating a new token will invalidate the previous one. Do you want to proceed?'
|
||||
'confirm_generate_new_token' => 'Generating a new token will invalidate the previous one. Do you want to proceed?',
|
||||
'themes_hint' => 'Here you can import themes. Select a zip-file of your theme you want to import and once import succeeded, the theme will be available to all users. Note: If the zip-archive contains multiple themes, then the system will try to import all of them.',
|
||||
'theme_import_successful' => 'The import was successful. Imported themes: {count}'
|
||||
];
|
||||
@@ -119,4 +119,54 @@ class ThemeModule {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function startImport()
|
||||
{
|
||||
try {
|
||||
if ((!isset($_FILES['theme'])) || ($_FILES['theme']['error'] !== UPLOAD_ERR_OK) || (strpos($_FILES['theme']['type'], 'zip') === false)) {
|
||||
throw new \Exception('Failed to upload file or invalid file uploaded');
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$import_file = 'theme_import_' . date('Y-m-d_H-i-s');
|
||||
|
||||
move_uploaded_file($_FILES['theme']['tmp_name'], public_path() . '/themes/' . $import_file . '.zip');
|
||||
|
||||
$zip = new ZipArchive();
|
||||
|
||||
if ($zip->open(public_path() . '/themes/' . $import_file . '.zip')) {
|
||||
$zip->extractTo(public_path() . '/themes/' . $import_file);
|
||||
$zip->close();
|
||||
|
||||
$folders = scandir(public_path() . '/themes/' . $import_file);
|
||||
foreach ($folders as $folder) {
|
||||
if (substr($folder, 0, 1) !== '.') {
|
||||
if (!is_dir(public_path() . '/themes/' . $folder)) {
|
||||
rename(public_path() . '/themes/' . $import_file . '/' . $folder, public_path() . '/themes/' . $folder);
|
||||
|
||||
static::load(public_path() . '/themes/' . $folder);
|
||||
if (!static::ready()) {
|
||||
throw new \Exception('Failed to load theme: ' . $folder);
|
||||
}
|
||||
|
||||
$result[] = $folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UtilsModule::clearFolder(public_path() . '/themes/' . $import_file);
|
||||
}
|
||||
|
||||
unlink(public_path() . '/themes/' . $import_file . '.zip');
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-1
@@ -669,7 +669,7 @@ window.vue = new Vue({
|
||||
},
|
||||
|
||||
selectAdminTab: function(tab) {
|
||||
const tabs = ['environment', 'media', 'users', 'locations', 'mail', 'backup', 'info'];
|
||||
const tabs = ['environment', 'media', 'users', 'locations', 'mail', 'themes', 'backup', 'info'];
|
||||
|
||||
let selEl = document.querySelector('.admin-' + tab);
|
||||
if (selEl) {
|
||||
@@ -804,6 +804,26 @@ window.vue = new Vue({
|
||||
});
|
||||
},
|
||||
|
||||
startThemeImport: function(file, button) {
|
||||
let oldText = button.innerHTML;
|
||||
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> ' + oldText;
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('theme', file.files[0]);
|
||||
|
||||
window.vue.ajaxRequest('post', window.location.origin + '/admin/themes/import', formData, function(response) {
|
||||
button.innerHTML = oldText;
|
||||
|
||||
if (response.code == 200) {
|
||||
let import_result = document.getElementById('themes-import-result');
|
||||
if (import_result) {
|
||||
import_result.innerText = import_result.innerText.replace('{count}', response.themes.length);
|
||||
import_result.classList.remove('is-hidden');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
copyToClipboard: function(text) {
|
||||
const el = document.createElement('textarea');
|
||||
el.value = text;
|
||||
|
||||
@@ -2027,6 +2027,29 @@ fieldset .field {
|
||||
background-color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
.admin-themes p {
|
||||
color: rgb(150, 150, 150);
|
||||
margin-bottom: 30px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.admin-themes input, .admin-themes select {
|
||||
color: rgb(150, 150, 150);
|
||||
background-color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
.admin-themes-result {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid rgb(255, 255, 255);
|
||||
background-color: rgb(185, 255, 164);
|
||||
}
|
||||
|
||||
.admin-themes-result i {
|
||||
color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
.admin-backup label, .admin-backup span {
|
||||
color: rgb(150, 150, 150);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<li class="admin-tab-users {{ ((isset($_GET['tab'])) && ($_GET['tab'] === 'users')) ? 'is-active' : ''}}"><a href="javascript:void(0);" onclick="window.vue.selectAdminTab('users');">{{ __('app.users') }}</a></li>
|
||||
<li class="admin-tab-locations {{ ((isset($_GET['tab'])) && ($_GET['tab'] === 'locations')) ? 'is-active' : ''}}"><a href="javascript:void(0);" onclick="window.vue.selectAdminTab('locations');">{{ __('app.locations') }}</a></li>
|
||||
<li class="admin-tab-mail {{ ((isset($_GET['tab'])) && ($_GET['tab'] === 'mail')) ? 'is-active' : ''}}"><a href="javascript:void(0);" onclick="window.vue.selectAdminTab('mail');">{{ __('app.mail') }}</a></li>
|
||||
<li class="admin-tab-themes {{ ((isset($_GET['tab'])) && ($_GET['tab'] === 'themes')) ? 'is-active' : ''}}"><a href="javascript:void(0);" onclick="window.vue.selectAdminTab('themes');">{{ __('app.themes') }}</a></li>
|
||||
<li class="admin-tab-backup {{ ((isset($_GET['tab'])) && ($_GET['tab'] === 'backup')) ? 'is-active' : ''}}"><a href="javascript:void(0);" onclick="window.vue.selectAdminTab('backup');">{{ __('app.backup') }}</a></li>
|
||||
<li class="admin-tab-info {{ ((isset($_GET['tab'])) && ($_GET['tab'] === 'info')) ? 'is-active' : ''}}">
|
||||
<a href="javascript:void(0);" onclick="window.vue.selectAdminTab('info');">
|
||||
@@ -346,6 +347,26 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="admin-themes {{ ((!isset($_GET['tab'])) || ($_GET['tab'] !== 'themes')) ? 'is-hidden' : ''}}">
|
||||
<h2>{{ __('app.themes') }}</h2>
|
||||
|
||||
<p>{{ __('app.themes_hint') }}</p>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input type="file" class="input" id="theme_import_file" accept=".zip"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button type="button" class="button is-link" onclick="window.vue.startThemeImport(document.getElementById('theme_import_file'), this);">{{ __('app.import') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-themes-result is-hidden" id="themes-import-result">{{ __('app.theme_import_successful') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-backup {{ ((!isset($_GET['tab'])) || ($_GET['tab'] !== 'backup')) ? 'is-hidden' : ''}}">
|
||||
<h2>{{ __('app.export') }}</h2>
|
||||
|
||||
|
||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user