namespace App\Console\Commands;
+use App\Models\Traits\FluidbookPlayerBranches;
use Cubist\Backpack\Console\Commands\CubistCommand;
use Cubist\Util\CommandLine\Git;
use Cubist\Util\Files\Files;
protected $signature = 'fluidbook:player:updatesources';
protected $description = 'Update fluidbook player sources from git repos';
- protected function executeGitCommands($dir, $commands)
- {
- if (!is_array($commands)) {
- $commands = [$commands];
- }
- $res = [];
- foreach ($commands as $command) {
- $res[] = $this->executeGitCommand($dir, $command);
- }
- return $res;
- }
-
- protected function executeGitCommand($dir, $command)
- {
- $git = new Git($dir);
- $output = $git->executeCmd($command);
-
- $this->line('<fg=blue>' . $git->getCommand() . '</>');
- $this->line($output);
- return $output;
- }
+ use FluidbookPlayerBranches;
public function handle()
{
PHP::neverStop(true);
-
- $playerDir = Files::mkdir(resource_path('fluidbookpublication/player')) . '/';
- $branchesDir = Files::mkdir($playerDir . 'branches/');
- $localDir = Files::mkdir($playerDir . 'local/');
- $baseBranchDir = Files::mkdir($branchesDir . 'fluidbook-html5');
-
- $this->executeGitCommands($baseBranchDir, ['stash save --keep-index', 'stash drop', 'pull --all', 'fetch --all --prune']);
-
- $git = new Git($baseBranchDir);
- $branches = $git->listBranches();
- foreach ($branches as $b) {
- $gitsource = $branchesDir . $b;
- $local = $localDir . $b;
- if (!file_exists($branchesDir . $b)) {
- $this->executeGitCommands($branchesDir, 'clone -b ' . $b . ' --single-branch git@git.cubedesigners.com:fluidbook-html5.git ' . $b);
- }
- if (!file_exists($local)) {
- mkdir($local, 0777, true);
- `cp -r $gitsource/* $local`;
- `rm -rf $local/.git`;
- }
- $this->executeGitCommands($branchesDir . $b, ['reset --hard origin/' . $b, 'pull']);
- }
- file_put_contents($playerDir . '/activebranches', json_encode($branches));
+ $this->updateAllBranches();
}
}
{
protected function setupPreviewRoutes($segment, $routeName, $controller)
{
- Route::match(['get'], $segment . '/{id}_{hash}/preview', $controller . '@preview')->withoutMiddleware([CheckIfAdmin::class]);
+ // Redirect to the url with a timestamp to prevent cache
+ Route::match(['get'], $segment . '/preview/{id}_{hash}', function ($id, $hash) use ($segment) {
+ return redirect(backpack_url($segment . '/preview/' . $id . '_' . $hash . '_' . time()));
+ })->whereNumber('id')
+ ->where('hash', '[0-9a-f]{32}')
+ ->withoutMiddleware([CheckIfAdmin::class]);
+
+ Route::match(['get'], $segment . '/preview/{id}_{hash}_{time}/{path?}', function ($id, $hash, $time, $path = 'index.html') use ($segment, $controller) {
+ // If timestamp is too old, redirect to a more recent one
+ if ($path === 'index.html' && (time() - $time) > 30) {
+ return redirect(backpack_url($segment . '/preview/' . $id . '_' . $hash . '_' . time() . '/'));
+ }
+ return $this->preview($id, $hash, $path);
+ })->whereNumber('id')
+ ->where('hash', '[0-9a-f]{32}')
+ ->where('path', '.*')
+ ->withoutMiddleware([CheckIfAdmin::class]);
}
protected function setupPreviewDefaults()
$this->crud->addButtonFromView('line', 'preview', 'fluidbook_publication.preview', 'end');
}
- public function preview($id, $hash)
+ public function preview($id, $hash, $path = 'index.html')
{
$fluidbook = FluidbookPublication::where('id', $id)->where('hash', $hash)->first();
if (null === $fluidbook) {
abort(404);
}
+ $dest = $fluidbook->getFinalPath();
+
+ if ($path === 'index.html') {
+ $fluidbook->compile($dest);
+ }
+ return response('Preview of fluidbook ' . $id . ': ' . $path);
}
}
--- /dev/null
+<?php
+
+namespace App\Http\Controllers\Admin\Operations\Tools;
+
+use Prologue\Alerts\Facades\Alert;
+
+trait BaseTool
+{
+ protected function _warn($message)
+ {
+ $this->_flash($message, 'warning');
+ return $this->_redirectReferer();
+ }
+
+ protected function _success($message)
+ {
+ $this->_flash($message, 'success');
+ return $this->_redirectReferer();
+ }
+
+ protected function _error($message)
+ {
+ $this->_flash($message, 'error');
+ return $this->_redirectReferer();
+ }
+
+ protected function _flash($message, $type = 'info')
+ {
+ Alert::add($type, $message)->flash();
+ }
+
+ protected function _redirectReferer()
+ {
+ return redirect(request()->input('_referrer'));
+ }
+}
trait DockerWebContainer
{
+ use BaseTool;
public function dockerwebcontainer()
{
$form = new Form(backpack_url('tools/dodockerwebcontainer'));
trait Excel2JSON
{
+ use BaseTool;
public function excel2json()
{
$form = new Form(backpack_url('tools/doexcel2json'));
trait FluidbookAssetsDownloader
{
+ use BaseTool;
+
public function fluidbookassetsdownloader()
{
$form = new Form(backpack_url('tools/fluidbookassetsdownloaderDownload'));
'type' => FluidbookID::class]);
$form->addField('folder', SelectFromArray::class, __('Dossier'), ['allows_null' => false, 'options' => ['commerce' => __('Panier / eCommerce'), 'working' => __('Assets et liens')]]);
$form->addField('url', Textarea::class, __('Liste des urls à télécharger'), ['hint' => __('Une URL par ligne')]);
- $form->addField('type', SelectFromArray::class, __('Méthode'), ['allows_null' => false, 'options' => ['unzip' => __('Télécharger et dézipper'),'unzip_recursive' => __('Télécharger et dézipper'), 'download' => __('Télécharger les fichier')], 'hint' => __('Dézipper ne conservera pas l\'arborescence des fichiers dans le zip')]);
+ $form->addField('type', SelectFromArray::class, __('Méthode'), ['allows_null' => false, 'options' => ['unzip' => __('Télécharger et dézipper'), 'unzip_recursive' => __('Télécharger et dézipper'), 'download' => __('Télécharger les fichier')], 'hint' => __('Dézipper ne conservera pas l\'arborescence des fichiers dans le zip')]);
$form->addField('debug', Checkbox::class, __('Mode débogage'));
return view('tools.form', ['form' => $form]);
PHP::neverStop(false);
}
\App\Jobs\Tools\FluidbookAssetsDownloader::$func($request->input('url'), $request->input('type'), $request->input('fluidbook'), $request->input('folder'), backpack_user());
- Alert::add('success', __('L\'opération a été placée en file d\'attente. Vous recevrez un email lorsqu\'elle sera terminée.'))->flash();
- return redirect($request->input('_referrer'));
+
+ return $this->_success(__('L\'opération a été placée en file d\'attente. Vous recevrez un email lorsqu\'elle sera terminée.'));
}
}
--- /dev/null
+<?php
+
+namespace App\Http\Controllers\Admin\Operations\Tools;
+
+use App\Models\Traits\FluidbookPlayerBranches;
+use Cubist\Backpack\Magic\Fields\Text;
+use Cubist\Backpack\Magic\Form;
+use Cubist\Util\Str;
+use Prologue\Alerts\Facades\Alert;
+
+trait FluidbookBranchCreate
+{
+ use BaseTool;
+ use FluidbookPlayerBranches;
+
+ public function fluidbookbranchcreate()
+ {
+ $form = new Form(backpack_url('tools/dofluidbookbranchcreate'));
+ $form->setTitle(__('Créer une branch fluidbook'));
+ $form->setSubmitLabel(__('Créer'));
+ $form->setSubmitIcon('la-git');
+ $form->addField('branch', Text::class, __('Nom de la branche'));
+
+ return view('tools.form', ['form' => $form]);
+ }
+
+ public function dofluidbookbranchcreate()
+ {
+ $branch = request()->get('branch');
+ if (null === $branch) {
+ return $this->_error(__('Le nom de la branche est invalide'));
+ }
+ $branch = \Cubist\Util\Text::str2url(trim($branch));
+ $branches = $this->getActiveBranches();
+ if (in_array($branch, $branches)) {
+ return $this->_error(__('La branche :branch existe déjà', ['branch', $branch]));
+ }
+
+ if ($this->fluidbookCreateBranch($branch)) {
+ return $this->_success(__('La branche :branch a été crée', ['branch' => $branch]));
+ } else {
+ return $this->_error(__('Une erreur s\'est produite lors de la création de la branche :branch', ['branch' => $branch]));
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Http\Controllers\Admin\Operations\Tools;
+
+use App\Models\Traits\FluidbookPlayerBranches;
+use Cubist\Backpack\Magic\Fields\SelectFromArray;
+use Cubist\Backpack\Magic\Form;
+
+trait FluidbookBranchRemove
+{
+ use BaseTool;
+ use FluidbookPlayerBranches;
+
+ protected static $_fluidbookProtectedBranches = ['master'];
+
+ public function fluidbookbranchremove()
+ {
+ $form = new Form(backpack_url('tools/dofluidbookbranchremove'));
+ $form->setTitle(__('Supprimer une branch fluidbook'));
+ $form->setSubmitLabel(__('Supprimer'));
+ $form->setSubmitIcon('la-git');
+ $branches = array_diff($this->getActiveBranches(), self::$_fluidbookProtectedBranches);
+ $form->addField('branch', SelectFromArray::class, __('Nom de la branche'), ['options' => array_combine($branches, $branches)]);
+
+ return view('tools.form', ['form' => $form]);
+ }
+
+ public function dofluidbookbranchremove()
+ {
+ $branch = request()->get('branch');
+ if (null === $branch) {
+ return $this->_error(__('Veuillez sélectionner une branche à supprimer'));
+ }
+ $branches = $this->getActiveBranches();
+ if (!in_array($branch, $branches) || in_array($branch, self::$_fluidbookProtectedBranches)) {
+ return $this->_error(__('Impossible de supprimer la branche :branch', ['branch' => $branch]));
+ }
+ if ($this->fluidbookRemoveBranch($branch)) {
+ return $this->_success(__('La branche :branch a été supprimée', ['branch' => $branch]));
+ } else {
+ return $this->_error(__('Une erreur s\'est produite lors de la suppression de la branche :branch', ['branch' => $branch]));
+ }
+ }
+}
namespace App\Http\Controllers\Admin\Operations\Tools;
-use Cubist\Backpack\Magic\Fields\Checkbox;
-use Cubist\Backpack\Magic\Fields\Integer;
-use Cubist\Backpack\Magic\Fields\SelectFromArray;
-use Cubist\Backpack\Magic\Fields\StandardFile;
-use Cubist\Backpack\Magic\Fields\Text;
use Cubist\Backpack\Magic\Form;
-use Cubist\Util\Str;
-use Prologue\Alerts\Facades\Alert;
+use Cubist\Util\Text;
+
trait GitReposCreate
{
+ use BaseTool;
+
public function gitreposcreate()
{
$form = new Form(backpack_url('tools/dogitreposcreate'));
$form->setTitle(__('Créer un répertoire GIT'));
$form->setSubmitLabel(__('Create'));
$form->setSubmitIcon('la-git');
- $form->addField('repos', Text::class, __('Nom du répertoire'), ['prefix' => 'git@git.cubedesigners.com:', 'suffix' => '.git']);
+ $form->addField('repos', \Cubist\Backpack\Magic\Fields\Text::class, __('Nom du répertoire'), ['prefix' => 'git@git.cubedesigners.com:', 'suffix' => '.git']);
return view('tools.form', ['form' => $form]);
}
`cd $storage;git clone git@git.cubedesigners.com:gitolite-admin.git`;
}
`cd $gitolite;git stash;git pull`;
- $repos = Str::slug($request->get('repos'));
+ $repos = Text::str2url($request->get('repos'));
$projectsConf = $gitolite . '/conf/projects.conf';
$projects = trim(file_get_contents($projectsConf));
$projects .= "\n@allrepos = $repos\n";
$projects;
`cd $gitolite;git commit -a -m "Added $repos from Toolbox"`;
`cd $gitolite;git push -u origin master`;
- Alert::add('success', __('Le répertoire :repos a été crée', ['repos' => $repos]))->flash();
- return redirect($request->input('_referrer'));
+
+ return $this->_success(__('Le répertoire :repos a été crée', ['repos' => $repos]));
}
}
use App\Http\Controllers\Admin\Operations\Tools\DockerWebContainer;
use App\Http\Controllers\Admin\Operations\Tools\Excel2JSON;
use App\Http\Controllers\Admin\Operations\Tools\FluidbookAssetsDownloader;
+use App\Http\Controllers\Admin\Operations\Tools\FluidbookBranchCreate;
+use App\Http\Controllers\Admin\Operations\Tools\FluidbookBranchRemove;
use App\Http\Controllers\Admin\Operations\Tools\GitReposCreate;
use App\Http\Controllers\Admin\Operations\Tools\JSON2Excel;
use App\Http\Controllers\Admin\Operations\Tools\PDF2SVGOperation;
use DockerWebContainer;
use JSON2Excel;
use Excel2JSON;
+ use FluidbookBranchCreate;
+ use FluidbookBranchRemove;
protected function index($tool, $args = '')
{
use Cubist\Backpack\Magic\Fields\Hidden;
use Cubist\Backpack\Magic\Fields\Integer;
use Cubist\Backpack\Magic\Fields\SelectFromArray;
+use Cubist\Scorm\Manifest;
+use Cubist\Util\Files\VirtualDirectory;
class FluidbookPublication extends ToolboxModel
{
}
return $res;
}
+
+ public function getFinalPath()
+ {
+ return protected_path('fluidbookpublication/final/' . $this->id);
+ }
+
+ public function compile($dest)
+ {
+
+ }
}
--- /dev/null
+<?php
+
+namespace App\Models\Traits;
+
+use Cubist\Util\CommandLine\Git;
+use Cubist\Util\Files\Files;
+use Cubist\Util\PHP;
+
+trait FluidbookPlayerBranches
+{
+ protected function executeGitCommands($dir, $commands)
+ {
+ if (!is_array($commands)) {
+ $commands = [$commands];
+ }
+ $res = [];
+ foreach ($commands as $command) {
+ $res[] = $this->executeGitCommand($dir, $command);
+ }
+ return $res;
+ }
+
+ protected function executeGitCommand($dir, $command)
+ {
+ $git = new Git($dir);
+ $output = $git->executeCmd($command);
+
+ if (method_exists($this, 'line')) {
+ $this->line('<fg=blue>' . $git->getCommand() . '</>');
+ $this->line($output);
+ }
+ return $output;
+ }
+
+ protected function getFluidbookPlayerBaseDirectory()
+ {
+ return Files::mkdir(resource_path('fluidbookpublication/player')) . '/';
+ }
+
+ protected function getActiveBranches()
+ {
+ $cacheFile = $this->getFluidbookPlayerBaseDirectory() . '/activebranches';
+ return json_decode(file_get_contents($cacheFile));
+ }
+
+ protected function fluidbookCreateBranch($branch)
+ {
+ $playerDir = $this->getFluidbookPlayerBaseDirectory();
+
+ $this->updateAllBranches();
+
+ $branchesDir = $playerDir . 'branches/';
+ $dir = $branchesDir . 'fluidbook-html5';
+ $this->executeGitCommands($dir, ['checkout -b ' . $branch, 'push --set-upstream origin ' . $branch]);
+
+ $this->updateAllBranches();
+ $this->executeGitCommand($dir, 'checkout master');
+
+ $this->updateAllBranches();
+ return in_array($branch, $this->getActiveBranches());
+ }
+
+ protected function fluidbookRemoveBranch($branch)
+ {
+ $playerDir = $this->getFluidbookPlayerBaseDirectory();
+ $branchesDir = $playerDir . 'branches/';
+ $localDir = $playerDir . 'local/';
+
+ $this->updateAllBranches();
+ $this->executeGitCommand($branchesDir . 'fluidbook-html5', 'push --delete origin ' . $branch);
+
+ `rm -rf $localDir$branch`;
+ `rm -rf $branchesDir$branch`;
+
+ // TODO modifier la branche des fluidbooks qui utilisaient cette branche (self::resetPlayerVersion($branch);)
+
+ $this->updateAllBranches();
+ return !in_array($branch, $this->getActiveBranches());
+ }
+
+ protected function updateAllBranches()
+ {
+ PHP::neverStop();
+
+ $playerDir = $this->getFluidbookPlayerBaseDirectory();
+ $branchesDir = Files::mkdir($playerDir . 'branches/');
+ $localDir = Files::mkdir($playerDir . 'local/');
+ $baseBranchDir = Files::mkdir($branchesDir . 'fluidbook-html5');
+
+ $this->executeGitCommands($baseBranchDir, ['stash save --keep-index', 'stash drop', 'pull --all', 'fetch --all --prune']);
+
+ $git = new Git($baseBranchDir);
+ $branches = $git->listBranches();
+ foreach ($branches as $b) {
+ $gitsource = $branchesDir . $b;
+ $local = $localDir . $b;
+ if (!file_exists($branchesDir . $b)) {
+ $this->executeGitCommands($branchesDir, 'clone -b ' . $b . ' --single-branch git@git.cubedesigners.com:fluidbook-html5.git ' . $b);
+ }
+ if (!file_exists($local)) {
+ mkdir($local, 0777, true);
+ `cp -r $gitsource/* $local`;
+ `rm -rf $local/.git`;
+ }
+ $this->executeGitCommands($branchesDir . $b, ['reset --hard origin/' . $b, 'pull']);
+ }
+ file_put_contents($playerDir . '/activebranches', json_encode($branches));
+ }
+
+}
<li class='nav-item'><a class='nav-link' href='{{ backpack_url('tools/excel2json') }}'><i
class='nav-icon las la-code'></i>
<span>{{__('Excel to JSON')}}</span></a></li>
+ <li class='nav-item'><a class='nav-link' href='{{ backpack_url('tools/fluidbookbranchcreate') }}'><i
+ class='nav-icon la la-git'></i>
+ <span>{{__('Créer une branche du player fluidbook')}}</span></a></li>
+ <li class='nav-item'><a class='nav-link' href='{{ backpack_url('tools/fluidbookbranchremove') }}'><i
+ class='nav-icon la la-git'></i>
+ <span>{{__('Supprimer une branche du player fluidbook')}}</span></a></li>
+
{{-- <li class='nav-item'><a class='nav-link' href='{{ backpack_url('tools/securehosting') }}'><i--}}
{{-- class='nav-icon la la-lock'></i>--}}
{{-- <span>{{__('Sécuriser hosting')}}</span></a></li>--}}