浏览代码

Added export feature (closes #126)
Added copy mode option (closes #117)

Sergio Brighenti 5 年之前
父节点
当前提交
12179f1b06

+ 3 - 1
CHANGELOG.md

@@ -1,6 +1,8 @@
 ## v.3.1 (WIP)
-+ Updated system settings page.
++ The theme is now re-applied after every system update.
++ Added ability to choose between default and raw url on copy.
 + Added hide by default option.
++ Updated system settings page.
 + Updated translations.
 
 ## v.3.0.2

+ 3 - 0
app/Controllers/DashboardController.php

@@ -58,6 +58,8 @@ class DashboardController extends Controller
             ->search(param($request, 'search', null))
             ->run($page);
 
+        $copyUrl = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'copy_url_behavior\'')->fetch()->value;
+
         return view()->render(
             $response,
             ($this->session->get('admin', false) && $this->session->get('gallery_view', true)) ? 'dashboard/list.twig' : 'dashboard/grid.twig',
@@ -66,6 +68,7 @@ class DashboardController extends Controller
                 'next'         => $page < floor($query->getPages()),
                 'previous'     => $page >= 1,
                 'current_page' => ++$page,
+                'copy_url_behavior' => $copyUrl,
             ]
         );
     }

+ 50 - 0
app/Controllers/ExportController.php

@@ -0,0 +1,50 @@
+<?php
+
+
+namespace App\Controllers;
+
+
+use League\Flysystem\FileNotFoundException;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use ZipStream\Option\Archive;
+use ZipStream\ZipStream;
+
+class ExportController extends Controller
+{
+    /**
+     * @param  Request  $request
+     * @param  Response  $response
+     * @param  int|null  $id
+     * @return Response
+     * @throws \Slim\Exception\HttpNotFoundException
+     * @throws \Slim\Exception\HttpUnauthorizedException
+     * @throws \ZipStream\Exception\OverflowException
+     */
+    public function downloadData(Request $request, Response $response, int $id): Response
+    {
+        $user = $this->getUser($request, $id, true);
+
+        $medias = $this->database->query('SELECT `uploads`.`filename`, `uploads`.`storage_path` FROM `uploads` WHERE `user_id` = ?', $user->id);
+
+        set_time_limit(0);
+        ob_end_clean();
+
+        $options = new Archive();
+        $options->setSendHttpHeaders(true);
+
+        $zip = new ZipStream($user->username.'-'.time().'-export.zip', $options);
+
+        $filesystem = $this->storage;
+        foreach ($medias as $media) {
+            try {
+                $zip->addFileFromStream($media->filename, $filesystem->readStream($media->storage_path));
+            } catch (FileNotFoundException $e) {
+                $this->logger->error('Cannot export file', ['exception' => $e]);
+            }
+        }
+        $zip->finish();
+        exit(0);
+    }
+
+}

+ 3 - 0
app/Controllers/MediaController.php

@@ -66,11 +66,14 @@ class MediaController extends Controller
             throw new HttpNotFoundException($request);
         }
 
+        $copyUrl = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'copy_url_behavior\'')->fetch()->value;
+
         return view()->render($response, 'upload/public.twig', [
             'delete_token' => $token,
             'media' => $media,
             'type' => $type,
             'url' => urlFor("/{$userCode}/{$mediaCode}"),
+            'copy_url_behavior' => $copyUrl,
         ]);
     }
 

+ 80 - 0
app/Controllers/ProfileController.php

@@ -0,0 +1,80 @@
+<?php
+
+
+namespace App\Controllers;
+
+
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Slim\Exception\HttpNotFoundException;
+use Slim\Exception\HttpUnauthorizedException;
+
+class ProfileController extends Controller
+{
+    /**
+     * @param Request  $request
+     * @param Response $response
+     *
+     * @throws HttpNotFoundException
+     * @throws HttpUnauthorizedException
+     * @throws \Twig\Error\LoaderError
+     * @throws \Twig\Error\RuntimeError
+     * @throws \Twig\Error\SyntaxError
+     *
+     * @return Response
+     */
+    public function profile(Request $request, Response $response): Response
+    {
+        $user = $this->getUser($request, $this->session->get('user_id'), true);
+
+        return view()->render($response, 'user/edit.twig', [
+            'profile' => true,
+            'user'    => $user,
+        ]);
+    }
+
+    /**
+     * @param Request  $request
+     * @param Response $response
+     * @param int      $id
+     *
+     * @throws HttpNotFoundException
+     * @throws HttpUnauthorizedException
+     *
+     * @return Response
+     */
+    public function profileEdit(Request $request, Response $response, int $id): Response
+    {
+        if (param($request, 'email') === null) {
+            $this->session->alert(lang('email_required'), 'danger');
+
+            return redirect($response, route('profile'));
+        }
+
+        $user = $this->getUser($request, $id, true);
+
+        if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [param($request, 'email'), $user->email])->fetch()->count > 0) {
+            $this->session->alert(lang('email_taken'), 'danger');
+
+            return redirect($response, route('profile'));
+        }
+
+        if (param($request, 'password') !== null && !empty(param($request, 'password'))) {
+            $this->database->query('UPDATE `users` SET `email`=?, `password`=? WHERE `id` = ?', [
+                param($request, 'email'),
+                password_hash(param($request, 'password'), PASSWORD_DEFAULT),
+                $user->id,
+            ]);
+        } else {
+            $this->database->query('UPDATE `users` SET `email`=? WHERE `id` = ?', [
+                param($request, 'email'),
+                $user->id,
+            ]);
+        }
+
+        $this->session->alert(lang('profile_updated'), 'success');
+        $this->logger->info('User '.$this->session->get('username')." updated profile of $user->id.");
+
+        return redirect($response, route('profile'));
+    }
+}

+ 12 - 23
app/Controllers/SettingController.php

@@ -17,13 +17,13 @@ class SettingController extends Controller
      */
     public function saveSettings(Request $request, Response $response): Response
     {
-        $this->settingUpdate('register_enabled', param($request, 'register_enabled', 'off'));
-        $this->settingUpdate('hide_by_default', param($request, 'hide_by_default', 'off'));
-        $this->settingUpdate('copy_url_behavior', param($request, 'copy_url_behavior', 'off'));
+        $this->updateSetting('register_enabled', param($request, 'register_enabled', 'off'));
+        $this->updateSetting('hide_by_default', param($request, 'hide_by_default', 'off'));
+        $this->updateSetting('copy_url_behavior', param($request, 'copy_url_behavior') === null ? 'default' : 'raw');
 
         $this->applyTheme($request);
         $this->applyLang($request);
-        $this->saveCustomHead($request);
+        $this->updateSetting('custom_head', param($request, 'custom_head'));
 
         $this->session->alert(lang('settings_saved'));
 
@@ -36,28 +36,12 @@ class SettingController extends Controller
     public function applyLang(Request $request)
     {
         if (param($request, 'lang') !== 'auto') {
-            if (!$this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'lang\'')->fetch()) {
-                $this->database->query('INSERT INTO `settings`(`key`, `value`) VALUES (\'lang\', ?)', param($request, 'lang'));
-            } else {
-                $this->database->query('UPDATE `settings` SET `value`=? WHERE `key` = \'lang\'', param($request, 'lang'));
-            }
+            $this->updateSetting('copy_url_behavior', param($request, 'lang'));
         } else {
             $this->database->query('DELETE FROM `settings` WHERE `key` = \'lang\'');
         }
     }
 
-    /**
-     * @param  Request  $request
-     */
-    public function saveCustomHead(Request $request)
-    {
-        if ($request->getAttribute('custom_head_key_present')) {
-            $this->database->query('UPDATE `settings` SET `value`=? WHERE `key` = \'custom_head\'', param($request, 'custom_head'));
-        } else {
-            $this->database->query('INSERT INTO `settings`(`key`, `value`) VALUES (\'custom_head\', ?)', param($request, 'custom_head'));
-        }
-    }
-
 
     /**
      * @param  Request  $request
@@ -72,7 +56,12 @@ class SettingController extends Controller
                 file_put_contents(BASE_DIR.'static/bootstrap/css/bootstrap.min.css', file_get_contents(param($request, 'css')));
             }
 
-            $this->settingUpdate('css', param($request, 'css'));
+            // if is default, remove setting
+            if (param($request, 'css') !== 'https://bootswatch.com/_vendor/bootstrap/dist/css/bootstrap.min.css'){
+                $this->updateSetting('css', param($request, 'css'));
+            } else {
+                $this->database->query('DELETE FROM `settings` WHERE `key` = \'css\'');
+            }
         }
     }
 
@@ -80,7 +69,7 @@ class SettingController extends Controller
      * @param $key
      * @param  null  $value
      */
-    private function settingUpdate($key, $value = null)
+    private function updateSetting($key, $value = null)
     {
         if (!$this->database->query('SELECT `value` FROM `settings` WHERE `key` = '.$this->database->getPdo()->quote($key))->fetch()) {
             $this->database->query('INSERT INTO `settings`(`key`, `value`) VALUES ('.$this->database->getPdo()->quote($key).', ?)', $value);

+ 0 - 67
app/Controllers/UserController.php

@@ -237,73 +237,6 @@ class UserController extends Controller
         return redirect($response, route('user.index'));
     }
 
-    /**
-     * @param Request  $request
-     * @param Response $response
-     *
-     * @throws HttpNotFoundException
-     * @throws HttpUnauthorizedException
-     * @throws \Twig\Error\LoaderError
-     * @throws \Twig\Error\RuntimeError
-     * @throws \Twig\Error\SyntaxError
-     *
-     * @return Response
-     */
-    public function profile(Request $request, Response $response): Response
-    {
-        $user = $this->getUser($request, $this->session->get('user_id'), true);
-
-        return view()->render($response, 'user/edit.twig', [
-            'profile' => true,
-            'user'    => $user,
-        ]);
-    }
-
-    /**
-     * @param Request  $request
-     * @param Response $response
-     * @param int      $id
-     *
-     * @throws HttpNotFoundException
-     * @throws HttpUnauthorizedException
-     *
-     * @return Response
-     */
-    public function profileEdit(Request $request, Response $response, int $id): Response
-    {
-        if (param($request, 'email') === null) {
-            $this->session->alert(lang('email_required'), 'danger');
-
-            return redirect($response, route('profile'));
-        }
-
-        $user = $this->getUser($request, $id, true);
-
-        if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [param($request, 'email'), $user->email])->fetch()->count > 0) {
-            $this->session->alert(lang('email_taken'), 'danger');
-
-            return redirect($response, route('profile'));
-        }
-
-        if (param($request, 'password') !== null && !empty(param($request, 'password'))) {
-            $this->database->query('UPDATE `users` SET `email`=?, `password`=? WHERE `id` = ?', [
-                param($request, 'email'),
-                password_hash(param($request, 'password'), PASSWORD_DEFAULT),
-                $user->id,
-            ]);
-        } else {
-            $this->database->query('UPDATE `users` SET `email`=? WHERE `id` = ?', [
-                param($request, 'email'),
-                $user->id,
-            ]);
-        }
-
-        $this->session->alert(lang('profile_updated'), 'success');
-        $this->logger->info('User '.$this->session->get('username')." updated profile of $user->id.");
-
-        return redirect($response, route('profile'));
-    }
-
     /**
      * @param Request  $request
      * @param Response $response

+ 1 - 1
app/Middleware/InjectMiddleware.php

@@ -19,6 +19,6 @@ class InjectMiddleware extends Middleware
         $head = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'custom_head\'')->fetch();
         $this->view->getTwig()->addGlobal('customHead', $head->value ?? null);
 
-        return $handler->handle($request->withAttribute('custom_head_key_present', isset($head->value)));
+        return $handler->handle($request);
     }
 }

+ 6 - 2
app/routes.php

@@ -4,8 +4,10 @@
 use App\Controllers\AdminController;
 use App\Controllers\ClientController;
 use App\Controllers\DashboardController;
+use App\Controllers\ExportController;
 use App\Controllers\LoginController;
 use App\Controllers\MediaController;
+use App\Controllers\ProfileController;
 use App\Controllers\SettingController;
 use App\Controllers\ThemeController;
 use App\Controllers\UpgradeController;
@@ -46,12 +48,14 @@ $app->group('', function (RouteCollectorProxy $group) {
         $group->get('/{id}/delete', [UserController::class, 'delete'])->setName('user.delete');
     })->add(AdminMiddleware::class);
 
-    $group->get('/profile', [UserController::class, 'profile'])->setName('profile');
-    $group->post('/profile/{id}', [UserController::class, 'profileEdit'])->setName('profile.update');
+    $group->get('/profile', [ProfileController::class, 'profile'])->setName('profile');
+    $group->post('/profile/{id}', [ProfileController::class, 'profileEdit'])->setName('profile.update');
     $group->post('/user/{id}/refreshToken', [UserController::class, 'refreshToken'])->setName('refreshToken');
     $group->get('/user/{id}/config/sharex', [ClientController::class, 'getShareXConfig'])->setName('config.sharex');
     $group->get('/user/{id}/config/script', [ClientController::class, 'getBashScript'])->setName('config.script');
 
+    $group->get('/user/{id}/export', [ExportController::class, 'downloadData'])->setName('export.data');
+
     $group->post('/upload/{id}/publish', [MediaController::class, 'togglePublish'])->setName('upload.publish');
     $group->post('/upload/{id}/unpublish', [MediaController::class, 'togglePublish'])->setName('upload.unpublish');
     $group->get('/upload/{id}/raw', [MediaController::class, 'getRawById'])->add(AdminMiddleware::class)->setName('upload.raw');

+ 8 - 8
composer.json

@@ -5,23 +5,23 @@
   "type": "project",
   "require": {
     "php": ">=7.1",
+    "ext-gd": "*",
     "ext-intl": "*",
     "ext-json": "*",
-    "ext-gd": "*",
     "ext-pdo": "*",
     "ext-zip": "*",
-    "slim/slim": "^4.0",
-    "php-di/slim-bridge": "^3.0",
-    "twig/twig": "^2.12",
     "guzzlehttp/psr7": "^1.6",
-    "league/flysystem": "^1.0.45",
-    "monolog/monolog": "^1.23",
+    "http-interop/http-factory-guzzle": "^1.0",
     "intervention/image": "^2.4",
+    "league/flysystem": "^1.0.45",
     "league/flysystem-aws-s3-v3": "^1.0",
+    "maennchen/zipstream-php": "^2.0",
+    "monolog/monolog": "^1.23",
+    "php-di/slim-bridge": "^3.0",
+    "slim/slim": "^4.0",
     "spatie/flysystem-dropbox": "^1.0",
     "superbalist/flysystem-google-storage": "^7.2",
-    "http-interop/http-factory-guzzle": "^1.0"
-
+    "twig/twig": "^2.12"
   },
   "config": {
     "optimize-autoloader": true,

+ 109 - 2
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "9e8abd66e7b27ece61e41aae2cc27114",
+    "content-hash": "17be54724e0928ed7049b18bbcb181b9",
     "packages": [
         {
             "name": "aws/aws-sdk-php",
@@ -894,6 +894,67 @@
             "description": "Flysystem adapter for the AWS S3 SDK v3.x",
             "time": "2020-02-23T13:31:58+00:00"
         },
+        {
+            "name": "maennchen/zipstream-php",
+            "version": "2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/maennchen/ZipStream-PHP.git",
+                "reference": "9ceee828f9620b2e5c075e551ec7ed8a7035ac95"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/9ceee828f9620b2e5c075e551ec7ed8a7035ac95",
+                "reference": "9ceee828f9620b2e5c075e551ec7ed8a7035ac95",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "myclabs/php-enum": "^1.5",
+                "php": ">= 7.1",
+                "psr/http-message": "^1.0"
+            },
+            "require-dev": {
+                "ext-zip": "*",
+                "guzzlehttp/guzzle": ">= 6.3",
+                "mikey179/vfsstream": "^1.6",
+                "phpunit/phpunit": ">= 7.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ZipStream\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paul Duncan",
+                    "email": "pabs@pablotron.org"
+                },
+                {
+                    "name": "Jonatan Männchen",
+                    "email": "jonatan@maennchen.ch"
+                },
+                {
+                    "name": "Jesse Donat",
+                    "email": "donatj@gmail.com"
+                },
+                {
+                    "name": "András Kolesár",
+                    "email": "kolesar@kolesar.hu"
+                }
+            ],
+            "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
+            "keywords": [
+                "stream",
+                "zip"
+            ],
+            "time": "2020-02-23T01:48:39+00:00"
+        },
         {
             "name": "monolog/monolog",
             "version": "1.25.3",
@@ -1029,6 +1090,52 @@
             ],
             "time": "2019-12-30T18:03:34+00:00"
         },
+        {
+            "name": "myclabs/php-enum",
+            "version": "1.7.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/php-enum.git",
+                "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/5f36467c7a87e20fbdc51e524fd8f9d1de80187c",
+                "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7",
+                "squizlabs/php_codesniffer": "1.*",
+                "vimeo/psalm": "^3.8"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MyCLabs\\Enum\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP Enum contributors",
+                    "homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
+                }
+            ],
+            "description": "PHP Enum implementation",
+            "homepage": "http://github.com/myclabs/php-enum",
+            "keywords": [
+                "enum"
+            ],
+            "time": "2020-02-14T08:15:52+00:00"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
@@ -3326,9 +3433,9 @@
     "prefer-lowest": false,
     "platform": {
         "php": ">=7.1",
+        "ext-gd": "*",
         "ext-intl": "*",
         "ext-json": "*",
-        "ext-gd": "*",
         "ext-pdo": "*",
         "ext-zip": "*"
     },

+ 6 - 0
install/index.php

@@ -217,6 +217,12 @@ $app->post('/', function (Request $request, Response $response, Filesystem $stor
         return redirect($response, '/install');
     }
 
+    // re-apply the previous theme if is present
+    $css = $db->query('SELECT `value` FROM `settings` WHERE `key` = \'css\'')->fetch()->value;
+    if ($css) {
+        file_put_contents(BASE_DIR.'static/bootstrap/css/bootstrap.min.css', file_get_contents($css));
+    }
+
     // post install cleanup
     cleanDirectory(__DIR__.'/../resources/cache');
     cleanDirectory(__DIR__.'/../resources/sessions');

+ 1 - 0
resources/lang/en.lang.php

@@ -115,4 +115,5 @@ return [
     'hide_by_default'              => 'Hide uploads by default',
     'copy_url_behavior'              => 'Copy URL mode',
     'settings_saved'              => 'System settings saved!',
+    'export_data' => 'Export Data'
 ];

+ 1 - 1
resources/templates/dashboard/grid.twig

@@ -23,7 +23,7 @@
                                         <div class="col-12">
                                             <span class="badge badge-dark shadow-lg">{{ media.size }}</span>
                                             <div class="btn-group shadow-lg float-right">
-                                                <button type="button" class="btn btn-sm btn-success btn-clipboard" data-toggle="tooltip" title="{{ lang('copy_link') }}" data-clipboard-text="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension) }}">
+                                                <button type="button" class="btn btn-sm btn-success btn-clipboard" data-toggle="tooltip" title="{{ lang('copy_link') }}" data-clipboard-text="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension) }}{{ copy_url_behavior == 'raw' ? '/raw' }}">
                                                     <i class="fas fa-link"></i>
                                                 </button>
                                                 <a href="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension ~ '/download') }}" class="btn btn-sm btn-secondary" data-toggle="tooltip" title="{{ lang('download') }}"><i class="fas fa-cloud-download-alt"></i></a>

+ 1 - 1
resources/templates/dashboard/list.twig

@@ -56,7 +56,7 @@
                                                     {% if media.username is not null %}
                                                         <a href="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension) }}" class="btn btn-sm btn-outline-secondary" data-toggle="tooltip" title="{{ lang('open') }}" target="_blank"><i class="fas fa-external-link-alt"></i></a>
                                                         <a href="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension ~ '/download') }}" class="btn btn-sm btn-outline-primary" data-toggle="tooltip" title="{{ lang('download') }}"><i class="fas fa-cloud-download-alt"></i></a>
-                                                        <a href="javascript:void(0)" class="btn btn-sm btn-outline-success btn-clipboard" data-toggle="tooltip" title="{{ lang('copy_link') }}" data-clipboard-text="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension) }}"><i class="fas fa-link"></i></a>
+                                                        <a href="javascript:void(0)" class="btn btn-sm btn-outline-success btn-clipboard" data-toggle="tooltip" title="{{ lang('copy_link') }}" data-clipboard-text="{{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension) }}{{ copy_url_behavior == 'raw' ? '/raw' }}"><i class="fas fa-link"></i></a>
                                                     {% else %}
                                                         <a href="{{ route('upload.raw', {'id': media.id}) }}" class="btn btn-sm btn-outline-dark" data-toggle="tooltip" title="{{ lang('raw') }}" target="_blank"><i class="fas fa-external-link-alt"></i></a>
                                                     {% endif %}

+ 1 - 1
resources/templates/dashboard/system.twig

@@ -77,7 +77,7 @@
                             <div class="form-group row">
                                 <label for="custom_head" class="col-sm-4 col-form-label">{{ lang('copy_url_behavior') }}</label>
                                 <div class="col-sm-8">
-                                    <input type="checkbox" name="copy_url_behavior" data-toggle="toggle" data-off="Default URL" data-on="Raw URL" data-onstyle="primary" data-offstyle="secondary" {{ copy_url_behavior == 'on' ? 'checked' }}>
+                                    <input type="checkbox" name="copy_url_behavior" data-toggle="toggle" data-off="Default URL" data-on="Raw URL" data-onstyle="primary" data-offstyle="secondary" {{ copy_url_behavior == 'raw' ? 'checked' }}>
                                 </div>
                             </div>
 

+ 1 - 1
resources/templates/upload/public.twig

@@ -17,7 +17,7 @@
             </button>
             <div class="collapse navbar-collapse" id="navbarCollapse">
                 <div class="ml-auto">
-                    <a href="javascript:void(0)" class="btn btn-success my-2 my-sm-0 btn-clipboard" data-toggle="tooltip" title="{{ lang('copy_link') }}" data-clipboard-text="{{ url }}"><i class="fas fa-link fa-lg fa-fw"></i></a>
+                    <a href="javascript:void(0)" class="btn btn-success my-2 my-sm-0 btn-clipboard" data-toggle="tooltip" title="{{ lang('copy_link') }}" data-clipboard-text="{{ url }}{{ copy_url_behavior == 'raw' ? '/raw' }}"><i class="fas fa-link fa-lg fa-fw"></i></a>
                     <a href="javascript:void(0)" class="btn btn-info my-2 my-sm-0" data-toggle="tooltip" title="{{ lang('public.telegram') }}" onclick="$('#modalTelegramShare').modal('toggle')"><i class="fab fa-telegram-plane fa-lg fa-fw"></i></a>
                     <a href="{{ url }}/raw" class="btn btn-secondary my-2 my-sm-0" data-toggle="tooltip" title="{{ lang('raw') }}"><i class="fas fa-file-alt fa-lg fa-fw"></i></a>
                     <a href="{{ url }}/download" class="btn btn-warning my-2 my-sm-0" data-toggle="tooltip" title="{{ lang('download') }}"><i class="fas fa-cloud-download-alt fa-lg fa-fw"></i></a>

+ 8 - 0
resources/templates/user/edit.twig

@@ -57,6 +57,14 @@
                                     </div>
                                 </div>
                             </div>
+                            <div class="form-group row">
+                                <label class="col-sm-2 col-form-label">{{ lang('export_data') }}</label>
+                                <div class="col-sm-10">
+                                    <div class="btn-group">
+                                        <a href="{{ route('export.data', {'id': user.id}) }}" class="btn btn-lg btn-outline-warning"><i class="fas fa-fw fa-file-archive"></i> {{ lang('download') }}</a>
+                                    </div>
+                                </div>
+                            </div>
                             {% if not profile %}
                                 <div class="form-group row">
                                     <div class="col-sm-2"></div>