]> _ Git - fluidbook-toolbox.git/commitdiff
wip #5045 @3
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Mon, 31 Jan 2022 10:58:27 +0000 (11:58 +0100)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Mon, 31 Jan 2022 10:58:27 +0000 (11:58 +0100)
app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php [new file with mode: 0644]
app/Http/Controllers/Admin/Operations/ELearningMedia/PreviewOperation.php
app/Jobs/DownloadBase.php [new file with mode: 0644]
app/Jobs/ElearningMediaDownload.php [new file with mode: 0644]
app/Jobs/FluidbookCollectionDownload.php
app/Mail/DeferredDownload.php [new file with mode: 0644]
app/Mail/FluidbookCollectionDownload.php [deleted file]
app/Models/ELearningMedia.php
app/Services/ScormCloud.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/buttons/elearningmedia/download.blade.php
update

diff --git a/app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php b/app/Http/Controllers/Admin/Operations/ELearningMedia/DownloadOperation.php
new file mode 100644 (file)
index 0000000..b58c9d5
--- /dev/null
@@ -0,0 +1,28 @@
+<?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'));
+    }
+}
index 6b01804e8e6caee9bb2c38e988241143a3461ea4..80985a64a5ae8fdccc256d81bddb437389722f46 100644 (file)
@@ -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 (file)
index 0000000..7b373ef
--- /dev/null
@@ -0,0 +1,81 @@
+<?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);
+    }
+}
diff --git a/app/Jobs/ElearningMediaDownload.php b/app/Jobs/ElearningMediaDownload.php
new file mode 100644 (file)
index 0000000..b8f533a
--- /dev/null
@@ -0,0 +1,55 @@
+<?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);
+    }
+
+
+}
index 753bceef9164c8fb9f603c8fe66b7b4b03e0205c..6228cccb958f8486fc4592cd651d57272873a5be 100644 (file)
@@ -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 : <a href=":url">:url</a>', ['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\>(.*)\<\/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>
@@ -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/DeferredDownload.php b/app/Mail/DeferredDownload.php
new file mode 100644 (file)
index 0000000..359e2f8
--- /dev/null
@@ -0,0 +1,18 @@
+<?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;
+    }
+
+}
diff --git a/app/Mail/FluidbookCollectionDownload.php b/app/Mail/FluidbookCollectionDownload.php
deleted file mode 100644 (file)
index 1177495..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<?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;
-    }
-
-}
index bc65d2de801d91439cd613f41feade2bab6714b9..cbac9ff8274b47b2c3503b6965bf47e969b2e2fc 100644 (file)
@@ -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 (file)
index 0000000..dd7827f
--- /dev/null
@@ -0,0 +1,49 @@
+<?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;
+    }
+}
index ec3f065311f2093c472944c0f1ada0439229d051..ec4743b37e79c00661e428f78ef0bbc696836192 100644 (file)
@@ -1,2 +1,51 @@
-<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>
diff --git a/update b/update
index 2fef21a7ae298e1191211271e8fbd90d8b421368..7a736ab75121ca8322ea38bc5fd8861d13ba6032 100644 (file)
--- 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