--- /dev/null
+<?php
+
+namespace App\Http\Controllers\Admin\Operations\Files;
+
+use App\Http\Middleware\CheckIfAdmin;
+use App\Models\File;
+use CFPropertyList\CFPropertyList;
+use CFPropertyList\IOException;
+use Cubist\Backpack\Http\Controllers\Base\XSendFileController;
+use Cubist\Util\Files\Files;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Route;
+use ZipArchive;
+
+trait DownloadOperation
+{
+ protected function setupDownloadRoutes($segment, $routeName, $controller)
+ {
+ Route::match(['get'], $segment . '/{hash}/install', $controller . '@manifestIpa')->withoutMiddleware([CheckIfAdmin::class]);
+ Route::match(['get'], $segment . '/{hash}/{file}', $controller . '@download')->withoutMiddleware([CheckIfAdmin::class]);
+
+ }
+
+ protected function setupDownloadDefaults()
+ {
+ $this->crud->addButtonFromView('line', 'install', 'files.install', 'end');
+ $this->crud->addButtonFromView('line', 'download', 'files.download', 'end');
+ }
+
+ protected function download($hash, $name)
+ {
+ $file = File::where('hash', $hash)->where('name', $name)->first();
+ if ($file === null) {
+ abort(404);
+ }
+ return XSendFileController::sendfile($file->path);
+ }
+
+ /**
+ * @throws IOException
+ */
+ protected function manifestIpa($hash)
+ {
+ $file = File::where('hash', $hash)->first();
+ if ($file === null) {
+ abort(404);
+ }
+
+ $xml = Cache::rememberForever('ipamanifest_' . $hash, function () use ($file) {
+ $ipa = $file->path;
+
+ $zip = new ZipArchive();
+ $zip->open($ipa);
+ for ($i = 0; $i < $zip->numFiles; $i++) {
+ $filename = $zip->getNameIndex($i);
+ if (preg_match('|Payload/(.+).app/Info.plist|', $filename, $matches)) {
+ $idx = $i;
+ break;
+ }
+ }
+ if (!$idx) {
+ return;
+ }
+
+ $tmp = Files::tempnam();
+ file_put_contents($tmp, $zip->getFromIndex($idx));
+
+ $plist = new CFPropertyList($tmp);
+
+ $infos = $plist->toArray();
+ $bundle = $infos['CFBundleIdentifier'];
+ $appName = $infos['CFBundleDisplayName'];
+ $version = $infos['CFBundleVersion'];
+
+ return '<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>items</key>
+ <array>
+ <dict>
+ <key>assets</key>
+ <array>
+ <dict>
+ <key>kind</key>
+ <string>software-package</string>
+ <key>url</key>
+ <string>' . $file->getURL() . '</string>
+ </dict>
+ <dict>
+ <key>kind</key>
+ <string>display-image</string>
+ <key>url</key>
+ <string>https://toolbox.fluidbook.com/images/ios/57.png</string>
+ </dict>
+ <dict>
+ <key>kind</key>
+ <string>full-size-image</string>
+ <key>url</key>
+ <string>https://toolbox.fluidbook.com/images/ios/57.png</string>
+ </dict>
+ </array>
+ <key>metadata</key>
+ <dict>
+ <key>bundle-identifier</key>
+ <string>' . $bundle . '</string>
+ <key>bundle-version</key>
+ <string>' . $version . '</string>
+ <key>kind</key>
+ <string>software</string>
+ <key>title</key>
+ <string>' . $appName . '</string>
+ </dict>
+ </dict>
+ </array>
+</dict>
+</plist>';
+ });
+
+
+ return response($xml, 200, ['Content-type' => 'application/xml']);
+
+
+ }
+
+}
+
namespace App\Models;
+use App\Http\Controllers\Admin\Operations\Files\DownloadOperation;
use App\Models\Base\ToolboxModel;
+use Cubist\Backpack\CubistBackpackServiceProvider;
use Cubist\Backpack\Magic\Fields\Date;
use Cubist\Backpack\Magic\Fields\Hidden;
use Cubist\Backpack\Magic\Fields\Integer;
protected static $_permissionBase = 'files';
+ protected $_enableEdition = false;
+ protected $_enableClone = false;
+
+ protected $primaryKey = 'hash';
+ public $incrementing = false;
+ protected $keyType = 'string';
+
+
+ protected $_operations = [DownloadOperation::class];
+
public function setFields()
{
parent::setFields();
+ //$this->addField('hash', Text::class, __('Hash'), ['column' => false, 'database_index' => true]);
$this->addField('name', Text::class, __('Nom du fichier'), ['column' => true]);
$this->addField('path', Hidden::class, __('Chemin'));
$this->addField('ext', Text::class, __('Type'), ['column' => true]);
$this->addField('updated_at', Date::class, __('Date'), ['column' => true]);
- $this->addField('size', Integer::class, __('Taille'), ['column' => true]);
+ $this->addField('size', Integer::class, __('Taille'), ['column' => true, 'column_type' => 'filesize', 'column_view_namespace' => CubistBackpackServiceProvider::NAMESPACE . '::columns']);
$this->addField('from', \App\Fields\User::class, __('Envoyé par'), ['column' => true]);
$this->addField('to', \App\Fields\User::class, __('Destiné à'), ['column' => true]);
- $this->addField('hash', Hidden::class, __('Hash'));
$this->addField('mtime', Hidden::class, '');
-
$this->addOwnerField(['column' => false]);
}
- protected function getData()
+ protected function _getData()
{
/** @var User $user */
$users = User::withoutGlobalScopes()->get();
foreach ($users as $user) {
$this->_listFilesOfUser($user->id, $files);
}
- usort($files, function ($a, $b) {
- return $a['mtime'] - $b['mtime'];
- });
- return array_values($files);
+ return $files;
}
protected function _listFilesOfUser($id, &$files)
return $this->___listFilesOfUser($id);
});
- foreach ($uFiles as $path => $uFile) {
- if (isset($files[$path])) {
+ foreach ($uFiles as $hash => $uFile) {
+ if (isset($files[$hash])) {
continue;
}
- $files[$path] = $uFile;
+ $files[$hash] = $uFile;
}
}
$date = new \DateTime();
$date->setTimestamp($mtime);
+ $hash = Files::hashFileAttributes($pathname);
- $res[$pathname] = [
+ $res[$hash] = [
'path' => $pathname,
'name' => $file->getFilename(),
'ext' => mb_strtolower($file->getExtension()),
'to' => $to,
'owner' => $id,
'mtime' => $mtime,
- 'hash' => Files::hashFileAttributes($pathname),
+ 'hash' => $hash,
];
}
return $res;
}
+ public function showPrimaryColumn()
+ {
+ return false;
+ }
+
public static function addOwnerClause(Builder $builder)
{
}
$builder->whereIn(static::$_ownerAttribute, backpack_user()->getManagedUsers());
}
+
+ public function getURL()
+ {
+ return config('url', 'https://toolbox.fluidbook.com') . '/file/' . $this->hash . '/' . $this->name;
+ }
}
"mxl/laravel-job": "^1.3",
"nyholm/psr7": "^1.5",
"php-ffmpeg/php-ffmpeg": "^0.18.0",
+ "rodneyrehm/plist": "^2.0",
"rustici-software/scormcloud-api-v2-client-php": "^2.0",
"symfony/http-client": "^v6.0"
},
"require-dev": {
"facade/ignition": "^2.17",
- "fzaninotto/faker": "^1.9",
"mockery/mockery": "^1.5",
"nunomaduro/collision": "^4.3",
"phpunit/phpunit": "^8.5",
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
- "sort-packages": true
+ "sort-packages": true,
+ "allow-plugins": {
+ "php-http/discovery": true
+ }
},
"extra": {
"laravel": {
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "3841d2420cde41846464f40adf52e325",
+ "content-hash": "9e1d830868759266a700df2a00576cf8",
"packages": [
{
"name": "ahmadshah/lucy",
"source": {
"type": "git",
"url": "git://git.cubedesigners.com/cubist_cms-back.git",
- "reference": "3cbabfd839e1ee1449dfe53050e2f5537d0dd7fd"
+ "reference": "541015ec6f5b6838d5ac59fbfef12aac086311e7"
},
"dist": {
"type": "tar",
- "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-37b21b.tar",
- "reference": "3cbabfd839e1ee1449dfe53050e2f5537d0dd7fd",
- "shasum": "a5d02527b1621e284024d141f3d71634cd90d7fb"
+ "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-0f74fc.tar",
+ "reference": "541015ec6f5b6838d5ac59fbfef12aac086311e7",
+ "shasum": "3adce0eeb2370518325f7ca2ab03f99d6d724267"
},
"require": {
"backpack/backupmanager": "^3.0",
}
],
"description": "Cubist Backpack extension",
- "time": "2023-02-15T09:41:45+00:00"
+ "time": "2023-02-15T15:17:43+00:00"
},
{
"name": "cubist/cms-front",
],
"time": "2022-02-11T10:27:51+00:00"
},
+ {
+ "name": "rodneyrehm/plist",
+ "version": "v2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/TECLIB/CFPropertyList.git",
+ "reference": "eb1f97cc44427359be9f09e617d68eef57707617"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/TECLIB/CFPropertyList/zipball/eb1f97cc44427359be9f09e617d68eef57707617",
+ "reference": "eb1f97cc44427359be9f09e617d68eef57707617",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.0",
+ "squizlabs/php_codesniffer": "^3.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "CFPropertyList\\": "src/CFPropertyList/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Kruse",
+ "email": "cjk@wwwtech.de",
+ "role": "developer"
+ },
+ {
+ "name": "Rodney Rehm",
+ "email": "mail+github@rodneyrehm.de",
+ "role": "developer"
+ },
+ {
+ "name": "Thierry Bugier",
+ "email": "tbugier@teclib.com",
+ "role": "developer"
+ }
+ ],
+ "description": "Library for reading and writing Apple's CFPropertyList (plist) files in XML as well as binary format.",
+ "homepage": "https://github.com/TECLIB/CFPropertyList",
+ "keywords": [
+ "CFPropertyList",
+ "Core Foundation",
+ "apple",
+ "binary",
+ "plist",
+ "xml"
+ ],
+ "support": {
+ "docs": "http://teclib.github.io/CFPropertyList/howtos/",
+ "email": "contact@teclib.com",
+ "issues": "https://github.com/TECLIB/CFPropertyList/issues",
+ "rss": "https://teclib.github.io/CFPropertyList/feed.xml",
+ "source": "https://github.com/TECLIB/CFPropertyList"
+ },
+ "time": "2021-12-01T18:24:28+00:00"
+ },
{
"name": "rustici-software/scormcloud-api-v2-client-php",
"version": "2.1.0",
],
"time": "2022-11-02T16:23:29+00:00"
},
- {
- "name": "fzaninotto/faker",
- "version": "v1.9.2",
- "source": {
- "type": "git",
- "url": "https://github.com/fzaninotto/Faker.git",
- "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/848d8125239d7dbf8ab25cb7f054f1a630e68c2e",
- "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e",
- "shasum": ""
- },
- "require": {
- "php": "^5.3.3 || ^7.0"
- },
- "require-dev": {
- "ext-intl": "*",
- "phpunit/phpunit": "^4.8.35 || ^5.7",
- "squizlabs/php_codesniffer": "^2.9.2"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.9-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Faker\\": "src/Faker/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "François Zaninotto"
- }
- ],
- "description": "Faker is a PHP library that generates fake data for you.",
- "keywords": [
- "data",
- "faker",
- "fixtures"
- ],
- "support": {
- "issues": "https://github.com/fzaninotto/Faker/issues",
- "source": "https://github.com/fzaninotto/Faker/tree/v1.9.2"
- },
- "abandoned": true,
- "time": "2020-12-11T09:56:16+00:00"
- },
{
"name": "hamcrest/hamcrest-php",
"version": "v2.0.1",
--- /dev/null
+<a class="btn btn-sm btn-link" download="{{$entry->name}}" href="{{$entry->getURL()}}"><i
+ class="la la-arrow-circle-down"></i> {{__('Télécharger')}}</a>
--- /dev/null
+@if($entry->ext==='apk')
+ <a class="btn btn-sm btn-link" download="{{$entry->name}}"
+ href="{{$entry->getURL()}}"><i class="las la-mobile"></i> {{__('Installer')}}</a>
+@elseif($entry->ext==='ipa')
+ <a class="btn btn-sm btn-link"
+ href="itms-services://?action=download-manifest&url={{urlencode($crud->route.'/'.$entry->hash.'/install')}}"><i
+ class="las la-mobile"></i> {{__('Installer')}}</a>
+@endif