From 74581f80d4145c9b438598e23516f7892a01217c Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Mon, 31 Jan 2022 11:58:27 +0100 Subject: [PATCH] wip #5045 @3 --- .../ELearningMedia/DownloadOperation.php | 28 +++++ .../ELearningMedia/PreviewOperation.php | 5 +- app/Jobs/DownloadBase.php | 81 +++++++++++++ app/Jobs/ElearningMediaDownload.php | 55 +++++++++ app/Jobs/FluidbookCollectionDownload.php | 111 +++--------------- ...ctionDownload.php => DeferredDownload.php} | 2 +- app/Models/ELearningMedia.php | 11 +- app/Services/ScormCloud.php | 49 ++++++++ .../buttons/elearningmedia/download.blade.php | 53 ++++++++- update | 1 + 10 files changed, 294 insertions(+), 102 deletions(-) create mode 100644 app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php create mode 100644 app/Jobs/DownloadBase.php create mode 100644 app/Jobs/ElearningMediaDownload.php rename app/Mail/{FluidbookCollectionDownload.php => DeferredDownload.php} (82%) create mode 100644 app/Services/ScormCloud.php diff --git a/app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php b/app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php new file mode 100644 index 000000000..b58c9d529 --- /dev/null +++ b/app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php @@ -0,0 +1,28 @@ +crud->addButtonFromView('line', 'download', 'elearningmedia.download', 'end'); + } + + protected function download($id, $action) + { + ElearningMediaDownload::dispatch(ELearningMedia::find($id), $action, backpack_user()); + Alert::add('success', __('La compilation a été placée en file d\'attente. Vous recevrez un email lorsqu\'elle sera terminée.'))->flash(); + return redirect(backpack_url('elearning-media')); + } +} diff --git a/app/Http/Controllers/Admin/Operations/ELearningMedia/PreviewOperation.php b/app/Http/Controllers/Admin/Operations/ELearningMedia/PreviewOperation.php index 6b01804e8..80985a64a 100644 --- a/app/Http/Controllers/Admin/Operations/ELearningMedia/PreviewOperation.php +++ b/app/Http/Controllers/Admin/Operations/ELearningMedia/PreviewOperation.php @@ -20,10 +20,11 @@ trait PreviewOperation protected function preview($id, $path = 'index.html') { - $dest = protected_path('elearningmedia/final/' . $id); + $entry = $this->crud->getEntry($id); + $dest = $entry->getFinalPath(); if ($path === 'index.html') { - $entry = $this->crud->getEntry($id); + $entry->compile($dest); } diff --git a/app/Jobs/DownloadBase.php b/app/Jobs/DownloadBase.php new file mode 100644 index 000000000..7b373ef5f --- /dev/null +++ b/app/Jobs/DownloadBase.php @@ -0,0 +1,81 @@ +entry = $entry; + $this->user = $user; + $this->action = $action; + } + + public function sendEmail($subject, $body) + { + $mail = new DeferredDownload(); + $mail->to($this->user->email); + $mail->subject($subject); + $mail->html($body); + Mail::send($mail); + } + + protected function _fname($title = null, $extension = 'zip') + { + if (null === $title) { + $title = $this->entry->title; + } + return Str::slugCase($this->type . '-' . date('Ymdhis') . '-' . md5(rand(10000, 100000000)) . '-' . Str::slug($title)) . '.' . $extension; + } + + + protected function _dest($fname) + { + return Files::mkdir(storage_path('app/public/' . $this->type . '/download/')) . $fname; + } + + protected function _url($fname) + { + return url('storage/' . $this->type . '/download/' . $fname); + } +} diff --git a/app/Jobs/ElearningMediaDownload.php b/app/Jobs/ElearningMediaDownload.php new file mode 100644 index 000000000..b8f533a81 --- /dev/null +++ b/app/Jobs/ElearningMediaDownload.php @@ -0,0 +1,55 @@ +entry->getFinalPath(); + $this->entry->compile($compilepath); + + $fname = $this->_fname(); + $dest = Files::mkdir(storage_path('app/public/elearningmedia/download/')) . $fname; + + Zip::archive($compilepath, $dest); + if (!file_exists($dest)) { + throw new \Exception('An error occured while compiling the collection'); + } + + $url = $this->_url($fname); + + $subject = __('Media ":title" (#:nb) prêt au téléchargement', ['title' => $this->entry->title, 'nb' => $this->entry->id]); + $body = __('Le fichier est disponible à l\'adresse suivante : :url', ['url' => $url]); + + try { + if ($this->action === 'scormcloud') { + $scormURL = ScormCloud::send($url, 'toolbox_' . $this->type . '_' . $this->entry->id); + $body .= "

"; + $body .= __('Le media peut être testé sur SCORM Cloud : :url', ['url' => $scormURL]); + } + } catch (\Exception $e) { + $body .= "

"; + $body .= __('Une erreur s\'est produite lors de l\'envoi sur SCORM Cloud (App ID :appid) : :error', ['error' => $e->getMessage(), 'appid' => env('SCORM_CLOUD_APP_ID')]); + } + + + } catch (\Exception $e) { + $subject = __('Erreur lors de la compilation du media :nb', ['nb' => $this->entry->id]); + $body = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); + } + + $this->sendEmail($subject, $body); + } + + +} diff --git a/app/Jobs/FluidbookCollectionDownload.php b/app/Jobs/FluidbookCollectionDownload.php index 753bceef9..6228cccb9 100644 --- a/app/Jobs/FluidbookCollectionDownload.php +++ b/app/Jobs/FluidbookCollectionDownload.php @@ -2,57 +2,17 @@ namespace App\Jobs; -use App\Models\FluidbookCollection; -use App\Models\User; +use App\Services\ScormCloud; use App\Services\WorkshopV2; use Cubist\Util\Files\Files; use Cubist\Util\PHP; use Cubist\Util\Str; use Cubist\Util\Zip; -use GuzzleHttp\Exception\RequestException; -use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\Mail; -use InvalidArgumentException; -use Psr\Http\Message\ResponseInterface; -use RusticiSoftware\Cloud\V2 as ScormCloud; - - -class FluidbookCollectionDownload implements ShouldQueue -{ - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - - /** - * @var FluidbookCollection - */ - protected $collection; - - /** - * @var User - */ - protected $user; - - - /** - * @var string - */ - protected $action; - - /** - * @param $collection FluidbookCollection - * @param $user User - */ - public function __construct($collection, $action, $user) - { - $this->collection = $collection; - $this->action = $action; - $this->user = $user; +class FluidbookCollectionDownload extends DownloadBase +{ - } + protected $type = 'collection'; /** * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response @@ -61,20 +21,20 @@ class FluidbookCollectionDownload implements ShouldQueue public function handle() { try { - $compilepath = protected_path('collection/final/' . $this->collection->id); + $compilepath = protected_path('collection/final/' . $this->entry->id); $this->compile($compilepath); - $fname = Str::slugCase('collection-' . date('Ymdhis') . '-' . md5(rand(10000, 100000000)) . '-' . Str::slug($this->collection->title)) . '.zip'; - $dest = Files::mkdir(storage_path('app/public/collection/download/')) . $fname; + $fname = $this->_fname(); + $dest = $this->_dest($fname); Zip::archive($compilepath, $dest); if (!file_exists($dest)) { throw new \Exception('An error occured while compiling the collection'); } - $url = url('storage/collection/download/' . $fname); + $url = $this->_url($fname); - $subject = __('Collection ":title" (#:nb) prête au téléchargement', ['title' => $this->collection->title, 'nb' => $this->collection->id]); + $subject = __('Collection ":title" (#:nb) prête au téléchargement', ['title' => $this->entry->title, 'nb' => $this->entry->id]); $body = __('Le fichier est disponible à l\'adresse suivante : :url', ['url' => $url]); try { @@ -90,15 +50,12 @@ class FluidbookCollectionDownload implements ShouldQueue } catch (\Exception $e) { - $subject = __('Erreur lors de la compilation de la collection :nb', ['nb' => $this->collection->id]); + $subject = __('Erreur lors de la compilation de la collection :nb', ['nb' => $this->entry->id]); $body = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); } - $mail = new \App\Mail\FluidbookCollectionDownload(); - $mail->to($this->user->email); - $mail->subject($subject); - $mail->html($body); - Mail::send($mail); + $this->sendEmail($subject, $body); + } /** @@ -106,7 +63,7 @@ class FluidbookCollectionDownload implements ShouldQueue */ public function compile($path) { - $data = $this->collection->getPageData(); + $data = $this->entry->getPageData(); $path = Files::emptyDir($path); PHP::neverStop(); @@ -131,7 +88,7 @@ class FluidbookCollectionDownload implements ShouldQueue { $options = []; - foreach ($this->collection->getPageData()->override_settings as $setting) { + foreach ($this->entry->getPageData()->override_settings as $setting) { $options[$setting['key']] = $setting['value']; } @@ -208,7 +165,7 @@ class FluidbookCollectionDownload implements ShouldQueue } $manifestContent = file_get_contents($manifestFile); - $manifestContent = preg_replace('/\(.*)\<\/title\>/U', '' . htmlspecialchars($this->collection->title) . '', $manifestContent); + $manifestContent = preg_replace('/\(.*)\<\/title\>/U', '' . htmlspecialchars($this->entry->title) . '', $manifestContent); file_put_contents($manifestFile, $manifestContent); $redirectionScript = " @@ -299,42 +256,6 @@ window.location='./' + locale + '/index.html'; public function sendToSCORMCloud($url) { - $config = new ScormCloud\Configuration(); - $appId = env('SCORM_CLOUD_APP_ID'); - $config->setUsername($appId); - $config->setPassword(env('SCORM_CLOUD_SECRET_KEY')); - ScormCloud\Configuration::setDefaultConfiguration($config); - - $courseId = 'toolbox_collection_' . $this->collection->getKey(); - $courseAPI = new ScormCloud\Api\CourseApi(); - - try { - $courseAPI->deleteCourse($courseId); - } catch (\Exception $e) { - - } - - $request = new ScormCloud\Model\ImportFetchRequestSchema(['url' => $url, 'content_type' => 'application/zip']); - $promise = $courseAPI->createFetchAndImportCourseJobAsync($courseId, $request, true); - $jobId = $promise->wait(); - - for ($i = 0; $i <= 20; $i++) { - try { - $jobResult = $courseAPI->getImportJobStatus($jobId->getResult()); - break; - } catch (\Exception $e) { - sleep(10); - } - } - while ($jobResult->getStatus() == ScormCloud\Model\ImportJobResultSchema::STATUS_RUNNING) { - sleep(1); - $jobResult = $courseAPI->getImportJobStatus($jobId->getResult()); - } - - if ($jobResult->getStatus() == ScormCloud\Model\ImportJobResultSchema::STATUS_ERROR) { - throw new InvalidArgumentException('Course is not properly formatted: ' . $jobResult->getMessage()); - } - - return 'https://cloud.scorm.com/sc/user/Course?appId=' . $appId . '&courseId=' . $courseId; + return ScormCloud::send($url, 'toolbox_collection_' . $this->entry->getKey()); } } diff --git a/app/Mail/FluidbookCollectionDownload.php b/app/Mail/DeferredDownload.php similarity index 82% rename from app/Mail/FluidbookCollectionDownload.php rename to app/Mail/DeferredDownload.php index 1177495d2..359e2f8cd 100644 --- a/app/Mail/FluidbookCollectionDownload.php +++ b/app/Mail/DeferredDownload.php @@ -6,7 +6,7 @@ use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; -class FluidbookCollectionDownload extends Mailable +class DeferredDownload extends Mailable { use Queueable, SerializesModels; diff --git a/app/Models/ELearningMedia.php b/app/Models/ELearningMedia.php index bc65d2de8..cbac9ff82 100644 --- a/app/Models/ELearningMedia.php +++ b/app/Models/ELearningMedia.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Http\Controllers\Admin\Operations\ELearningMedia\ImportOperation; use App\Http\Controllers\Admin\Operations\ELearningMedia\PreviewOperation; +use App\Http\Controllers\Admin\Operations\ELearningMedia\DownloadOperation; use App\Models\Base\ToolboxModel; use Cubist\Backpack\Magic\Fields\Files; use Cubist\Backpack\Magic\Fields\Percent; @@ -24,7 +25,7 @@ class ELearningMedia extends ToolboxModel public const MEDIA_TYPES = ['audio/mpeg', 'video/mp4']; - protected $_operations = [ImportOperation::class, PreviewOperation::class]; + protected $_operations = [ImportOperation::class, PreviewOperation::class, DownloadOperation::class]; public function setFields() { @@ -39,9 +40,15 @@ class ELearningMedia extends ToolboxModel $this->addField('file', Files::class, __('Media'), ['acceptedFiles' => static::MEDIA_TYPES]); } + public function getFinalPath() + { + return protected_path('elearningmedia/final/' . $this->id); + } + public function compile($dest) { - $organization = User::find($this->owner)->companyName; + $owner = User::withoutGlobalScopes()->findOrFail($this->owner); + $organization = $owner->companyName; $vdir = new VirtualDirectory($dest); $vdir->file_put_contents('imsmanifest.xml', new Manifest($this->title, Manifest::SCORM_2004, $organization, 'MEDIA_' . $this->id)); diff --git a/app/Services/ScormCloud.php b/app/Services/ScormCloud.php new file mode 100644 index 000000000..dd7827f05 --- /dev/null +++ b/app/Services/ScormCloud.php @@ -0,0 +1,49 @@ +setUsername($appId); + $config->setPassword(env('SCORM_CLOUD_SECRET_KEY')); + V2\Configuration::setDefaultConfiguration($config); + + $courseAPI = new V2\Api\CourseApi(); + + try { + $courseAPI->deleteCourse($courseId); + } catch (\Exception $e) { + + } + + $request = new V2\Model\ImportFetchRequestSchema(['url' => $url, 'content_type' => 'application/zip']); + $promise = $courseAPI->createFetchAndImportCourseJobAsync($courseId, $request, true); + $jobId = $promise->wait(); + + for ($i = 0; $i <= 20; $i++) { + try { + $jobResult = $courseAPI->getImportJobStatus($jobId->getResult()); + break; + } catch (\Exception $e) { + sleep(10); + } + } + while ($jobResult->getStatus() == V2\Model\ImportJobResultSchema::STATUS_RUNNING) { + sleep(1); + $jobResult = $courseAPI->getImportJobStatus($jobId->getResult()); + } + + if ($jobResult->getStatus() == V2\Model\ImportJobResultSchema::STATUS_ERROR) { + throw new InvalidArgumentException('Course is not properly formatted: ' . $jobResult->getMessage()); + } + + return 'https://cloud.scorm.com/sc/user/Course?appId=' . $appId . '&courseId=' . $courseId; + } +} diff --git a/resources/views/vendor/backpack/crud/buttons/elearningmedia/download.blade.php b/resources/views/vendor/backpack/crud/buttons/elearningmedia/download.blade.php index ec3f06531..ec4743b37 100644 --- a/resources/views/vendor/backpack/crud/buttons/elearningmedia/download.blade.php +++ b/resources/views/vendor/backpack/crud/buttons/elearningmedia/download.blade.php @@ -1,2 +1,51 @@ - {{__('Télécharger')}} +@once + @php + $showjs=false; + if($crud->getValue('seenExportJS')===null){ + $showjs =true; + $crud->setValue('seenExportJS',true); + } + @endphp + @if($showjs) + + + @endif +@endonce + + {{__('Exporter')}} + + diff --git a/update b/update index 2fef21a7a..7a736ab75 100644 --- a/update +++ b/update @@ -5,3 +5,4 @@ /usr/bin/php8.0 artisan cubist:magic:migrate /usr/bin/php8.0 artisan cubist:magic:generate /usr/bin/php8.0 artisan optimize:clear +npm run prod -- 2.39.5