--- /dev/null
+<?php
+
+namespace App\Http\Controllers\Admin\Operations\ELearningMedia;
+
+use App\Jobs\ElearningMediaDownload;
+use App\Models\ELearningMedia;
+use Illuminate\Support\Facades\Route;
+use Prologue\Alerts\Facades\Alert;
+
+trait DownloadOperation
+{
+ protected function setupDownloadRoutes($segment, $routeName, $controller)
+ {
+ Route::match(['get'], $segment . '/{id}/download/{action}', $controller . '@download');
+ }
+
+ protected function setupDownloadDefaults()
+ {
+ $this->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'));
+ }
+}
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);
}
--- /dev/null
+<?php
+
+namespace App\Jobs;
+
+use App\Mail\DeferredDownload;
+use App\Models\User;
+use Cubist\Backpack\Magic\Models\CubistMagicAbstractModel;
+use Cubist\Util\Files\Files;
+use Cubist\Util\Str;
+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;
+
+class DownloadBase implements ShouldQueue
+{
+ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+ /**
+ * @var string
+ */
+ protected $type = 'base';
+
+ /**
+ * @var CubistMagicAbstractModel
+ */
+ protected $entry;
+
+ /**
+ * @var User
+ */
+ protected $user;
+
+
+ /**
+ * @var string
+ */
+ protected $action;
+
+ /**
+ * @param $entry CubistMagicAbstractModel
+ * @param $action string
+ * @param $user User
+ */
+ public function __construct($entry, $action, $user)
+ {
+ $this->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);
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Jobs;
+
+use App\Services\ScormCloud;
+use Cubist\Util\Files\Files;
+use Cubist\Util\Str;
+use Cubist\Util\Zip;
+
+class ElearningMediaDownload extends DownloadBase
+{
+
+ protected $type = 'elearningmedia';
+
+ public function handle()
+ {
+ try {
+ $compilepath = $this->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 : <a href=":url">:url</a>', ['url' => $url]);
+
+ try {
+ if ($this->action === 'scormcloud') {
+ $scormURL = ScormCloud::send($url, 'toolbox_' . $this->type . '_' . $this->entry->id);
+ $body .= "<br><br>";
+ $body .= __('Le media peut être testé sur SCORM Cloud : <a href=":url">:url</a>', ['url' => $scormURL]);
+ }
+ } catch (\Exception $e) {
+ $body .= "<br><br>";
+ $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);
+ }
+
+
+}
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
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 : <a href=":url">:url</a>', ['url' => $url]);
try {
} 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);
+
}
/**
*/
public function compile($path)
{
- $data = $this->collection->getPageData();
+ $data = $this->entry->getPageData();
$path = Files::emptyDir($path);
PHP::neverStop();
{
$options = [];
- foreach ($this->collection->getPageData()->override_settings as $setting) {
+ foreach ($this->entry->getPageData()->override_settings as $setting) {
$options[$setting['key']] = $setting['value'];
}
}
$manifestContent = file_get_contents($manifestFile);
- $manifestContent = preg_replace('/\<title\>(.*)\<\/title\>/U', '<title>' . htmlspecialchars($this->collection->title) . '</title>', $manifestContent);
+ $manifestContent = preg_replace('/\<title\>(.*)\<\/title\>/U', '<title>' . htmlspecialchars($this->entry->title) . '</title>', $manifestContent);
file_put_contents($manifestFile, $manifestContent);
$redirectionScript = "<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());
}
}
--- /dev/null
+<?php
+
+namespace App\Mail;
+
+use Illuminate\Bus\Queueable;
+use Illuminate\Mail\Mailable;
+use Illuminate\Queue\SerializesModels;
+
+class DeferredDownload extends Mailable
+{
+ use Queueable, SerializesModels;
+
+ public function build()
+ {
+ return $this;
+ }
+
+}
+++ /dev/null
-<?php
-
-namespace App\Mail;
-
-use Illuminate\Bus\Queueable;
-use Illuminate\Mail\Mailable;
-use Illuminate\Queue\SerializesModels;
-
-class FluidbookCollectionDownload extends Mailable
-{
- use Queueable, SerializesModels;
-
- public function build()
- {
- return $this;
- }
-
-}
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;
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()
{
$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));
--- /dev/null
+<?php
+
+namespace App\Services;
+
+use RusticiSoftware\Cloud\V2;
+use InvalidArgumentException;
+
+class ScormCloud
+{
+ public static function send($url,$courseId)
+ {
+ $config = new V2\Configuration();
+ $appId = env('SCORM_CLOUD_APP_ID');
+ $config->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;
+ }
+}
-<a class="btn btn-sm btn-link" href="{{$crud->route}}/{{$entry->getKey()}}/download" data-toggle="tooltip"
- title="{{__('Télécharger le media')}}"><i class="la la-arrow-circle-down"></i> {{__('Télécharger')}}</a>
+@once
+ @php
+ $showjs=false;
+ if($crud->getValue('seenExportJS')===null){
+ $showjs =true;
+ $crud->setValue('seenExportJS',true);
+ }
+ @endphp
+ @if($showjs)
+ <style>
+ a.exportelearningmedia {
+ position: relative;
+ }
+
+ a.exportelearningmedia select {
+ opacity: 0;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ cursor: pointer;
+ }
+ </style>
+ <script>
+ jQuery(document).ready(function ($) {
+ $('a.exportelearningmedia').on('click', function () {
+ return false;
+ });
+ $('a.exportelearningmedia select').on('change', function () {
+ var val = $(this).val();
+ if (val <= 0 || val == null || val == 'null') {
+ return;
+ }
+ var id = $(this).data('id');
+ window.location = $(this).data('route') + "/" + id + "/download/" + val;
+ });
+ });
+ </script>
+ @endif
+@endonce
+
+<a class="btn btn-sm btn-link exportelearningmedia" href="#"
+ data-toggle="tooltip"
+ title="{{__('Exporter le media')}}"><i class="la la-arrow-circle-down"></i> {{__('Exporter')}}
+ <select data-route="{{$crud->route}}" data-id="{{$entry->getKey()}}">
+ <option value="" selected style="display: none">--</option>
+ <option value="download">{{__('Télécharger')}}</option>
+ <option value="scormcloud">{{__('Tester sur Scorm Cloud')}}</option>
+ </select>
+</a>
/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