Przeglądaj źródła

Merge pull request #91 from merumelu/psr1_2

Use four spaces for indetation and follow PSR-1 and PSR-2
Rémi Verschelde 8 lat temu
rodzic
commit
a9e8ef3832

+ 1 - 1
api/index.php

@@ -31,7 +31,7 @@ require __DIR__ . '/../src/middleware.php';
 
 // Register routes
 
-foreach(glob(__DIR__ . "/../src/routes/*.php") as $filename) {
+foreach (glob(__DIR__ . "/../src/routes/*.php") as $filename) {
     require $filename;
 }
 

+ 52 - 0
src/Helpers/Tokens.php

@@ -0,0 +1,52 @@
+<?php
+// Token format: <base64-encoded json-encoded data>&<base64-encoded id (composed of raw random bytes)>|<base64-encoded time>&<base64-encoded hmac>
+
+namespace Godot\AssetLibrary\Helpers;
+
+class Tokens
+{
+    private $c;
+
+    public function __construct($c)
+    {
+        $this->c = $c;
+    }
+
+    private function signToken($token)
+    {
+        return hash_hmac('sha256', $token, $this->c->settings['auth']['secret'], true);
+    }
+
+    public function generate($data)
+    {
+        $token_data = json_encode($data);
+
+        $token_id = openssl_random_pseudo_bytes(8);
+        $token_time = time();
+
+        $token_payload = base64_encode($token_data) . '&' . base64_encode($token_id) . '|' . base64_encode($token_time);
+        $token = $token_payload . '&' . base64_encode($this->signToken($token_payload));
+
+        return $token;
+    }
+
+    public function validate($token)
+    {
+        $token_parts = explode('&', $token);
+        if (count($token_parts) != 3) {
+            return false;
+        }
+
+        $token_data = json_decode(base64_decode($token_parts[0]));
+        $token_time = base64_decode(explode('|', $token_parts[1])[1]);
+        $token_signature = base64_decode($token_parts[2]);
+
+        $token_payload = $token_parts[0] . '&' . $token_parts[1];
+
+        if ($token_signature !== $this->signToken($token_payload) || time() > $token_time + $this->c->settings['auth']['tokenExpirationTime']) {
+            return false;
+        }
+
+        return $token_data;
+    }
+}

+ 189 - 0
src/Helpers/Utils.php

@@ -0,0 +1,189 @@
+<?php
+
+namespace Godot\AssetLibrary\Helpers;
+
+class Utils
+{
+    private $c;
+
+    public function __construct($c)
+    {
+        $this->c = $c;
+    }
+
+    public function getComputedDownloadUrl($repo_url, $provider, $commit, &$warning=null) // i.e. browse_url, download_provider, download_commit
+    {
+        $repo_url = rtrim($repo_url, '/');
+        if (is_int($provider)) {
+            $provider = $this->c->constants['download_provider'][$provider];
+        }
+        $warning_suffix = "Please, ensure that the URL and the repository provider are, indeed, correct.";
+        $light_warning_suffix = "Please, doublecheck that the URL and the repository provider are correct.";
+        switch ($provider) {
+            case 'GitHub':
+                if (sizeof(preg_grep('/^https:\/\/github\.com\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
+                    $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"https://github.com/<owner>/<name>\". $warning_suffix";
+                }
+                return "$repo_url/archive/$commit.zip";
+            case 'GitLab':
+                if (sizeof(preg_grep('/^https:\/\/(gitlab\.com|[^\/]+)\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
+                    $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"https://<gitlab instance>/<owner>/<name>\". $warning_suffix";
+                } elseif (sizeof(preg_grep('/^https:\/\/(gitlab\.com)\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
+                    $warning = "\"$repo_url\" might not be correct; it should be similar to \"https://gitlab.com/<owner>/<name>\", unless the asset is hosted on a custom instance of GitLab. $light_warning_suffix";
+                }
+                return "$repo_url/repository/archive.zip?ref=$commit";
+            case 'BitBucket':
+                if (sizeof(preg_grep('/^https:\/\/bitbucket\.org\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
+                    $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"https://bitbucket.org/<owner>/<name>\". $warning_suffix";
+                }
+                return "$repo_url/get/$commit.zip";
+            case 'Gogs':
+                if (sizeof(preg_grep('/^https?:\/\/[^\/]+?\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
+                    $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"http<s>://<gogs instance>/<owner>/<name>\". $warning_suffix";
+                }
+                $warning = "Since Gogs might be self-hosted, we can't be sure that \"$repo_url\" is a valid Gogs URL. $light_warning_suffix";
+                return "$repo_url/archive/$commit.zip";
+            case 'cgit':
+                if (sizeof(preg_grep('/^https?:\/\/[^\/]+?\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
+                    $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"http<s>://<cgit instance>/<owner>/<name>\". $warning_suffix";
+                }
+                $warning = "Since cgit might be self-hosted, we can't be sure that \"$repo_url\" is a valid cgit URL. $light_warning_suffix";
+                return "$repo_url/snapshot/$commit.zip";
+            default:
+                return "$repo_url/$commit.zip"; // Obviously incorrect, but we would like to have some default case...
+        }
+    }
+
+    public function getDefaultIssuesUrl($repo_url, $provider) // i.e. browse_url, download_provider
+    {
+        $repo_url = rtrim($repo_url, '/');
+        if (is_int($provider)) {
+            $provider = $this->c->constants['download_provider'][$provider];
+        }
+        switch ($provider) {
+            case 'GitHub':
+            case 'GitLab':
+            case 'BitBucket':
+            case 'Gogs':
+                return "$repo_url/issues";
+            case 'cgit':
+            default:
+                return "";
+        }
+    }
+
+    public function errorResponseIfNotUserHasLevel($currentStatus, &$response, $user, $required_level_name, $message = 'You are not authorized to do this')
+    {
+        if ($user === false || $currentStatus) {
+            return true;
+        }
+
+        if ((int) $user['type'] < $this->c->constants['user_type'][$required_level_name]) {
+            $response = $response->withJson([
+                'error' => $message,
+            ], 403);
+            return true;
+        }
+        return false;
+    }
+
+    public function errorResponseIfMissingOrNotString($currentStatus, &$response, $object, $property)
+    {
+        if ($currentStatus) {
+            return true;
+        }
+
+        if (!isset($object[$property]) || !is_string($object[$property]) || $object[$property] == "") {
+            $response = $response->withJson([
+                'error' => $property . ' is required, and must be a string'
+            ], 400);
+            return true;
+        }
+        return false;
+    }
+
+    public function errorResponseIfQueryBad($currentStatus, &$response, $query, $message = 'An error occured while executing DB queries')
+    {
+        if ($currentStatus) {
+            return true;
+        }
+
+        if ($query->errorCode() != '00000') {
+            $this->c->logger->error('DBError', $query->errorInfo());
+            $response = $response->withJson([
+                'error' => $message,
+            ], 500);
+            return true;
+        }
+        return false;
+    }
+
+    public function errorResponseIfQueryNoResults($currentStatus, &$response, $query, $message = 'DB returned no results')
+    {
+        if ($currentStatus) {
+            return true;
+        }
+
+        if ($query->rowCount() == 0) {
+            $response = $response->withJson([
+                'error' => $message
+            ], 404);
+            return true;
+        }
+        return false;
+    }
+
+    public function ensureLoggedIn($currentStatus, &$response, $body, &$user, &$token_data = null, $reset = false)
+    {
+        $currentStatus = $this->errorResponseIfMissingOrNotString($currentStatus, $response, $body, 'token');
+        if ($currentStatus) {
+            return true;
+        }
+
+        $token_data = $this->c->tokens->validate($body['token']);
+        $error = $this->getUserFromTokenData(false, $response, $token_data, $user, $reset);
+        return $error;
+    }
+
+    public function getUserFromTokenData($currentStatus, &$response, $token_data, &$user, $reset = false)
+    {
+        if ($currentStatus) {
+            return true;
+        }
+        if (!$token_data) {
+            $response = $response->withJson([
+                'error' => 'Invalid token'
+            ], 403);
+            return true;
+        }
+
+        // Insecure
+        // if(isset($token_data->user_id)) {
+        //   $query = $this->c->queries['user']['get_one'];
+        //   $query->bindValue(':id', (int) $token_data->user_id, PDO::PARAM_INT);
+        // }
+        if (isset($token_data->session) && !$reset) {
+            $query = $this->c->queries['user']['get_by_session_token'];
+            $query->bindValue(":session_token", base64_decode($token_data->session));
+        } elseif (isset($token_data->reset) && $reset) {
+            $query = $this->c->queries['user']['get_by_reset_token'];
+            $query->bindValue(":reset_token", base64_decode($token_data->reset));
+        } else {
+            $response = $response->withJson([
+                'error' => 'Invalid token'
+            ], 403);
+            return true;
+        }
+
+        $query->execute();
+
+        $currentStatus = $this->errorResponseIfQueryBad(false, $response, $query);
+        $currentStatus = $this->errorResponseIfQueryNoResults($currentStatus, $response, $query, 'Nonexistent token submitted');
+        if ($currentStatus) {
+            return true;
+        }
+
+        $user = $query->fetchAll()[0];
+        return false;
+    }
+}

+ 48 - 48
src/constants.php

@@ -2,54 +2,54 @@
 
 function double_map($array)
 {
-  foreach ($array as $key => $value) {
-    $array[(string) $value] = $key;
-    $array[$value] = $key;
-  }
-  return $array;
+    foreach ($array as $key => $value) {
+        $array[(string) $value] = $key;
+        $array[$value] = $key;
+    }
+    return $array;
 }
 
 return $constants = [
-  'edit_status' => double_map([
-    'new' => 0,
-    'in_review' => 1,
-    'accepted' => 2,
-    'rejected' => 3,
-  ]),
-  'edit_preview_operation' => double_map([
-    'insert' => 0,
-    'remove' => 1,
-    'update' => 2,
-  ]),
-  'category_type' => double_map([
-    'addon' => 0,
-    'project' => 1,
-    'any' => '%',
-  ]),
-  'support_level' => double_map([
-    'testing' => 0,
-    'community' => 1,
-    'official' => 2,
-  ]),
-  'user_type' => double_map([
-    'normal' => 0,
-    'editor' => 25,
-    'moderator' => 50,
-    'admin' => 100,
-  ]),
-  'download_provider' => double_map([
-    'GitHub' => 0,
-    'GitLab' => 1,
-    'BitBucket' => 2,
-    'Gogs' => 3,
-    'cgit' => 4,
-  ]),
-  'asset_edit_fields' => [
-    'title', 'description', 'category_id',
-    'version_string', 'cost',
-    'download_provider', 'download_commit', 'browse_url', 'issues_url', 'icon_url',
-  ],
-  'asset_edit_preview_fields' => [
-    'type', 'link', 'thumbnail',
-  ]
-];
+    'edit_status' => double_map([
+        'new' => 0,
+        'in_review' => 1,
+        'accepted' => 2,
+        'rejected' => 3,
+    ]),
+    'edit_preview_operation' => double_map([
+        'insert' => 0,
+        'remove' => 1,
+        'update' => 2,
+    ]),
+    'category_type' => double_map([
+        'addon' => 0,
+        'project' => 1,
+        'any' => '%',
+    ]),
+    'support_level' => double_map([
+        'testing' => 0,
+        'community' => 1,
+        'official' => 2,
+    ]),
+    'user_type' => double_map([
+        'normal' => 0,
+        'editor' => 25,
+        'moderator' => 50,
+        'admin' => 100,
+    ]),
+    'download_provider' => double_map([
+        'GitHub' => 0,
+        'GitLab' => 1,
+        'BitBucket' => 2,
+        'Gogs' => 3,
+        'cgit' => 4,
+    ]),
+    'asset_edit_fields' => [
+        'title', 'description', 'category_id',
+        'version_string', 'cost',
+        'download_provider', 'download_commit', 'browse_url', 'issues_url', 'icon_url',
+    ],
+    'asset_edit_preview_fields' => [
+        'type', 'link', 'thumbnail',
+    ]
+];

+ 61 - 57
src/dependencies.php

@@ -5,100 +5,104 @@ $container = $app->getContainer();
 
 // view renderer
 $container['renderer'] = function ($c) {
-  $settings = $c->get('settings')['renderer'];
-  return new Slim\Views\PhpRenderer($settings['template_path']);
+    $settings = $c->get('settings')['renderer'];
+    return new Slim\Views\PhpRenderer($settings['template_path']);
 };
 
 // monolog
 $container['logger'] = function ($c) {
-  $settings = $c->get('settings')['logger'];
-  $logger = new Monolog\Logger($settings['name']);
-  $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-  $logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], Monolog\Logger::DEBUG));
-  return $logger;
+    $settings = $c->get('settings')['logger'];
+    $logger = new Monolog\Logger($settings['name']);
+    $logger->pushProcessor(new Monolog\Processor\UidProcessor());
+    $logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], Monolog\Logger::DEBUG));
+    return $logger;
 };
 
 // pdo
 $container['db'] = function ($c) {
-  $settings = $c->get('settings')['db'];
-  $db = new PDO($settings['dsn'], $settings['user'], $settings['pass']);
-  $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
-  return $db;
+    $settings = $c->get('settings')['db'];
+    $db = new PDO($settings['dsn'], $settings['user'], $settings['pass']);
+    $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
+    return $db;
 };
 
 // constants
 $container['constants'] = function ($c) {
-  return require_once __DIR__ . '/constants.php';
+    return require_once __DIR__ . '/constants.php';
 };
 
 // queries
 $container['queries'] = function ($c) {
-  $db = $c->db;
+    $db = $c->db;
 
-  $raw_queries = require_once __DIR__ . '/queries.php';
-  $queries = [];
-  foreach ($raw_queries as $model => $model_queries) {
-    $queries[$model] = [];
-    foreach ($model_queries as $query_name => $query) {
-      $queries[$model][$query_name] = $db->prepare($query);
+    $raw_queries = require_once __DIR__ . '/queries.php';
+    $queries = [];
+    foreach ($raw_queries as $model => $model_queries) {
+        $queries[$model] = [];
+        foreach ($model_queries as $query_name => $query) {
+            $queries[$model][$query_name] = $db->prepare($query);
+        }
     }
-  }
-  return $queries;
+    return $queries;
 };
 
 // mail
 $container['mail'] = function ($c) {
-  return function() use ($c) {
-    $settings = $c->get('settings')['mail'];
-    $mail = new PHPMailer;
-    $mail->setFrom($settings['from']);
-    if(isset($settings['replyTo'])) {
-      $mail->addReplyTo($settings['replyTo']);
-    }
-    if(isset($settings['smtp'])) {
-      $mail->isSMTP();
-      $mail->Host = $settings['smtp']['host'];
-      $mail->Port = $settings['smtp']['port'];
-      if(isset($settings['smtp']['auth'])) {
-        $mail->SMTPAuth = true;
-        $mail->Username = $settings['smtp']['auth']['user'];
-        $mail->Password = $settings['smtp']['auth']['pass'];
-        if($settings['smtp']['secure']) {
-          $mail->SMTPSecure = $settings['smtp']['secure'];
+    return function () use ($c) {
+        $settings = $c->get('settings')['mail'];
+        $mail = new PHPMailer;
+        $mail->setFrom($settings['from']);
+        if (isset($settings['replyTo'])) {
+            $mail->addReplyTo($settings['replyTo']);
         }
-      } else {
-        $mail->SMTPAuth = true;
-      }
-    }
-    return $mail;
-  };
+        if (isset($settings['smtp'])) {
+            $mail->isSMTP();
+            $mail->Host = $settings['smtp']['host'];
+            $mail->Port = $settings['smtp']['port'];
+            if (isset($settings['smtp']['auth'])) {
+                $mail->SMTPAuth = true;
+                $mail->Username = $settings['smtp']['auth']['user'];
+                $mail->Password = $settings['smtp']['auth']['pass'];
+                if ($settings['smtp']['secure']) {
+                    $mail->SMTPSecure = $settings['smtp']['secure'];
+                }
+            } else {
+                $mail->SMTPAuth = true;
+            }
+        }
+        return $mail;
+    };
 };
 
 // csrf guard
 $container['csrf'] = function ($c) {
-  session_name('assetlib-csrf');
-  session_start();
-  return new \Slim\Csrf\Guard;
+    session_name('assetlib-csrf');
+    session_start();
+    return new \Slim\Csrf\Guard;
 };
 
 // cookies
 $container['cookies'] = function ($c) {
-  return [
-    'cookie' => function($name, $value) {return Dflydev\FigCookies\Cookie::create($name, $value);},
-    'setCookie' => function($name) {return Dflydev\FigCookies\SetCookie::create($name);},
-    'requestCookies' => new Dflydev\FigCookies\FigRequestCookies,
-    'responseCookies' => new Dflydev\FigCookies\FigResponseCookies,
-  ];
+    return [
+        'cookie' => function ($name, $value) {
+            return Dflydev\FigCookies\Cookie::create($name, $value);
+        },
+        'setCookie' => function ($name) {
+            return Dflydev\FigCookies\SetCookie::create($name);
+        },
+        'requestCookies' => new Dflydev\FigCookies\FigRequestCookies,
+        'responseCookies' => new Dflydev\FigCookies\FigResponseCookies,
+    ];
 };
 
 // tokens
 $container['tokens'] = function ($c) {
-  require_once __DIR__ . '/helpers/tokens.php';
-  return new Tokens($c);
+    require_once __DIR__ . '/Helpers/Tokens.php';
+    return new Godot\AssetLibrary\Helpers\Tokens($c);
 };
 
 // utils
 $container['utils'] = function ($c) {
-  require_once __DIR__ . '/helpers/utils.php';
-  return new Utils($c);
+    require_once __DIR__ . '/Helpers/Utils.php';
+    return new Godot\AssetLibrary\Helpers\Utils($c);
 };

+ 0 - 49
src/helpers/tokens.php

@@ -1,49 +0,0 @@
-<?php
-// Token format: <base64-encoded json-encoded data>&<base64-encoded id (composed of raw random bytes)>|<base64-encoded time>&<base64-encoded hmac>
-
-class Tokens
-{
-  var $c;
-  public function __construct($c)
-  {
-    $this->c = $c;
-  }
-
-  function sign_token($token) {
-    return hash_hmac('sha256', $token, $this->c->settings['auth']['secret'], true);
-  }
-
-  public function generate($data)
-  {
-    $token_data = json_encode($data);
-
-    $token_id = openssl_random_pseudo_bytes(8);
-    $token_time = time();
-
-    $token_payload = base64_encode($token_data) . '&' . base64_encode($token_id) . '|' . base64_encode($token_time);
-    $token = $token_payload . '&' . base64_encode($this->sign_token($token_payload));
-
-    return $token;
-  }
-
-  public function validate($token)
-  {
-    $token_parts = explode('&', $token);
-    if(count($token_parts) != 3) {
-      return false;
-    }
-
-    $token_data = json_decode(base64_decode($token_parts[0]));
-    $token_time = base64_decode(explode('|', $token_parts[1])[1]);
-    $token_signature = base64_decode($token_parts[2]);
-
-    $token_payload = $token_parts[0] . '&' . $token_parts[1];
-
-    if($token_signature !== $this->sign_token($token_payload) || time() > $token_time + $this->c->settings['auth']['tokenExpirationTime']) {
-      return false;
-    }
-
-    return $token_data;
-  }
-}
-

+ 0 - 172
src/helpers/utils.php

@@ -1,172 +0,0 @@
-<?php
-
-class Utils
-{
-  var $c;
-  public function __construct($c)
-  {
-    $this->c = $c;
-  }
-
-  public function get_computed_download_url($repo_url, $provider, $commit, &$warning=null) // i.e. browse_url, download_provider, download_commit
-  {
-    $repo_url = rtrim($repo_url, '/');
-    if(is_int($provider)) {
-      $provider = $this->c->constants['download_provider'][$provider];
-    }
-    $warning_suffix = "Please, ensure that the URL and the repository provider are, indeed, correct.";
-    $light_warning_suffix = "Please, doublecheck that the URL and the repository provider are correct.";
-    switch ($provider) {
-      case 'GitHub':
-        if(sizeof(preg_grep('/^https:\/\/github\.com\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
-          $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"https://github.com/<owner>/<name>\". $warning_suffix";
-        }
-        return "$repo_url/archive/$commit.zip";
-      case 'GitLab':
-        if(sizeof(preg_grep('/^https:\/\/(gitlab\.com|[^\/]+)\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
-          $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"https://<gitlab instance>/<owner>/<name>\". $warning_suffix";
-        } elseif(sizeof(preg_grep('/^https:\/\/(gitlab\.com)\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
-          $warning = "\"$repo_url\" might not be correct; it should be similar to \"https://gitlab.com/<owner>/<name>\", unless the asset is hosted on a custom instance of GitLab. $light_warning_suffix";
-        }
-        return "$repo_url/repository/archive.zip?ref=$commit";
-      case 'BitBucket':
-        if(sizeof(preg_grep('/^https:\/\/bitbucket\.org\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
-          $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"https://bitbucket.org/<owner>/<name>\". $warning_suffix";
-        }
-        return "$repo_url/get/$commit.zip";
-      case 'Gogs':
-        if(sizeof(preg_grep('/^https?:\/\/[^\/]+?\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
-          $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"http<s>://<gogs instance>/<owner>/<name>\". $warning_suffix";
-        }
-        $warning = "Since Gogs might be self-hosted, we can't be sure that \"$repo_url\" is a valid Gogs URL. $light_warning_suffix";
-        return "$repo_url/archive/$commit.zip";
-      case 'cgit':
-        if(sizeof(preg_grep('/^https?:\/\/[^\/]+?\/[^\/]+?\/[^\/]+?$/', [$repo_url])) == 0) {
-          $warning = "\"$repo_url\" doesn't look correct; it should be similar to \"http<s>://<cgit instance>/<owner>/<name>\". $warning_suffix";
-        }
-        $warning = "Since cgit might be self-hosted, we can't be sure that \"$repo_url\" is a valid cgit URL. $light_warning_suffix";
-        return "$repo_url/snapshot/$commit.zip";
-      default: return "$repo_url/$commit.zip"; // Obviously incorrect, but we would like to have some default case...
-    }
-  }
-
-  public function get_default_issues_url($repo_url, $provider) // i.e. browse_url, download_provider
-  {
-    $repo_url = rtrim($repo_url, '/');
-    if(is_int($provider)) {
-      $provider = $this->c->constants['download_provider'][$provider];
-    }
-    switch ($provider) {
-      case 'GitHub':
-      case 'GitLab':
-      case 'BitBucket':
-      case 'Gogs':
-        return "$repo_url/issues";
-      case 'cgit':
-      default:
-        return "";
-    }
-  }
-
-  public function error_reponse_if_not_user_has_level($currentStatus, &$response, $user, $required_level_name, $message = 'You are not authorized to do this')
-  {
-    if($user === false || $currentStatus) return true;
-
-    if((int) $user['type'] < $this->c->constants['user_type'][$required_level_name]) {
-      $response = $response->withJson([
-        'error' => $message,
-      ], 403);
-      return true;
-    }
-    return false;
-  }
-
-  public function error_reponse_if_missing_or_not_string($currentStatus, &$response, $object, $property)
-  {
-    if($currentStatus) return true;
-
-    if(!isset($object[$property]) || !is_string($object[$property]) || $object[$property] == "") {
-      $response = $response->withJson([
-        'error' => $property . ' is required, and must be a string'
-      ], 400);
-      return true;
-    }
-    return false;
-  }
-
-  public function error_reponse_if_query_bad($currentStatus, &$response, $query, $message = 'An error occured while executing DB queries')
-  {
-    if($currentStatus) return true;
-
-    if($query->errorCode() != '00000') {
-      $this->c->logger->error('DBError', $query->errorInfo());
-      $response = $response->withJson([
-        'error' => $message,
-      ], 500);
-      return true;
-    }
-    return false;
-  }
-
-  public function error_reponse_if_query_no_results($currentStatus, &$response, $query, $message = 'DB returned no results')
-  {
-    if($currentStatus) return true;
-
-    if($query->rowCount() == 0) {
-      $response = $response->withJson([
-        'error' => $message
-      ], 404);
-      return true;
-    }
-    return false;
-  }
-
-  public function ensure_logged_in($currentStatus, &$response, $body, &$user, &$token_data=null, $reset = false)
-  {
-    $currentStatus = $this->error_reponse_if_missing_or_not_string($currentStatus, $response, $body, 'token');
-    if($currentStatus) return true;
-
-    $token_data = $this->c->tokens->validate($body['token']);
-    $error = $this->get_user_from_token_data(false, $response, $token_data, $user, $reset);
-    return $error;
-  }
-
-  public function get_user_from_token_data($currentStatus, &$response, $token_data, &$user, $reset = false)
-  {
-    if($currentStatus) return true;
-    if(!$token_data) {
-      $response = $response->withJson([
-        'error' => 'Invalid token'
-      ], 403);
-      return true;
-    }
-
-    // Insecure
-    // if(isset($token_data->user_id)) {
-    //   $query = $this->c->queries['user']['get_one'];
-    //   $query->bindValue(':id', (int) $token_data->user_id, PDO::PARAM_INT);
-    // }
-    if(isset($token_data->session) && !$reset) {
-      $query = $this->c->queries['user']['get_by_session_token'];
-      $query->bindValue(":session_token", base64_decode($token_data->session));
-    } else if(isset($token_data->reset) && $reset) {
-      $query = $this->c->queries['user']['get_by_reset_token'];
-      $query->bindValue(":reset_token", base64_decode($token_data->reset));
-    } else {
-      $response = $response->withJson([
-        'error' => 'Invalid token'
-      ], 403);
-      return true;
-    }
-
-    $query->execute();
-
-    $currentStatus = $this->error_reponse_if_query_bad(false, $response, $query);
-    $currentStatus = $this->error_reponse_if_query_no_results($currentStatus, $response, $query, 'Nonexistent token submitted');
-    if($currentStatus) return true;
-
-    $user = $query->fetchAll()[0];
-    return false;
-
-  }
-}

+ 160 - 160
src/middleware.php

@@ -1,171 +1,171 @@
 <?php
 
-if(FRONTEND) {
-  $container = $app->getContainer();
-
-  $app->get('/', function ($request, $response) {
-    return $response->withJson(['url' => 'asset']);
-  });
-
-  $app->add(function ($request, $response, $next) {
-    $cookie = $this->cookies['requestCookies']->get($request, 'token');
-    $body = $request->getParsedBody();
-    if($cookie->getValue() !== null && !isset($body['token'])) {
-      $cookieValue = (string) $cookie->getValue();
-      $body['token'] = $cookieValue;
-      $request = $request->withParsedBody($body);
-    }
-    $response->getBody()->rewind();
-    $preresult = json_decode($response->getBody()->getContents(), true);
-    if(!isset($preresult['error'])) {
-      $response = $next($request, $response);
-    }
-
-    $static_routes = [
-      '/login' => true,
-      '/register' => true,
-      '/forgot_password' => true,
-      '/change_password' => true,
-      '/asset/submit' => true,
-    ];
-    $queryUri = false;
-
-    $route = $request->getAttribute('route');
-    $path = $request->getUri()->getPath();
-
-    if(substr($path, 0, 8) == 'frontend') {
-      $response = $response->withHeader('Location', $request->getUri()->getBasePath() . substr($path, 8) . '?' . $request->getUri()->getQuery());
-    }
-
-    if(isset($static_routes['/' . $path])) {
-      $queryUri = '/' . $path;
-    } elseif($route) {
-      $queryUri = $route->getPattern();
-    } else {
-      return $response;
-    }
-
-    $queryUri = $request->getMethod() . ' ' . $queryUri;
-
-    if($route) {
-      $response->getBody()->rewind();
-      $result = json_decode($response->getBody()->getContents(), true);
-      if($result === null) {
-        return $response;
-        //$result = ['error' => 'Can\'t decode api response - ' . $response->getBody()->getContents()];
-      }
-    } else {
-      $result = [];
-    }
-
-
-    if(isset($result['url'])) {
-      $response = new \Slim\Http\Response(303);
-      $response = $response->withHeader('Location', $request->getUri()->getBasePath() . '/' . $result['url']);
-    } else {
-      if(isset($result['token'])) {
-        $body['token'] = $result['token'];
-      }
-      $template_names = [
-        'GET /user/feed' => 'feed',
-
-        'GET /asset' => 'assets',
-        'GET /asset/submit' => 'submit_asset',
-        'GET /asset/{id:[0-9]+}' => 'asset',
-        'GET /asset/{id:[0-9]+}/edit' => 'edit_asset',
-
-        'GET /asset/edit' => 'asset_edits',
-        'GET /asset/edit/{id:[0-9]+}' => 'asset_edit',
-        'GET /asset/edit/{id:[0-9]+}/edit' => 'edit_asset_edit',
-
-        'GET /login' => 'login',
-        'ERROR POST /login' => 'login',
-        'GET /register' => 'register',
-        'ERROR POST /register' => 'register',
-        'GET /forgot_password' => 'forgot_password',
-        'POST /forgot_password' => 'forgot_password_result',
-        'GET /reset_password' => 'reset_password',
-        'GET /change_password' => 'change_password',
-        'ERROR POST /change_password' => 'change_password',
-
-        'ERROR' => 'error',
-      ];
-
-      if(isset($result['error'])) {
-        if(isset($template_names['ERROR ' . $queryUri])) {
-          $queryUri = 'ERROR ' . $queryUri;
-        } else {
-          $queryUri = 'ERROR';
+if (FRONTEND) {
+    $container = $app->getContainer();
+
+    $app->get('/', function ($request, $response) {
+        return $response->withJson(['url' => 'asset']);
+    });
+
+    $app->add(function ($request, $response, $next) {
+        $cookie = $this->cookies['requestCookies']->get($request, 'token');
+        $body = $request->getParsedBody();
+        if ($cookie->getValue() !== null && !isset($body['token'])) {
+            $cookieValue = (string) $cookie->getValue();
+            $body['token'] = $cookieValue;
+            $request = $request->withParsedBody($body);
+        }
+        $response->getBody()->rewind();
+        $preresult = json_decode($response->getBody()->getContents(), true);
+        if (!isset($preresult['error'])) {
+            $response = $next($request, $response);
         }
-      }
-
-      if(isset($template_names[$queryUri])) {
-        $response = new \Slim\Http\Response();
-        $errorResponse = new \Slim\Http\Response();
-        $params = [
-          'data' => $result,
-          'basepath' => $request->getUri()->getBasePath(). '',
-          'bowerpath' => $request->getUri()->getBasePath() . '/bower_components',
-          'path' => $path,
-          'params' => $request->getQueryParams(),
-          'query' => $request->getUri()->getQuery(),
-          'categories' => [], // Filled later
-          'constants' => $this->constants,
-          'csrf_name_key' => $this->csrf->getTokenNameKey(),
-          'csrf_name' => $request->getAttribute('csrf_name'),
-          'csrf_value_key' => $this->csrf->getTokenValueKey(),
-          'csrf_value' => $request->getAttribute('csrf_value'),
-          //'body' => $request->getParsedBody(),
+
+        $static_routes = [
+            '/login' => true,
+            '/register' => true,
+            '/forgot_password' => true,
+            '/change_password' => true,
+            '/asset/submit' => true,
         ];
+        $queryUri = false;
+
+        $route = $request->getAttribute('route');
+        $path = $request->getUri()->getPath();
+
+        if (substr($path, 0, 8) == 'frontend') {
+            $response = $response->withHeader('Location', $request->getUri()->getBasePath() . substr($path, 8) . '?' . $request->getUri()->getQuery());
+        }
+
+        if (isset($static_routes['/' . $path])) {
+            $queryUri = '/' . $path;
+        } elseif ($route) {
+            $queryUri = $route->getPattern();
+        } else {
+            return $response;
+        }
+
+        $queryUri = $request->getMethod() . ' ' . $queryUri;
 
-        if(isset($body['token'])) {
-          $token = $this->tokens->validate($body['token']);
-          $error = $this->utils->get_user_from_token_data(false, $errorResponse, $token, $user);
-          if(!$error) {
-            $params['user'] = $user;
-          } else {
-            $error = $this->utils->get_user_from_token_data(false, $errorResponse, $token, $reset_user, true);
-            if(!$error) {
-              $params['reset_user'] = $reset_user;
+        if ($route) {
+            $response->getBody()->rewind();
+            $result = json_decode($response->getBody()->getContents(), true);
+            if ($result === null) {
+                return $response;
+                //$result = ['error' => 'Can\'t decode api response - ' . $response->getBody()->getContents()];
             }
-          }
+        } else {
+            $result = [];
         }
 
-        $query_categories = $this->queries['category']['list'];
-        $query_categories->bindValue(':category_type', '%');
-        $query_categories->execute();
-
-        $error = $this->utils->error_reponse_if_query_bad(false, $errorResponse, $query_categories);
-        $error = $this->utils->error_reponse_if_query_no_results($error, $errorResponse, $query_categories);
-        if(!$error) {
-          $categories = $query_categories->fetchAll();
-          foreach ($categories as $key => $value) {
-            $params['categories'][$value['id']] = $value;
-          }
+
+        if (isset($result['url'])) {
+            $response = new \Slim\Http\Response(303);
+            $response = $response->withHeader('Location', $request->getUri()->getBasePath() . '/' . $result['url']);
+        } else {
+            if (isset($result['token'])) {
+                $body['token'] = $result['token'];
+            }
+            $template_names = [
+                'GET /user/feed' => 'feed',
+
+                'GET /asset' => 'assets',
+                'GET /asset/submit' => 'submit_asset',
+                'GET /asset/{id:[0-9]+}' => 'asset',
+                'GET /asset/{id:[0-9]+}/edit' => 'edit_asset',
+
+                'GET /asset/edit' => 'asset_edits',
+                'GET /asset/edit/{id:[0-9]+}' => 'asset_edit',
+                'GET /asset/edit/{id:[0-9]+}/edit' => 'edit_asset_edit',
+
+                'GET /login' => 'login',
+                'ERROR POST /login' => 'login',
+                'GET /register' => 'register',
+                'ERROR POST /register' => 'register',
+                'GET /forgot_password' => 'forgot_password',
+                'POST /forgot_password' => 'forgot_password_result',
+                'GET /reset_password' => 'reset_password',
+                'GET /change_password' => 'change_password',
+                'ERROR POST /change_password' => 'change_password',
+
+                'ERROR' => 'error',
+            ];
+
+            if (isset($result['error'])) {
+                if (isset($template_names['ERROR ' . $queryUri])) {
+                    $queryUri = 'ERROR ' . $queryUri;
+                } else {
+                    $queryUri = 'ERROR';
+                }
+            }
+
+            if (isset($template_names[$queryUri])) {
+                $response = new \Slim\Http\Response();
+                $errorResponse = new \Slim\Http\Response();
+                $params = [
+                    'data' => $result,
+                    'basepath' => $request->getUri()->getBasePath(). '',
+                    'bowerpath' => $request->getUri()->getBasePath() . '/bower_components',
+                    'path' => $path,
+                    'params' => $request->getQueryParams(),
+                    'query' => $request->getUri()->getQuery(),
+                    'categories' => [], // Filled later
+                    'constants' => $this->constants,
+                    'csrf_name_key' => $this->csrf->getTokenNameKey(),
+                    'csrf_name' => $request->getAttribute('csrf_name'),
+                    'csrf_value_key' => $this->csrf->getTokenValueKey(),
+                    'csrf_value' => $request->getAttribute('csrf_value'),
+                    //'body' => $request->getParsedBody(),
+                ];
+
+                if (isset($body['token'])) {
+                    $token = $this->tokens->validate($body['token']);
+                    $error = $this->utils->getUserFromTokenData(false, $errorResponse, $token, $user);
+                    if (!$error) {
+                        $params['user'] = $user;
+                    } else {
+                        $error = $this->utils->getUserFromTokenData(false, $errorResponse, $token, $reset_user, true);
+                        if (!$error) {
+                            $params['reset_user'] = $reset_user;
+                        }
+                    }
+                }
+
+                $query_categories = $this->queries['category']['list'];
+                $query_categories->bindValue(':category_type', '%');
+                $query_categories->execute();
+
+                $error = $this->utils->errorResponseIfQueryBad(false, $errorResponse, $query_categories);
+                $error = $this->utils->errorResponseIfQueryNoResults($error, $errorResponse, $query_categories);
+                if (!$error) {
+                    $categories = $query_categories->fetchAll();
+                    foreach ($categories as $key => $value) {
+                        $params['categories'][$value['id']] = $value;
+                    }
+                }
+
+                $response = $this->renderer->render($response, $template_names[$queryUri] . '.phtml', $params);
+            }
+        }
+
+        if (isset($result['token'])) {
+            $response = $this->cookies['responseCookies']->set($response, $this->cookies['setCookie']('token')
+                ->withValue($result['token'])
+                ->withDomain($_SERVER['HTTP_HOST'])
+                ->withPath($request->getUri()->getBasePath())
+                ->withHttpOnly(true)
+            );
         }
+        return $response;
+    });
+
+    // Adding after the real middleware, since it has to run first... o.O
+    $app->add($container->get('csrf'));
 
-        $response = $this->renderer->render($response, $template_names[$queryUri] . '.phtml', $params);
-      }
-    }
-
-    if(isset($result['token'])) {
-      $response = $this->cookies['responseCookies']->set($response, $this->cookies['setCookie']('token')
-        ->withValue($result['token'])
-        ->withDomain($_SERVER['HTTP_HOST'])
-        ->withPath($request->getUri()->getBasePath())
-        ->withHttpOnly(true)
-      );
-    }
-    return $response;
-  });
-
-  // Adding after the real middleware, since it has to run first... o.O
-  $app->add($container->get('csrf'));
-
-  $container->get('csrf')->setFailureCallable(function ($request, $response, $next) {
-    $response = $response->withJson([
-      'error' => 'CSRF check failed',
-    ]);
-    return $next($request, $response);
-  });
+    $container->get('csrf')->setFailureCallable(function ($request, $response, $next) {
+        $response = $response->withJson([
+            'error' => 'CSRF check failed',
+        ]);
+        return $next($request, $response);
+    });
 }

+ 164 - 164
src/queries.php

@@ -1,168 +1,168 @@
 <?php
 
 return [
-  'user' => [
-    'get_one' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE user_id = :id',
-    'get_by_username' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE username = :username',
-    'get_by_email' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE email = :email',
-    'get_by_session_token' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE session_token = :session_token',
-    'get_by_reset_token' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE reset_token = :reset_token',
-    'set_session_token' => 'UPDATE `as_users` SET session_token = :session_token WHERE user_id = :id',
-    'set_reset_token' => 'UPDATE `as_users` SET reset_token = :reset_token WHERE user_id = :id',
-    'set_password_and_nullify_session' => 'UPDATE `as_users` SET password_hash = :password_hash, session_token = null WHERE user_id = :id',
-    'register' => 'INSERT INTO `as_users` SET username = :username, email = :email, password_hash = :password_hash',
-    'list_edit_events' => 'SELECT edit_id, asset_id, COALESCE(`as_asset_edits`.title, `as_assets`.title) AS title, category, COALESCE(`as_asset_edits`.version_string, `as_assets`.version_string) AS version_string, COALESCE(`as_asset_edits`.icon_url, `as_assets`.icon_url) AS icon_url, status, reason FROM `as_asset_edits`
-      LEFT JOIN `as_assets` USING (asset_id)
-      LEFT JOIN `as_categories` ON `as_categories`.category_id = COALESCE(`as_asset_edits`.category_id, `as_assets`.category_id)
-      WHERE `as_asset_edits`.user_id = :user_id
-      ORDER BY `as_asset_edits`.modify_date DESC
-      LIMIT :page_size OFFSET :skip_count',
-  ],
-  'category' => [
-    'list' => 'SELECT category_id as id, category as name FROM `as_categories` WHERE category_type LIKE :category_type ORDER BY category_id',
-  ],
-  'asset' => [
-    'search' => 'SELECT asset_id, title, username as author, user_id as author_id, category, category_id, rating, cost, support_level, icon_url, version, version_string FROM `as_assets`
-      LEFT JOIN `as_users` USING (user_id)
-      LEFT JOIN `as_categories` USING (category_id)
-
-      WHERE searchable = TRUE AND category_id LIKE :category AND category_type LIKE :category_type
-      AND support_level RLIKE :support_levels_regex AND username LIKE :username
-      AND (
-        title LIKE :filter
-        OR cost LIKE :filter
-        OR username LIKE :filter
-      )
-
-      ORDER BY
-      CASE
-        WHEN :order_direction = "asc" THEN
-        CASE
-          WHEN :order = "rating" THEN rating
-          WHEN :order = "cost" THEN cost
-          WHEN :order = "title" THEN title
-          WHEN :order = "modify_date" THEN modify_date
-        END
-      END ASC,
-      CASE
-        WHEN :order_direction = "desc" THEN
-        CASE
-          WHEN :order = "rating" THEN rating
-          WHEN :order = "cost" THEN cost
-          WHEN :order = "title" THEN title
-          WHEN :order = "modify_date" THEN modify_date
-        END
-      END DESC
-
-      LIMIT :page_size OFFSET :skip_count',
-
-    'search_count' => 'SELECT count(*) as count FROM `as_assets`
-      LEFT JOIN `as_users` USING (user_id)
-      LEFT JOIN `as_categories` USING (category_id)
-      WHERE searchable = TRUE AND category_id LIKE :category AND category_type LIKE :category_type
-      AND support_level RLIKE :support_levels_regex AND username LIKE :username
-      AND (
-        title LIKE :filter
-        OR cost LIKE :filter
-        OR username LIKE :filter
-      )',
-
-    'get_one' => 'SELECT asset_id, category_type, title, username as author, user_id as author_id, version, version_string, category, category_id, rating, cost, description, support_level, download_provider, download_commit, download_hash, browse_url, issues_url, icon_url, preview_id, `as_asset_previews`.type, link, thumbnail, searchable FROM `as_assets`
-      LEFT JOIN `as_categories` USING (category_id)
-      LEFT JOIN `as_users` USING (user_id)
-      LEFT JOIN `as_asset_previews` USING (asset_id)
-      WHERE asset_id = :id',
-
-    'get_one_bare' => 'SELECT * FROM `as_assets` WHERE asset_id = :asset_id',
-    'get_one_preview_bare' => 'SELECT * FROM `as_asset_previews` WHERE preview_id = :preview_id',
-
-    'apply_creational_edit' => 'INSERT INTO `as_assets`
-      SET title=:title, description=:description, category_id=:category_id, user_id=:user_id,
-      version_string=:version_string, cost=:cost,
-      download_provider=:download_provider, download_commit=:download_commit, download_hash=:download_hash, browse_url=:browse_url, issues_url=:issues_url, icon_url=:icon_url,
-      version=0+:update_version, rating=0, searchable=TRUE',
-
-    'apply_edit' => 'UPDATE `as_assets`
-      SET title=COALESCE(:title, title), description=COALESCE(:description, description), category_id=COALESCE(:category_id, category_id),  version_string=COALESCE(:version_string, version_string), cost=COALESCE(:cost, cost),
-      download_provider=COALESCE(:download_provider, download_provider), download_commit=COALESCE(:download_commit, download_commit), download_hash=COALESCE(:download_hash, download_hash), browse_url=COALESCE(:browse_url, browse_url), issues_url=COALESCE(:issues_url, issues_url), icon_url=COALESCE(:icon_url, icon_url),
-      version=version+:update_version
-      WHERE asset_id=:asset_id',
-
-    'apply_preview_edit_insert' => 'INSERT INTO `as_asset_previews`
-      SET asset_id=:asset_id, type=:type, link=:link, thumbnail=:thumbnail',
-    'apply_preview_edit_remove' => 'DELETE FROM `as_asset_previews`
-      WHERE preview_id=:preview_id AND asset_id=:asset_id',
-    'apply_preview_edit_update' => 'UPDATE `as_asset_previews`
-      SET type=COALESCE(:type, type), link=COALESCE(:link, link), thumbnail=COALESCE(:thumbnail, thumbnail)
-      WHERE preview_id=:preview_id AND asset_id=:asset_id',
-
-    'set_support_level' => 'UPDATE `as_assets`
-      SET support_level=:support_level
-      WHERE asset_id=:asset_id'
-  ],
-  'asset_edit' => [
-    'get_one' => 'SELECT edit_id, `as_asset_edits`.asset_id, user_id, title, description, category_id, version_string,
-      cost, download_provider, download_commit, browse_url, issues_url, icon_url, status, reason,
-      edit_preview_id, `as_asset_previews`.preview_id, `as_asset_edit_previews`.type, `as_asset_edit_previews`.link, `as_asset_edit_previews`.thumbnail, `as_asset_edit_previews`.operation,
-      `as_asset_previews`.type AS orig_type, `as_asset_previews`.link AS orig_link, `as_asset_previews`.thumbnail AS orig_thumbnail,
-      unedited_previews.preview_id AS unedited_preview_id, unedited_previews.type AS unedited_type, unedited_previews.link AS unedited_link, unedited_previews.thumbnail AS unedited_thumbnail, username AS author
-      FROM `as_asset_edits`
-      LEFT JOIN `as_users` USING (user_id)
-      LEFT JOIN `as_asset_edit_previews` USING (edit_id)
-      LEFT JOIN `as_asset_previews` USING (preview_id)
-      LEFT JOIN `as_asset_previews` AS unedited_previews ON `as_asset_edits`.asset_id = unedited_previews.asset_id
-      WHERE edit_id=:edit_id',
-
-    'get_one_bare' => 'SELECT * FROM `as_asset_edits` WHERE edit_id=:edit_id',
-    'get_one_with_status' => 'SELECT * FROM `as_asset_edits` WHERE edit_id=:edit_id AND status=:status',
-    'get_editable_by_asset_id' => 'SELECT * FROM `as_asset_edits` WHERE asset_id=:asset_id AND status=0',
-
-    'search' => 'SELECT edit_id, asset_id,
-    `as_asset_edits`.user_id, COALESCE(`as_asset_edits`.title, `as_assets`.title) AS title, COALESCE(`as_asset_edits`.description, `as_assets`.description) AS description, category, COALESCE(`as_asset_edits`.version_string, `as_assets`.version_string) AS version_string, COALESCE(`as_asset_edits`.cost, `as_assets`.cost) AS cost, COALESCE(`as_asset_edits`.browse_url, `as_assets`.browse_url) AS browse_url, COALESCE(`as_asset_edits`.icon_url, `as_assets`.icon_url) AS icon_url, `as_assets`.support_level, status, reason, username AS author FROM `as_asset_edits`
-      LEFT JOIN `as_users` USING (user_id)
-      LEFT JOIN `as_categories` USING (category_id)
-      LEFT JOIN `as_assets` USING (asset_id)
-      WHERE
-        status RLIKE :statuses_regex
-        AND asset_id LIKE :asset_id AND username LIKE :username
-        AND (
-          `as_asset_edits`.title LIKE :filter
-          OR `as_assets`.title LIKE :filter
-          OR username LIKE :filter
-        )
-      ORDER BY `as_asset_edits`.modify_date DESC
-      LIMIT :page_size OFFSET :skip_count',
-
-    'search_count' => 'SELECT count(*) AS count FROM `as_asset_edits`
-      LEFT JOIN `as_users` USING (user_id)
-      WHERE
-        status RLIKE :statuses_regex
-        AND asset_id LIKE :asset_id AND username LIKE :username
-        AND (
-          title LIKE :filter
-          OR username LIKE :filter
-        )
-      ',
-
-    'submit' => 'INSERT INTO `as_asset_edits`
-      SET asset_id=:asset_id, user_id=:user_id, title=:title, description=:description, category_id=:category_id, version_string=:version_string,
-        cost=:cost, download_provider=:download_provider, download_commit=:download_commit, browse_url=:browse_url, issues_url=:issues_url, icon_url=:icon_url,
-        status=0, submit_date=NOW()',
-
-    'update' => 'UPDATE `as_asset_edits`
-      SET title=:title, description=:description, category_id=:category_id, version_string=:version_string, cost=:cost,
-      download_provider=:download_provider, download_commit=:download_commit, browse_url=:browse_url, issues_url=:issues_url, icon_url=:icon_url
-      WHERE edit_id=:edit_id AND status=0',
-
-    'add_preview' => 'INSERT INTO `as_asset_edit_previews`
-      SET edit_id=:edit_id, preview_id=:preview_id, type=:type, link=:link, thumbnail=:thumbnail, operation=:operation',
-    'update_preview' => 'UPDATE `as_asset_edit_previews`
-      SET type=COALESCE(:type, type), link=COALESCE(:link, link), thumbnail=COALESCE(:thumbnail, thumbnail)
-      WHERE edit_id=:edit_id AND edit_preview_id=:edit_preview_id',
-    'remove_preview' => 'DELETE FROM `as_asset_edit_previews`
-      WHERE edit_id=:edit_id AND edit_preview_id=:edit_preview_id',
-
-    'set_asset_id' => 'UPDATE `as_asset_edits` SET asset_id=:asset_id WHERE edit_id=:edit_id',
-    'set_status_and_reason' => 'UPDATE `as_asset_edits` SET status=:status, reason=:reason WHERE edit_id=:edit_id',
-  ],
+    'user' => [
+        'get_one' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE user_id = :id',
+        'get_by_username' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE username = :username',
+        'get_by_email' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE email = :email',
+        'get_by_session_token' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE session_token = :session_token',
+        'get_by_reset_token' => 'SELECT user_id, username, email, password_hash, type FROM `as_users` WHERE reset_token = :reset_token',
+        'set_session_token' => 'UPDATE `as_users` SET session_token = :session_token WHERE user_id = :id',
+        'set_reset_token' => 'UPDATE `as_users` SET reset_token = :reset_token WHERE user_id = :id',
+        'set_password_and_nullify_session' => 'UPDATE `as_users` SET password_hash = :password_hash, session_token = null WHERE user_id = :id',
+        'register' => 'INSERT INTO `as_users` SET username = :username, email = :email, password_hash = :password_hash',
+        'list_edit_events' => 'SELECT edit_id, asset_id, COALESCE(`as_asset_edits`.title, `as_assets`.title) AS title, category, COALESCE(`as_asset_edits`.version_string, `as_assets`.version_string) AS version_string, COALESCE(`as_asset_edits`.icon_url, `as_assets`.icon_url) AS icon_url, status, reason FROM `as_asset_edits`
+            LEFT JOIN `as_assets` USING (asset_id)
+            LEFT JOIN `as_categories` ON `as_categories`.category_id = COALESCE(`as_asset_edits`.category_id, `as_assets`.category_id)
+            WHERE `as_asset_edits`.user_id = :user_id
+            ORDER BY `as_asset_edits`.modify_date DESC
+            LIMIT :page_size OFFSET :skip_count',
+    ],
+    'category' => [
+        'list' => 'SELECT category_id as id, category as name FROM `as_categories` WHERE category_type LIKE :category_type ORDER BY category_id',
+    ],
+    'asset' => [
+        'search' => 'SELECT asset_id, title, username as author, user_id as author_id, category, category_id, rating, cost, support_level, icon_url, version, version_string FROM `as_assets`
+            LEFT JOIN `as_users` USING (user_id)
+            LEFT JOIN `as_categories` USING (category_id)
+
+            WHERE searchable = TRUE AND category_id LIKE :category AND category_type LIKE :category_type
+            AND support_level RLIKE :support_levels_regex AND username LIKE :username
+            AND (
+                title LIKE :filter
+                OR cost LIKE :filter
+                OR username LIKE :filter
+            )
+
+            ORDER BY
+            CASE
+                WHEN :order_direction = "asc" THEN
+                CASE
+                    WHEN :order = "rating" THEN rating
+                    WHEN :order = "cost" THEN cost
+                    WHEN :order = "title" THEN title
+                    WHEN :order = "modify_date" THEN modify_date
+                END
+            END ASC,
+            CASE
+                WHEN :order_direction = "desc" THEN
+                CASE
+                    WHEN :order = "rating" THEN rating
+                    WHEN :order = "cost" THEN cost
+                    WHEN :order = "title" THEN title
+                    WHEN :order = "modify_date" THEN modify_date
+                END
+            END DESC
+
+            LIMIT :page_size OFFSET :skip_count',
+
+        'search_count' => 'SELECT count(*) as count FROM `as_assets`
+            LEFT JOIN `as_users` USING (user_id)
+            LEFT JOIN `as_categories` USING (category_id)
+            WHERE searchable = TRUE AND category_id LIKE :category AND category_type LIKE :category_type
+            AND support_level RLIKE :support_levels_regex AND username LIKE :username
+            AND (
+                title LIKE :filter
+                OR cost LIKE :filter
+                OR username LIKE :filter
+            )',
+
+        'get_one' => 'SELECT asset_id, category_type, title, username as author, user_id as author_id, version, version_string, category, category_id, rating, cost, description, support_level, download_provider, download_commit, download_hash, browse_url, issues_url, icon_url, preview_id, `as_asset_previews`.type, link, thumbnail, searchable FROM `as_assets`
+            LEFT JOIN `as_categories` USING (category_id)
+            LEFT JOIN `as_users` USING (user_id)
+            LEFT JOIN `as_asset_previews` USING (asset_id)
+            WHERE asset_id = :id',
+
+        'get_one_bare' => 'SELECT * FROM `as_assets` WHERE asset_id = :asset_id',
+        'get_one_preview_bare' => 'SELECT * FROM `as_asset_previews` WHERE preview_id = :preview_id',
+
+        'apply_creational_edit' => 'INSERT INTO `as_assets`
+            SET title=:title, description=:description, category_id=:category_id, user_id=:user_id,
+            version_string=:version_string, cost=:cost,
+            download_provider=:download_provider, download_commit=:download_commit, download_hash=:download_hash, browse_url=:browse_url, issues_url=:issues_url, icon_url=:icon_url,
+            version=0+:update_version, rating=0, searchable=TRUE',
+
+        'apply_edit' => 'UPDATE `as_assets`
+            SET title=COALESCE(:title, title), description=COALESCE(:description, description), category_id=COALESCE(:category_id, category_id),  version_string=COALESCE(:version_string, version_string), cost=COALESCE(:cost, cost),
+            download_provider=COALESCE(:download_provider, download_provider), download_commit=COALESCE(:download_commit, download_commit), download_hash=COALESCE(:download_hash, download_hash), browse_url=COALESCE(:browse_url, browse_url), issues_url=COALESCE(:issues_url, issues_url), icon_url=COALESCE(:icon_url, icon_url),
+            version=version+:update_version
+            WHERE asset_id=:asset_id',
+
+        'apply_preview_edit_insert' => 'INSERT INTO `as_asset_previews`
+            SET asset_id=:asset_id, type=:type, link=:link, thumbnail=:thumbnail',
+        'apply_preview_edit_remove' => 'DELETE FROM `as_asset_previews`
+            WHERE preview_id=:preview_id AND asset_id=:asset_id',
+        'apply_preview_edit_update' => 'UPDATE `as_asset_previews`
+            SET type=COALESCE(:type, type), link=COALESCE(:link, link), thumbnail=COALESCE(:thumbnail, thumbnail)
+            WHERE preview_id=:preview_id AND asset_id=:asset_id',
+
+        'set_support_level' => 'UPDATE `as_assets`
+            SET support_level=:support_level
+            WHERE asset_id=:asset_id'
+    ],
+    'asset_edit' => [
+        'get_one' => 'SELECT edit_id, `as_asset_edits`.asset_id, user_id, title, description, category_id, version_string,
+            cost, download_provider, download_commit, browse_url, issues_url, icon_url, status, reason,
+            edit_preview_id, `as_asset_previews`.preview_id, `as_asset_edit_previews`.type, `as_asset_edit_previews`.link, `as_asset_edit_previews`.thumbnail, `as_asset_edit_previews`.operation,
+            `as_asset_previews`.type AS orig_type, `as_asset_previews`.link AS orig_link, `as_asset_previews`.thumbnail AS orig_thumbnail,
+            unedited_previews.preview_id AS unedited_preview_id, unedited_previews.type AS unedited_type, unedited_previews.link AS unedited_link, unedited_previews.thumbnail AS unedited_thumbnail, username AS author
+            FROM `as_asset_edits`
+            LEFT JOIN `as_users` USING (user_id)
+            LEFT JOIN `as_asset_edit_previews` USING (edit_id)
+            LEFT JOIN `as_asset_previews` USING (preview_id)
+            LEFT JOIN `as_asset_previews` AS unedited_previews ON `as_asset_edits`.asset_id = unedited_previews.asset_id
+            WHERE edit_id=:edit_id',
+
+        'get_one_bare' => 'SELECT * FROM `as_asset_edits` WHERE edit_id=:edit_id',
+        'get_one_with_status' => 'SELECT * FROM `as_asset_edits` WHERE edit_id=:edit_id AND status=:status',
+        'get_editable_by_asset_id' => 'SELECT * FROM `as_asset_edits` WHERE asset_id=:asset_id AND status=0',
+
+        'search' => 'SELECT edit_id, asset_id,
+        `as_asset_edits`.user_id, COALESCE(`as_asset_edits`.title, `as_assets`.title) AS title, COALESCE(`as_asset_edits`.description, `as_assets`.description) AS description, category, COALESCE(`as_asset_edits`.version_string, `as_assets`.version_string) AS version_string, COALESCE(`as_asset_edits`.cost, `as_assets`.cost) AS cost, COALESCE(`as_asset_edits`.browse_url, `as_assets`.browse_url) AS browse_url, COALESCE(`as_asset_edits`.icon_url, `as_assets`.icon_url) AS icon_url, `as_assets`.support_level, status, reason, username AS author FROM `as_asset_edits`
+            LEFT JOIN `as_users` USING (user_id)
+            LEFT JOIN `as_categories` USING (category_id)
+            LEFT JOIN `as_assets` USING (asset_id)
+            WHERE
+                status RLIKE :statuses_regex
+                AND asset_id LIKE :asset_id AND username LIKE :username
+                AND (
+                    `as_asset_edits`.title LIKE :filter
+                    OR `as_assets`.title LIKE :filter
+                    OR username LIKE :filter
+                )
+            ORDER BY `as_asset_edits`.modify_date DESC
+            LIMIT :page_size OFFSET :skip_count',
+
+        'search_count' => 'SELECT count(*) AS count FROM `as_asset_edits`
+            LEFT JOIN `as_users` USING (user_id)
+            WHERE
+                status RLIKE :statuses_regex
+                AND asset_id LIKE :asset_id AND username LIKE :username
+                AND (
+                    title LIKE :filter
+                    OR username LIKE :filter
+                )
+            ',
+
+        'submit' => 'INSERT INTO `as_asset_edits`
+            SET asset_id=:asset_id, user_id=:user_id, title=:title, description=:description, category_id=:category_id, version_string=:version_string,
+                cost=:cost, download_provider=:download_provider, download_commit=:download_commit, browse_url=:browse_url, issues_url=:issues_url, icon_url=:icon_url,
+                status=0, submit_date=NOW()',
+
+        'update' => 'UPDATE `as_asset_edits`
+            SET title=:title, description=:description, category_id=:category_id, version_string=:version_string, cost=:cost,
+            download_provider=:download_provider, download_commit=:download_commit, browse_url=:browse_url, issues_url=:issues_url, icon_url=:icon_url
+            WHERE edit_id=:edit_id AND status=0',
+
+        'add_preview' => 'INSERT INTO `as_asset_edit_previews`
+            SET edit_id=:edit_id, preview_id=:preview_id, type=:type, link=:link, thumbnail=:thumbnail, operation=:operation',
+        'update_preview' => 'UPDATE `as_asset_edit_previews`
+            SET type=COALESCE(:type, type), link=COALESCE(:link, link), thumbnail=COALESCE(:thumbnail, thumbnail)
+            WHERE edit_id=:edit_id AND edit_preview_id=:edit_preview_id',
+        'remove_preview' => 'DELETE FROM `as_asset_edit_previews`
+            WHERE edit_id=:edit_id AND edit_preview_id=:edit_preview_id',
+
+        'set_asset_id' => 'UPDATE `as_asset_edits` SET asset_id=:asset_id WHERE edit_id=:edit_id',
+        'set_status_and_reason' => 'UPDATE `as_asset_edits` SET status=:status, reason=:reason WHERE edit_id=:edit_id',
+    ],
 ];

+ 199 - 189
src/routes/asset.php

@@ -3,225 +3,235 @@
 
 // Searches through the list of assets
 $app->get('/asset', function ($request, $response, $args) {
-  $params = $request->getQueryParams();
-
-  $category = '%';
-  if(FRONTEND) {
-    $category_type = $this->constants['category_type']['any'];
-  } else {
-    $category_type = $this->constants['category_type']['addon'];
-  }
-  $filter = '%';
-  $username = '%';
-  $order_column = 'modify_date';
-  $order_direction = 'desc';
-  $support_levels = [];
-  $page_size = 10;
-  $max_page_size = 500;
-  $page_offset = 0;
-  if(isset($params['category']) && $params['category'] != "") {
-    $category = (int) $params['category'];
-  }
-  if(isset($params['type']) && isset($this->constants['category_type'][$params['type']])) {
-    $category_type = $this->constants['category_type'][$params['type']];
-  }
-  if(isset($params['support'])) { // Expects the param like `support=community+testing` or `support[community]=1&support[testing]=1&...`
+    $params = $request->getQueryParams();
+
+    $category = '%';
+    if (FRONTEND) {
+        $category_type = $this->constants['category_type']['any'];
+    } else {
+        $category_type = $this->constants['category_type']['addon'];
+    }
+    $filter = '%';
+    $username = '%';
+    $order_column = 'modify_date';
+    $order_direction = 'desc';
     $support_levels = [];
-    if(is_array($params['support'])) {
-      foreach($params['support'] as $key => $value) {
-        if($value && isset($this->constants['support_level'][$key])) {
-          array_push($support_levels, (int) $this->constants['support_level'][$key]);
+    $page_size = 10;
+    $max_page_size = 500;
+    $page_offset = 0;
+    if (isset($params['category']) && $params['category'] != "") {
+        $category = (int) $params['category'];
+    }
+    if (isset($params['type']) && isset($this->constants['category_type'][$params['type']])) {
+        $category_type = $this->constants['category_type'][$params['type']];
+    }
+    if (isset($params['support'])) { // Expects the param like `support=community+testing` or `support[community]=1&support[testing]=1&...`
+        $support_levels = [];
+        if (is_array($params['support'])) {
+            foreach ($params['support'] as $key => $value) {
+                if ($value && isset($this->constants['support_level'][$key])) {
+                    array_push($support_levels, (int) $this->constants['support_level'][$key]);
+                }
+            }
+        } else {
+            foreach (explode(' ', $params['support']) as $key => $value) { // `+` is changed to ` ` automatically
+                if (isset($this->constants['support_level'][$value])) {
+                    array_push($support_levels, (int) $this->constants['support_level'][$value]);
+                }
+            }
         }
-      }
-    } else {
-      foreach(explode(' ', $params['support']) as $key => $value) { // `+` is changed to ` ` automatically
-        if(isset($this->constants['support_level'][$value])) {
-          array_push($support_levels, (int) $this->constants['support_level'][$value]);
+    }
+    if (isset($params['filter'])) {
+        $filter = '%'.preg_replace('/[[:punct:]]+/', '%', $params['filter']).'%';
+    }
+    if (isset($params['user'])) {
+        $username = $params['user'];
+    }
+    if (isset($params['max_results'])) {
+        $page_size = min(abs((int) $params['max_results']), $max_page_size);
+    }
+    if (isset($params['page'])) {
+        $page_offset = abs((int) $params['page']) * $page_size;
+    } elseif (isset($params['offset'])) {
+        $page_offset = abs((int) $params['offset']);
+    }
+    if (isset($params['sort'])) {
+        $column_mapping = [
+            'rating' => 'rating',
+            'cost' => 'cost',
+            'name' => 'title',
+            'updated' => 'modify_date'
+            // TODO: downloads
+        ];
+        if (isset($column_mapping[$params['sort']])) {
+            $order_column = $column_mapping[$params['sort']];
         }
-      }
-    }
-  }
-  if(isset($params['filter'])) {
-    $filter = '%'.preg_replace('/[[:punct:]]+/', '%', $params['filter']).'%';
-  }
-  if(isset($params['user'])) {
-    $username = $params['user'];
-  }
-  if(isset($params['max_results'])) {
-    $page_size = min(abs((int) $params['max_results']), $max_page_size);
-  }
-  if(isset($params['page'])) {
-    $page_offset = abs((int) $params['page']) * $page_size;
-  } elseif(isset($params['offset'])) {
-    $page_offset = abs((int) $params['offset']);
-  }
-  if(isset($params['sort'])) {
-    $column_mapping = [
-      'rating' => 'rating',
-      'cost' => 'cost',
-      'name' => 'title',
-      'updated' => 'modify_date'
-      // TODO: downloads
-    ];
-    if(isset($column_mapping[$params['sort']])) {
-      $order_column = $column_mapping[$params['sort']];
-    }
-  }
-  if(isset($params['reverse'])) {
-    $order_direction = 'asc';
-  }
-
-  if(count($support_levels) === 0) {
-    $support_levels = [0, 1, 2]; // Testing + Community + Official
-  }
-  $support_levels = implode('|', $support_levels);
-
-  $query = $this->queries['asset']['search'];
-  $query->bindValue(':category', $category);
-  $query->bindValue(':category_type', $category_type, PDO::PARAM_INT);
-  $query->bindValue(':support_levels_regex', $support_levels);
-  $query->bindValue(':filter', $filter);
-  $query->bindValue(':username', $username);
-  $query->bindValue(':order', $order_column);
-  $query->bindValue(':order_direction', $order_direction);
-  $query->bindValue(':page_size', $page_size, PDO::PARAM_INT);
-  $query->bindValue(':skip_count', $page_offset, PDO::PARAM_INT);
-  $query->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
-
-  $query_count = $this->queries['asset']['search_count'];
-  $query_count->bindValue(':category', $category, PDO::PARAM_INT);
-  $query_count->bindValue(':category_type', $category_type, PDO::PARAM_INT);
-  $query_count->bindValue(':support_levels_regex', $support_levels);
-  $query_count->bindValue(':filter', $filter);
-  $query_count->bindValue(':username', $username);
-  $query_count->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_count);
-  if($error) return $response;
-
-  $total_count = $query_count->fetchAll()[0]['count'];
-
-  $assets = $query->fetchAll();
-
-  $context = $this;
-  $assets = array_map(function($asset) use($context) {
-    $asset["support_level"] = $context->constants['support_level'][(int) $asset['support_level']];
-    return $asset;
-  }, $assets);
-
-  return $response->withJson([
-    'result' => $assets,
-    'page' => floor($page_offset / $page_size),
-    'pages' => ceil($total_count / $page_size),
-    'page_length' => $page_size,
-    'total_items' => (int) $total_count,
-  ], 200);
+    }
+    if (isset($params['reverse'])) {
+        $order_direction = 'asc';
+    }
+
+    if (count($support_levels) === 0) {
+        $support_levels = [0, 1, 2]; // Testing + Community + Official
+    }
+    $support_levels = implode('|', $support_levels);
+
+    $query = $this->queries['asset']['search'];
+    $query->bindValue(':category', $category);
+    $query->bindValue(':category_type', $category_type, PDO::PARAM_INT);
+    $query->bindValue(':support_levels_regex', $support_levels);
+    $query->bindValue(':filter', $filter);
+    $query->bindValue(':username', $username);
+    $query->bindValue(':order', $order_column);
+    $query->bindValue(':order_direction', $order_direction);
+    $query->bindValue(':page_size', $page_size, PDO::PARAM_INT);
+    $query->bindValue(':skip_count', $page_offset, PDO::PARAM_INT);
+    $query->execute();
+
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
+
+    $query_count = $this->queries['asset']['search_count'];
+    $query_count->bindValue(':category', $category, PDO::PARAM_INT);
+    $query_count->bindValue(':category_type', $category_type, PDO::PARAM_INT);
+    $query_count->bindValue(':support_levels_regex', $support_levels);
+    $query_count->bindValue(':filter', $filter);
+    $query_count->bindValue(':username', $username);
+    $query_count->execute();
+
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_count);
+    if ($error) {
+        return $response;
+    }
+
+    $total_count = $query_count->fetchAll()[0]['count'];
+
+    $assets = $query->fetchAll();
+
+    $context = $this;
+    $assets = array_map(function ($asset) use ($context) {
+        $asset["support_level"] = $context->constants['support_level'][(int) $asset['support_level']];
+        return $asset;
+    }, $assets);
+
+    return $response->withJson([
+        'result' => $assets,
+        'page' => floor($page_offset / $page_size),
+        'pages' => ceil($total_count / $page_size),
+        'page_length' => $page_size,
+        'total_items' => (int) $total_count,
+    ], 200);
 });
 
 // Get information for a single asset
 $get_asset = function ($request, $response, $args) {
-  $query = $this->queries['asset']['get_one'];
+    $query = $this->queries['asset']['get_one'];
 
-  $query->bindValue(':id', (int) $args['id'], PDO::PARAM_INT);
-  $query->execute();
+    $query->bindValue(':id', (int) $args['id'], PDO::PARAM_INT);
+    $query->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-  if($query->rowCount() <= 0) {
-    return $response->withJson([
-      'error' => 'Couldn\'t find asset with id '.$args['id'].'!'
-    ], 404);
-  }
-
-  $output = $query->fetchAll();
-  $asset_info = [];
-  $previews = [];
-
-  foreach ($output as $row) {
-    foreach ($row as $column => $value) {
-      if($value!==null) {
-        if($column==='preview_id') {
-          $previews[] = ['preview_id' => $value];
-        } elseif($column==="type" || $column==="link" || $column==="thumbnail") {
-            $previews[count($previews) - 1][$column] = $value;
-        } elseif($column==="category_type") {
-          $asset_info["type"] = $this->constants['category_type'][(int) $value];
-        } elseif($column==="support_level") {
-          $asset_info["support_level"] = $this->constants['support_level'][(int) $value];
-        } elseif($column==="download_provider") {
-          $asset_info["download_provider"] = $this->constants['download_provider'][(int) $value];
-        } else {
-          $asset_info[$column] = $value;
+    if ($query->rowCount() <= 0) {
+        return $response->withJson([
+            'error' => 'Couldn\'t find asset with id '.$args['id'].'!'
+        ], 404);
+    }
+
+    $output = $query->fetchAll();
+    $asset_info = [];
+    $previews = [];
+
+    foreach ($output as $row) {
+        foreach ($row as $column => $value) {
+            if ($value!==null) {
+                if ($column==='preview_id') {
+                    $previews[] = ['preview_id' => $value];
+                } elseif ($column==="type" || $column==="link" || $column==="thumbnail") {
+                    $previews[count($previews) - 1][$column] = $value;
+                } elseif ($column==="category_type") {
+                    $asset_info["type"] = $this->constants['category_type'][(int) $value];
+                } elseif ($column==="support_level") {
+                    $asset_info["support_level"] = $this->constants['support_level'][(int) $value];
+                } elseif ($column==="download_provider") {
+                    $asset_info["download_provider"] = $this->constants['download_provider'][(int) $value];
+                } else {
+                    $asset_info[$column] = $value;
+                }
+            }
         }
-      }
     }
-  }
 
-  $asset_info['download_url'] = $this->utils->get_computed_download_url($asset_info['browse_url'], $asset_info['download_provider'], $asset_info['download_commit']);
-  if($asset_info['issues_url'] == '') {
-    $asset_info['issues_url'] = $this->utils->get_default_issues_url($asset_info['browse_url'], $asset_info['download_provider']);
-  }
+    $asset_info['download_url'] = $this->utils->getComputedDownloadUrl($asset_info['browse_url'], $asset_info['download_provider'], $asset_info['download_commit']);
+    if ($asset_info['issues_url'] == '') {
+        $asset_info['issues_url'] = $this->utils->getDefaultIssuesUrl($asset_info['browse_url'], $asset_info['download_provider']);
+    }
 
 
-  foreach ($previews as $i => $_) {
-    if(!isset($previews[$i]['thumbnail']) || $previews[$i]['thumbnail'] == '') {
-      if($previews[$i]['type'] == 'video') {
-        $matches = [];
-        if(preg_match('|youtube.com/watch\\?v=([^&]+)|', $previews[$i]['link'], $matches)) {
-          $previews[$i]['thumbnail'] = 'http://img.youtube.com/vi/'.$matches[1].'/default.jpg';
+    foreach ($previews as $i => $_) {
+        if (!isset($previews[$i]['thumbnail']) || $previews[$i]['thumbnail'] == '') {
+            if ($previews[$i]['type'] == 'video') {
+                $matches = [];
+                if (preg_match('|youtube.com/watch\\?v=([^&]+)|', $previews[$i]['link'], $matches)) {
+                    $previews[$i]['thumbnail'] = 'http://img.youtube.com/vi/'.$matches[1].'/default.jpg';
+                }
+            } else {
+                $previews[$i]['thumbnail'] = $previews[$i]['link'];
+            }
         }
-      } else {
-        $previews[$i]['thumbnail'] = $previews[$i]['link'];
-      }
     }
-  }
 
-  $asset_info['previews'] = $previews;
+    $asset_info['previews'] = $previews;
 
-  return $response->withJson($asset_info, 200);
+    return $response->withJson($asset_info, 200);
 };
 // Binding to multiple routes
 $app->get('/asset/{id:[0-9]+}', $get_asset);
-if(FRONTEND) {
-  $app->get('/asset/{id:[0-9]+}/edit', $get_asset);
+if (FRONTEND) {
+    $app->get('/asset/{id:[0-9]+}/edit', $get_asset);
 }
 
 // Change support level of an asset
 $app->post('/asset/{id:[0-9]+}/support_level', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  $error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'moderator');
-  $error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'support_level');
-  if($error) return $response;
-  if(!isset($this->constants['support_level'][$body['support_level']])) {
-    $numeric_value_keys = [];
-    foreach ($this->constants['support_level'] as $key => $value) {
-      if((int) $value === $value) {
-        array_push($numeric_value_keys, $key);
-      }
+    $body = $request->getParsedBody();
+
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    $error = $this->utils->errorResponseIfNotUserHasLevel($error, $response, $user, 'moderator');
+    $error = $this->utils->errorResponseIfMissingOrNotString($error, $response, $body, 'support_level');
+    if ($error) {
+        return $response;
+    }
+    if (!isset($this->constants['support_level'][$body['support_level']])) {
+        $numeric_value_keys = [];
+        foreach ($this->constants['support_level'] as $key => $value) {
+            if ((int) $value === $value) {
+                array_push($numeric_value_keys, $key);
+            }
+        }
+        return $response->withJson([
+            'error' => 'Invalid support level submitted, allowed are \'' . implode('\', \'', $numeric_value_keys) . '\'',
+        ]);
     }
-    return $response->withJson([
-      'error' => 'Invalid support level submitted, allowed are \'' . implode('\', \'', $numeric_value_keys) . '\'',
-    ]);
-  }
 
-  $query = $this->queries['asset']['set_support_level'];
+    $query = $this->queries['asset']['set_support_level'];
 
-  $query->bindValue(':asset_id', (int) $args['id'], PDO::PARAM_INT);
-  $query->bindValue(':support_level', (int) $this->constants['support_level'][$body['support_level']], PDO::PARAM_INT);
+    $query->bindValue(':asset_id', (int) $args['id'], PDO::PARAM_INT);
+    $query->bindValue(':support_level', (int) $this->constants['support_level'][$body['support_level']], PDO::PARAM_INT);
 
-  $query->execute();
+    $query->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-  return $response->withJson([
-    'changed' => true,
-    'url' => 'asset/' . $args['id'],
-  ], 200);
+    return $response->withJson([
+        'changed' => true,
+        'url' => 'asset/' . $args['id'],
+    ], 200);
 });

+ 683 - 603
src/routes/asset_edit.php

@@ -1,767 +1,847 @@
 <?php
 // Asset editing routes
 
-function _submit_asset_edit($c, $response, $body, $user_id, $asset_id=-1) {
-  $query = $c->queries['asset_edit']['submit'];
-  $query->bindValue(':user_id', $user_id, PDO::PARAM_INT);
-  $query->bindValue(':asset_id', $asset_id, PDO::PARAM_INT);
-  if($asset_id == -1) {
-    $error = _insert_asset_edit_fields($c, false, $response, $query, $body, true);
-    if($error) return $response;
-  } else {
-    $query_asset = $c->queries['asset']['get_one_bare'];
-    $query_asset->bindValue(':asset_id', (int) $asset_id, PDO::PARAM_INT);
-    $query_asset->execute();
+function _submit_asset_edit($c, $response, $body, $user_id, $asset_id=-1)
+{
+    $query = $c->queries['asset_edit']['submit'];
+    $query->bindValue(':user_id', $user_id, PDO::PARAM_INT);
+    $query->bindValue(':asset_id', $asset_id, PDO::PARAM_INT);
+    if ($asset_id == -1) {
+        $error = _insert_asset_edit_fields($c, false, $response, $query, $body, true);
+        if ($error) {
+            return $response;
+        }
+    } else {
+        $query_asset = $c->queries['asset']['get_one_bare'];
+        $query_asset->bindValue(':asset_id', (int) $asset_id, PDO::PARAM_INT);
+        $query_asset->execute();
 
-    $error = $c->utils->error_reponse_if_query_bad(false, $response, $query_asset);
-    if($error) return $response;
+        $error = $c->utils->errorResponseIfQueryBad(false, $response, $query_asset);
+        if ($error) {
+            return $response;
+        }
 
-    $asset = $query_asset->fetchAll()[0];
+        $asset = $query_asset->fetchAll()[0];
 
-    $error = _insert_asset_edit_fields($c, false, $response, $query, $body, false, $asset);
-    if($error) return $response;
-  }
+        $error = _insert_asset_edit_fields($c, false, $response, $query, $body, false, $asset);
+        if ($error) {
+            return $response;
+        }
+    }
 
-  // Make a transaction, so we can roll back failed submissions
-  $c->db->beginTransaction();
+    // Make a transaction, so we can roll back failed submissions
+    $c->db->beginTransaction();
 
-  $query->execute();
-  $error = $c->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) {
-    $c->db->rollback();
-    return $response;
-  }
+    $query->execute();
+    $error = $c->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        $c->db->rollback();
+        return $response;
+    }
 
-  $id = $c->db->lastInsertId();
+    $id = $c->db->lastInsertId();
 
-  if(isset($body['previews'])) {
-    $error = _add_previews_to_edit($c, $error, $response, $id, $body['previews'], null, $asset_id==-1);
-    if($error) {
-      $c->db->rollback();
-      return $response;
+    if (isset($body['previews'])) {
+        $error = _add_previews_to_edit($c, $error, $response, $id, $body['previews'], null, $asset_id==-1);
+        if ($error) {
+            $c->db->rollback();
+            return $response;
+        }
     }
-  }
 
-  $c->db->commit();
+    $c->db->commit();
 
-  return $response->withJson([
-    'id' => $id,
-    'url' => 'asset/edit/' . $id,
-  ], 200);
+    return $response->withJson([
+        'id' => $id,
+        'url' => 'asset/edit/' . $id,
+    ], 200);
 }
 
-function _insert_asset_edit_fields($c, $error, &$response, $query, $body, $required=false, $bare_asset=null) {
-  if($error) return true;
+function _insert_asset_edit_fields($c, $error, &$response, $query, $body, $required=false, $bare_asset=null)
+{
+    if ($error) {
+        return true;
+    }
 
-  if(isset($body['download_provider'])) {
-    if(isset($c->constants['download_provider'][$body['download_provider']])) {
-      $body['download_provider'] = (string) ((int) $c->constants['download_provider'][$body['download_provider']]);
-    } else {
-      $body['download_provider'] = 0;
-    }
-  }
-  if(isset($body['issues_url'])) {
-    $default_issues_url = null;
-    if(isset($body['browse_url']) && isset($body['download_provider'])) {
-      $default_issues_url = $c->utils->get_default_issues_url(
-        $body['browse_url'],
-        intval($body['download_provider'])
-      );
-    } else if($bare_asset !== null) {
-      $default_issues_url = $c->utils->get_default_issues_url(
-        $body['browse_url'] ?: $bare_asset['browse_url'],
-        intval($body['download_provider'] ?: $bare_asset['download_provider'])
-      );
-    }
-    if($default_issues_url !== null && $default_issues_url == $body['issues_url']) {
-      unset($body['issues_url']);
-    }
-  }
-
-  foreach ($c->constants['asset_edit_fields'] as $i => $field) {
-    if(!$required) {
-      if(isset($body[$field]) && ($bare_asset === null || $bare_asset[$field] != $body[$field])) {
-        $query->bindValue(':' . $field, $body[$field]);
-      } else {
-        $query->bindValue(':' . $field, null, PDO::PARAM_NULL);
-      }
-    } else {
-      if($bare_asset === null) {
-        if($field == 'issues_url') { // Default value present, so, no need to error out
-          if(isset($body[$field])) {
-            $query->bindValue(':' . $field, $body[$field]);
-          } else {
-            $query->bindValue(':' . $field, '', PDO::PARAM_NULL);
-          }
+    if (isset($body['download_provider'])) {
+        if (isset($c->constants['download_provider'][$body['download_provider']])) {
+            $body['download_provider'] = (string) ((int) $c->constants['download_provider'][$body['download_provider']]);
         } else {
-          $error = $c->utils->error_reponse_if_missing_or_not_string($error, $response, $body, $field);
-          if(!$error) $query->bindValue(':' . $field, $body[$field]);
+            $body['download_provider'] = 0;
         }
-      } else { // "Required" (so, non-null), but there is a base asset, so we can support incremental changes
-        if(isset($body[$field])) {
-          $query->bindValue(':' . $field, $body[$field]);
-        } else {
-          $query->bindValue(':' . $field, $bare_asset[$field]);
+    }
+    if (isset($body['issues_url'])) {
+        $default_issues_url = null;
+        if (isset($body['browse_url']) && isset($body['download_provider'])) {
+            $default_issues_url = $c->utils->getDefaultIssuesUrl(
+                $body['browse_url'],
+                intval($body['download_provider'])
+            );
+        } elseif ($bare_asset !== null) {
+            $default_issues_url = $c->utils->getDefaultIssuesUrl(
+                $body['browse_url'] ?: $bare_asset['browse_url'],
+                intval($body['download_provider'] ?: $bare_asset['download_provider'])
+            );
+        }
+        if ($default_issues_url !== null && $default_issues_url == $body['issues_url']) {
+            unset($body['issues_url']);
         }
-
-      }
     }
 
-    if($error) {
-      return $error;
+    foreach ($c->constants['asset_edit_fields'] as $i => $field) {
+        if (!$required) {
+            if (isset($body[$field]) && ($bare_asset === null || $bare_asset[$field] != $body[$field])) {
+                $query->bindValue(':' . $field, $body[$field]);
+            } else {
+                $query->bindValue(':' . $field, null, PDO::PARAM_NULL);
+            }
+        } else {
+            if ($bare_asset === null) {
+                if ($field == 'issues_url') { // Default value present, so, no need to error out
+                    if (isset($body[$field])) {
+                        $query->bindValue(':' . $field, $body[$field]);
+                    } else {
+                        $query->bindValue(':' . $field, '', PDO::PARAM_NULL);
+                    }
+                } else {
+                    $error = $c->utils->errorResponseIfMissingOrNotString($error, $response, $body, $field);
+                    if (!$error) {
+                        $query->bindValue(':' . $field, $body[$field]);
+                    }
+                }
+            } else { // "Required" (so, non-null), but there is a base asset, so we can support incremental changes
+                if (isset($body[$field])) {
+                    $query->bindValue(':' . $field, $body[$field]);
+                } else {
+                    $query->bindValue(':' . $field, $bare_asset[$field]);
+                }
+            }
+        }
+
+        if ($error) {
+            return $error;
+        }
     }
-  }
-  return $error;
+    return $error;
 }
 
-function _add_previews_to_edit($c, $error, &$response, $edit_id, $previews, $asset=null, $required=false) {
-  if($error) return true;
-
-  foreach ($previews as $i => $preview) {
-    if(!isset($preview['enabled']) || !$preview['enabled']) continue;
-    if($required || !isset($preview['edit_preview_id'])) {
-
-      $query = $c->queries['asset_edit']['add_preview'];
-
-      $error = $c->utils->error_reponse_if_missing_or_not_string($error, $response, $preview, 'operation');
-      if($error) return $error;
+function _add_previews_to_edit($c, $error, &$response, $edit_id, $previews, $asset=null, $required=false)
+{
+    if ($error) {
+        return true;
+    }
 
-      $operation = $c->constants['edit_preview_operation']['insert'];
+    foreach ($previews as $i => $preview) {
+        if (!isset($preview['enabled']) || !$preview['enabled']) {
+            continue;
+        }
+        if ($required || !isset($preview['edit_preview_id'])) {
+            $query = $c->queries['asset_edit']['add_preview'];
+
+            $error = $c->utils->errorResponseIfMissingOrNotString($error, $response, $preview, 'operation');
+            if ($error) {
+                return $error;
+            }
+
+            $operation = $c->constants['edit_preview_operation']['insert'];
+
+            if (!$required && $asset !== null && isset($c->constants['edit_preview_operation'][$preview['operation']])) {
+                $operation = $c->constants['edit_preview_operation'][$preview['operation']];
+            }
+            $query->bindValue(':operation', (int) $operation, PDO::PARAM_INT);
+
+            if ($operation == $c->constants['edit_preview_operation']['insert']) {
+                $query->bindValue(':preview_id', -1, PDO::PARAM_INT);
+            } else {
+                $error = $c->utils->errorResponseIfMissingOrNotString($error, $response, $preview, 'preview_id');
+                if ($error) {
+                    return $error;
+                }
+
+                if ($asset !== null) {
+                    $query_check = $c->queries['asset']['get_one_preview_bare'];
+                    $query_check->bindValue(':preview_id', (int) $preview['preview_id'], PDO::PARAM_INT);
+                    $query_check->execute();
+                    $error = $c->utils->errorResponseIfQueryBad(false, $response, $query_check);
+                    $error = $c->utils->errorResponseIfQueryNoResults($error, $response, $query_check);
+                    if ($error) {
+                        return $error;
+                    }
+
+                    $original_preview = $query_check->fetchAll()[0];
+                    if ($original_preview['asset_id'] != $asset['asset_id']) {
+                        $response = $response->withJson(['error' => 'Invalid preview id.'], 400);
+                        return true;
+                    }
+                } else {
+                    $response = $response->withJson(['error' => 'Bug in processing code, please report.'], 500);
+                    return true;
+                }
+
+                $query->bindValue(':preview_id', (int) $preview['preview_id'], PDO::PARAM_INT);
+            }
+        } elseif (isset($preview['remove']) && $preview['remove']) {
+            $query = $c->queries['asset_edit']['remove_preview'];
+            $query->bindValue(':edit_preview_id', (int) $preview['edit_preview_id'], PDO::PARAM_INT);
+            $query->bindValue(':edit_id', (int) $edit_id, PDO::PARAM_INT);
+            $query->execute();
+            $error = $c->utils->errorResponseIfQueryBad(false, $response, $query);
+            if ($error) {
+                return $error;
+            }
+
+            continue;
+        } else {
+            $query = $c->queries['asset_edit']['update_preview'];
+            $error = $c->utils->errorResponseIfMissingOrNotString($error, $response, $preview, 'edit_preview_id');
+            if ($error) {
+                return $error;
+            }
+            $query->bindValue(':edit_preview_id', (int) $preview['edit_preview_id'], PDO::PARAM_INT);
+        }
+        $query->bindValue(':edit_id', (int) $edit_id, PDO::PARAM_INT);
+
+        foreach ($c->constants['asset_edit_preview_fields'] as $i => $field) {
+            if (!$required) {
+                if (isset($preview[$field]) && !(isset($original_preview) && $original_preview[$field] == $preview[$field])) {
+                    $query->bindValue(':' . $field, $preview[$field]);
+                } elseif (!isset($preview[$field]) && !isset($original_preview)) {
+                    $query->bindValue(':' . $field, $preview[$field]);
+                } else {
+                    $query->bindValue(':' . $field, null, PDO::PARAM_NULL);
+                }
+            } else {
+                $error = $c->utils->errorResponseIfMissingOrNotString($error, $response, $preview, $field);
+                if (!$error) {
+                    $query->bindValue(':' . $field, $preview[$field]);
+                }
+            }
+        }
+        if ($error) {
+            return $error;
+        }
 
-      if(!$required && $asset !== null && isset($c->constants['edit_preview_operation'][$preview['operation']])) {
-        $operation = $c->constants['edit_preview_operation'][$preview['operation']];
-      }
-      $query->bindValue(':operation',(int) $operation, PDO::PARAM_INT);
+        $query->execute();
+        $error = $c->utils->errorResponseIfQueryBad(false, $response, $query);
+        if ($error) {
+            return $error;
+        }
+    }
 
-      if($operation == $c->constants['edit_preview_operation']['insert']) {
-        $query->bindValue(':preview_id', -1, PDO::PARAM_INT);
-      } else {
-        $error = $c->utils->error_reponse_if_missing_or_not_string($error, $response, $preview, 'preview_id');
-        if($error) return $error;
+    return $error;
+}
 
-        if($asset !== null) {
-          $query_check = $c->queries['asset']['get_one_preview_bare'];
-          $query_check->bindValue(':preview_id', (int) $preview['preview_id'], PDO::PARAM_INT);
-          $query_check->execute();
-          $error = $c->utils->error_reponse_if_query_bad(false, $response, $query_check);
-          $error = $c->utils->error_reponse_if_query_no_results($error, $response, $query_check);
-          if($error) return $error;
+$app->get('/asset/edit', function ($request, $response, $args) {
 
-          $original_preview = $query_check->fetchAll()[0];
-          if($original_preview['asset_id'] != $asset['asset_id']) {
-            $response = $response->withJson(['error' => 'Invalid preview id.'], 400);
-            return true;
-          }
+    // Enable if needed (for now, transparent to all) [Also change request to post]
+    // $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    // $error = $this->utils->errorResponseIfNotUserHasLevel($error, $response, $user, 'moderator');
+    // if ($error) {
+    //     return $response;
+    // }
+
+    $params = $request->getQueryParams();
+
+    $asset_id = '%';
+    $filter = '%';
+    $username = '%';
+    $statuses = [];
+    $page_size = 10;
+    $max_page_size = 500;
+    $page_offset = 0;
+    if (isset($params['asset'])) {
+        $asset_id = (int) $params['asset'];
+    }
+    if (isset($params['status'])) { // Expects the param like `new+in_review`
+        if (is_array($params['status'])) {
+            foreach ($params['status'] as $key => $value) {
+                if ($value && isset($this->constants['edit_status'][$key])) {
+                    array_push($statuses, (int) $this->constants['edit_status'][$key]);
+                }
+            }
         } else {
-          $response = $response->withJson(['error' => 'Bug in processing code, please report.'], 500);
-          return true;
+            foreach (explode(' ', $params['status']) as $key => $value) { // `+` is changed to ` ` automatically
+                if (isset($this->constants['edit_status'][$value])) {
+                    array_push($statuses, (int) $this->constants['edit_status'][$value]);
+                }
+            }
         }
+    }
+    if (isset($params['filter'])) {
+        $filter = '%'.preg_replace('/[[:punct:]]+/', '%', $params['filter']).'%';
+    }
+    if (isset($params['user'])) {
+        $username = $params['user'];
+    }
+    if (isset($params['max_results'])) {
+        $page_size = min(abs((int) $params['max_results']), $max_page_size);
+    }
+    if (isset($params['page'])) {
+        $page_offset = abs((int) $params['page']) * $page_size;
+    } elseif (isset($params['offset'])) {
+        $page_offset = abs((int) $params['offset']);
+    }
 
-        $query->bindValue(':preview_id', (int) $preview['preview_id'], PDO::PARAM_INT);
-      }
+    if (count($statuses) === 0) {
+        $statuses = [0, 1]; // New + In Review
+    }
+    $statuses = implode('|', $statuses);
+
+    $query = $this->queries['asset_edit']['search'];
+    $query->bindValue(':filter', $filter);
+    $query->bindValue(':username', $username);
+    $query->bindValue(':asset_id', $asset_id);
+    $query->bindValue(':statuses_regex', $statuses);
+    $query->bindValue(':page_size', $page_size, PDO::PARAM_INT);
+    $query->bindValue(':skip_count', $page_offset, PDO::PARAM_INT);
+    $query->execute();
 
-    } elseif(isset($preview['remove']) && $preview['remove']) {
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-      $query = $c->queries['asset_edit']['remove_preview'];
-      $query->bindValue(':edit_preview_id', (int) $preview['edit_preview_id'], PDO::PARAM_INT);
-      $query->bindValue(':edit_id', (int) $edit_id, PDO::PARAM_INT);
-      $query->execute();
-      $error = $c->utils->error_reponse_if_query_bad(false, $response, $query);
-      if($error) return $error;
+    $query_count = $this->queries['asset_edit']['search_count'];
+    $query_count->bindValue(':filter', $filter);
+    $query_count->bindValue(':username', $username);
+    $query_count->bindValue(':asset_id', $asset_id);
+    $query_count->bindValue(':statuses_regex', $statuses);
+    $query_count->execute();
 
-      continue;
-    } else {
-      $query = $c->queries['asset_edit']['update_preview'];
-      $error = $c->utils->error_reponse_if_missing_or_not_string($error, $response, $preview, 'edit_preview_id');
-      if($error) return $error;
-      $query->bindValue(':edit_preview_id', (int) $preview['edit_preview_id'], PDO::PARAM_INT);
-    }
-    $query->bindValue(':edit_id', (int) $edit_id, PDO::PARAM_INT);
-
-    foreach ($c->constants['asset_edit_preview_fields'] as $i => $field) {
-      if(!$required) {
-        if(isset($preview[$field]) && !(isset($original_preview) && $original_preview[$field] == $preview[$field])) {
-          $query->bindValue(':' . $field, $preview[$field]);
-        } elseif(!isset($preview[$field]) && !isset($original_preview)) {
-          $query->bindValue(':' . $field, $preview[$field]);
-        } else {
-          $query->bindValue(':' . $field, null, PDO::PARAM_NULL);
-        }
-      } else {
-        $error = $c->utils->error_reponse_if_missing_or_not_string($error, $response, $preview, $field);
-        if(!$error) $query->bindValue(':' . $field, $preview[$field]);
-      }
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_count);
+    if ($error) {
+        return $response;
     }
-    if($error) return $error;
 
-    $query->execute();
-    $error = $c->utils->error_reponse_if_query_bad(false, $response, $query);
-    if($error) return $error;
-  }
+    $total_count = $query_count->fetchAll()[0]['count'];
 
-  return $error;
-}
+    $asset_edits = $query->fetchAll();
 
-$app->get('/asset/edit', function ($request, $response, $args) {
+    $context = $this;
+    $asset_edits = array_map(function ($asset_edit) use ($context) {
+        $asset_edit['status'] = $context->constants['edit_status'][(int) $asset_edit['status']];
+        $asset_edit['support_level'] = $context->constants['support_level'][(int) $asset_edit['support_level']];
+        return $asset_edit;
+    }, $asset_edits);
 
-  // Enable if needed (for now, transparent to all) [Also change request to post]
-  // $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  // $error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'moderator');
-  // if($error) return $response;
-
-  $params = $request->getQueryParams();
-
-  $asset_id = '%';
-  $filter = '%';
-  $username = '%';
-  $statuses = [];
-  $page_size = 10;
-  $max_page_size = 500;
-  $page_offset = 0;
-  if(isset($params['asset'])) {
-    $asset_id = (int) $params['asset'];
-  }
-  if(isset($params['status'])) { // Expects the param like `new+in_review`
-    if(is_array($params['status'])) {
-      foreach($params['status'] as $key => $value) {
-        if($value && isset($this->constants['edit_status'][$key])) {
-          array_push($statuses, (int) $this->constants['edit_status'][$key]);
-        }
-      }
-    } else {
-      foreach(explode(' ', $params['status']) as $key => $value) { // `+` is changed to ` ` automatically
-        if(isset($this->constants['edit_status'][$value])) {
-          array_push($statuses, (int) $this->constants['edit_status'][$value]);
-        }
-      }
-    }
-  }
-  if(isset($params['filter'])) {
-    $filter = '%'.preg_replace('/[[:punct:]]+/', '%', $params['filter']).'%';
-  }
-  if(isset($params['user'])) {
-    $username = $params['user'];
-  }
-  if(isset($params['max_results'])) {
-    $page_size = min(abs((int) $params['max_results']), $max_page_size);
-  }
-  if(isset($params['page'])) {
-    $page_offset = abs((int) $params['page']) * $page_size;
-  } elseif(isset($params['offset'])) {
-    $page_offset = abs((int) $params['offset']);
-  }
-
-  if(count($statuses) === 0) {
-    $statuses = [0, 1]; // New + In Review
-  }
-  $statuses = implode('|', $statuses);
-
-  $query = $this->queries['asset_edit']['search'];
-  $query->bindValue(':filter', $filter);
-  $query->bindValue(':username', $username);
-  $query->bindValue(':asset_id', $asset_id);
-  $query->bindValue(':statuses_regex', $statuses);
-  $query->bindValue(':page_size', $page_size, PDO::PARAM_INT);
-  $query->bindValue(':skip_count', $page_offset, PDO::PARAM_INT);
-  $query->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
-
-  $query_count = $this->queries['asset_edit']['search_count'];
-  $query_count->bindValue(':filter', $filter);
-  $query_count->bindValue(':username', $username);
-  $query_count->bindValue(':asset_id', $asset_id);
-  $query_count->bindValue(':statuses_regex', $statuses);
-  $query_count->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_count);
-  if($error) return $response;
-
-  $total_count = $query_count->fetchAll()[0]['count'];
-
-  $asset_edits = $query->fetchAll();
-
-  $context = $this;
-  $asset_edits = array_map(function($asset_edit) use($context) {
-    $asset_edit['status'] = $context->constants['edit_status'][(int) $asset_edit['status']];
-    $asset_edit['support_level'] = $context->constants['support_level'][(int) $asset_edit['support_level']];
-    return $asset_edit;
-  }, $asset_edits);
-
-  return $response->withJson([
-    'result' => $asset_edits,
-    'page' => floor($page_offset / $page_size),
-    'pages' => ceil($total_count / $page_size),
-    'page_length' => $page_size,
-    'total_items' => (int) $total_count,
-  ], 200);
+    return $response->withJson([
+        'result' => $asset_edits,
+        'page' => floor($page_offset / $page_size),
+        'pages' => ceil($total_count / $page_size),
+        'page_length' => $page_size,
+        'total_items' => (int) $total_count,
+    ], 200);
 });
 
 // Get an edit
 $get_edit = function ($request, $response, $args) {
-  $query = $this->queries['asset_edit']['get_one'];
-  $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  $error = $this->utils->error_reponse_if_query_no_results($error, $response, $query);
-  if($error) return $response;
-
-  $output = $query->fetchAll();
-
-  $previews = [];
-  $previews_last_i = null;
-  $unedited_previews = [];
-  $unedited_previews_last_i = null;
-  $asset_edit = [];
-
-  foreach ($output as $row) {
-
-    foreach ($row as $column => $value) {
-      if($previews_last_i !== null && ($column==='preview_id' || $column==='type' || $column==='link' || $column==='thumbnail')) {
-        $previews[$previews_last_i][$column] = $value;
-      } elseif($previews_last_i !== null && $column==='operation') {
-        $previews[$previews_last_i][$column] = $this->constants['edit_preview_operation'][(int) $value];
-      } elseif($unedited_previews_last_i !== null && ($column==='unedited_type' || $column==='unedited_link' || $column==='unedited_thumbnail')) {
-        $unedited_previews[$unedited_previews_last_i][substr($column, strlen('unedited_'))] = $value;
-      }  elseif($column==='orig_type' || $column==='orig_link' || $column==='orig_thumbnail') {
-        if($value != null && $previews_last_i !== null) {
-          $previews[$previews_last_i]['original'][substr($column, strlen('orig_'))] = $value;
-        }
-      } elseif($value!==null) {
-        if($column==='edit_preview_id') {
-          $previews[$value] = ['edit_preview_id' => $value];
-          $previews_last_i = $value;
-        } elseif($column==='unedited_preview_id') {
-          $unedited_previews[$value] = ['preview_id' => $value];
-          $unedited_previews_last_i = $value;
-        } elseif($column==='status') {
-          $asset_edit['status'] = $this->constants['edit_status'][(int) $value];
-        } elseif($column==='download_provider') {
-          $asset_edit['download_provider'] = $this->constants['download_provider'][(int) $value];
-        } else {
-          $asset_edit[$column] = $value;
+    $query = $this->queries['asset_edit']['get_one'];
+    $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query->execute();
+
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    $error = $this->utils->errorResponseIfQueryNoResults($error, $response, $query);
+    if ($error) {
+        return $response;
+    }
+
+    $output = $query->fetchAll();
+
+    $previews = [];
+    $previews_last_i = null;
+    $unedited_previews = [];
+    $unedited_previews_last_i = null;
+    $asset_edit = [];
+
+    foreach ($output as $row) {
+        foreach ($row as $column => $value) {
+            if ($previews_last_i !== null && ($column==='preview_id' || $column==='type' || $column==='link' || $column==='thumbnail')) {
+                $previews[$previews_last_i][$column] = $value;
+            } elseif ($previews_last_i !== null && $column==='operation') {
+                $previews[$previews_last_i][$column] = $this->constants['edit_preview_operation'][(int) $value];
+            } elseif ($unedited_previews_last_i !== null && ($column==='unedited_type' || $column==='unedited_link' || $column==='unedited_thumbnail')) {
+                $unedited_previews[$unedited_previews_last_i][substr($column, strlen('unedited_'))] = $value;
+            } elseif ($column==='orig_type' || $column==='orig_link' || $column==='orig_thumbnail') {
+                if ($value != null && $previews_last_i !== null) {
+                    $previews[$previews_last_i]['original'][substr($column, strlen('orig_'))] = $value;
+                }
+            } elseif ($value!==null) {
+                if ($column==='edit_preview_id') {
+                    $previews[$value] = ['edit_preview_id' => $value];
+                    $previews_last_i = $value;
+                } elseif ($column==='unedited_preview_id') {
+                    $unedited_previews[$value] = ['preview_id' => $value];
+                    $unedited_previews_last_i = $value;
+                } elseif ($column==='status') {
+                    $asset_edit['status'] = $this->constants['edit_status'][(int) $value];
+                } elseif ($column==='download_provider') {
+                    $asset_edit['download_provider'] = $this->constants['download_provider'][(int) $value];
+                } else {
+                    $asset_edit[$column] = $value;
+                }
+            } elseif ($column!=='edit_preview_id' && $column!=='preview_id') {
+                $asset_edit[$column] = $value;
+            }
         }
-      } elseif($column!=='edit_preview_id' && $column!=='preview_id') {
-        $asset_edit[$column] = $value;
-      }
     }
-  }
 
-  if($asset_edit['asset_id'] != -1) {
-    foreach($previews as $preview) {
-      if(isset($preview['preview_id']) && isset($unedited_previews[$preview['preview_id']])) {
-        unset($unedited_previews[$preview['preview_id']]);
-      }
+    if ($asset_edit['asset_id'] != -1) {
+        foreach ($previews as $preview) {
+            if (isset($preview['preview_id']) && isset($unedited_previews[$preview['preview_id']])) {
+                unset($unedited_previews[$preview['preview_id']]);
+            }
+        }
+        $asset_edit['previews'] = array_merge(array_values($previews), array_values($unedited_previews));
+    } else {
+        $asset_edit['previews'] = array_values($previews);
     }
-    $asset_edit['previews'] = array_merge(array_values($previews), array_values($unedited_previews));
-  } else {
-    $asset_edit['previews'] = array_values($previews);
-  }
 
-  if($asset_edit['asset_id'] != -1) {
-    $query_asset = $this->queries['asset']['get_one_bare'];
-    $query_asset->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
-    $query_asset->execute();
+    if ($asset_edit['asset_id'] != -1) {
+        $query_asset = $this->queries['asset']['get_one_bare'];
+        $query_asset->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
+        $query_asset->execute();
 
-    $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_asset);
-    $error = $this->utils->error_reponse_if_query_no_results($error, $response, $query_asset);
-    if($error) return $response;
+        $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_asset);
+        $error = $this->utils->errorResponseIfQueryNoResults($error, $response, $query_asset);
+        if ($error) {
+            return $response;
+        }
 
-    $asset = $query_asset->fetchAll()[0];
+        $asset = $query_asset->fetchAll()[0];
+
+        $asset_edit['original'] = $asset;
+        $asset_edit['original']['download_provider'] = $this->constants['download_provider'][$asset['download_provider']];
+
+        if ($asset_edit['browse_url'] || $asset_edit['download_provider'] || $asset_edit['download_commit']) {
+            $asset_edit['download_url'] = $this->utils->getComputedDownloadUrl(
+                $asset_edit['browse_url'] ?: $asset_edit['original']['browse_url'],
+                $asset_edit['download_provider'] ?: $asset_edit['original']['download_provider'],
+                $asset_edit['download_commit'] ?: $asset_edit['original']['download_commit'],
+                $warning
+            );
+            if ($asset_edit['issues_url'] == '') {
+                $asset_edit['issues_url'] = $this->utils->getDefaultIssuesUrl(
+                    $asset_edit['browse_url'] ?: $asset_edit['original']['browse_url'],
+                    $asset_edit['download_provider'] ?: $asset_edit['original']['download_provider']
+                );
+            }
+        } else {
+            $asset_edit['download_url'] = null;
+        }
 
-    $asset_edit['original'] = $asset;
-    $asset_edit['original']['download_provider'] = $this->constants['download_provider'][$asset['download_provider']];
-
-    if($asset_edit['browse_url'] || $asset_edit['download_provider'] || $asset_edit['download_commit']) {
-      $asset_edit['download_url'] = $this->utils->get_computed_download_url(
-        $asset_edit['browse_url'] ?: $asset_edit['original']['browse_url'],
-        $asset_edit['download_provider'] ?: $asset_edit['original']['download_provider'],
-        $asset_edit['download_commit'] ?: $asset_edit['original']['download_commit'],
-        $warning
-      );
-      if($asset_edit['issues_url'] == '') {
-        $asset_edit['issues_url'] = $this->utils->get_default_issues_url(
-          $asset_edit['browse_url'] ?: $asset_edit['original']['browse_url'],
-          $asset_edit['download_provider'] ?: $asset_edit['original']['download_provider']
-        );
-      }
-    } else {
-      $asset_edit['download_url'] = null;
-    }
+        $asset_edit['original']['download_url'] = $this->utils->getComputedDownloadUrl($asset_edit['original']['browse_url'], $asset_edit['original']['download_provider'], $asset_edit['original']['download_commit'], $warning);
 
-    $asset_edit['original']['download_url'] = $this->utils->get_computed_download_url($asset_edit['original']['browse_url'], $asset_edit['original']['download_provider'], $asset_edit['original']['download_commit'], $warning);
+        if ($asset_edit['original']['issues_url'] == '') {
+            $asset_edit['original']['issues_url'] = $this->utils->getDefaultIssuesUrl($asset_edit['original']['browse_url'], $asset_edit['original']['download_provider']);
+        }
+    } else {
+        $asset_edit['download_url'] = $this->utils->getComputedDownloadUrl($asset_edit['browse_url'], $asset_edit['download_provider'], $asset_edit['download_commit'], $warning);
 
-    if($asset_edit['original']['issues_url'] == '') {
-      $asset_edit['original']['issues_url'] = $this->utils->get_default_issues_url($asset_edit['original']['browse_url'], $asset_edit['original']['download_provider']);
+        if ($asset_edit['issues_url'] == '') {
+            $asset_edit['issues_url'] = $this->utils->getDefaultIssuesUrl($asset_edit['browse_url'], $asset_edit['download_provider']);
+        }
     }
-  } else {
-    $asset_edit['download_url'] = $this->utils->get_computed_download_url($asset_edit['browse_url'], $asset_edit['download_provider'], $asset_edit['download_commit'], $warning);
 
-    if($asset_edit['issues_url'] == '') {
-      $asset_edit['issues_url'] = $this->utils->get_default_issues_url($asset_edit['browse_url'], $asset_edit['download_provider']);
+    if ($warning != null) {
+        $asset_edit['warning'] = $warning;
     }
-  }
-
-  if($warning != null) {
-    $asset_edit['warning'] = $warning;
-  }
-  if($asset_edit['download_commit'] == 'master') {
-    if(isset($asset_edit['warning'])) {
-      $asset_edit['warning'] .= "\n\n";
-    } else {
-      $asset_edit['warning'] = '';
+    if ($asset_edit['download_commit'] == 'master') {
+        if (isset($asset_edit['warning'])) {
+            $asset_edit['warning'] .= "\n\n";
+        } else {
+            $asset_edit['warning'] = '';
+        }
+        $asset_edit['warning'] .= "Giving 'master' (or any other branch name) as the commit to be downloaded is not recommended, since it would invalidate the asset when you push a new version (since we ensure the version is kept the same via a sha256 hash of the zip). You can try using tags instead.";
     }
-    $asset_edit['warning'] .= "Giving 'master' (or any other branch name) as the commit to be downloaded is not recommended, since it would invalidate the asset when you push a new version (since we ensure the version is kept the same via a sha256 hash of the zip). You can try using tags instead.";
-  }
-  if(sizeof(preg_grep('/\/|\\|\:|^\.|\ |\^|\~|\?|\*|\[|^\@$|\@\{/', [$asset_edit['download_commit']])) != 0) {
-    if(isset($asset_edit['warning'])) {
-      $asset_edit['warning'] .= "\n\n";
-    } else {
-      $asset_edit['warning'] = '';
+    if (sizeof(preg_grep('/\/|\\|\:|^\.|\ |\^|\~|\?|\*|\[|^\@$|\@\{/', [$asset_edit['download_commit']])) != 0) {
+        if (isset($asset_edit['warning'])) {
+            $asset_edit['warning'] .= "\n\n";
+        } else {
+            $asset_edit['warning'] = '';
+        }
+        $asset_edit['warning'] .= "The inputted download commit is not a valid git ref, please ensure you aren't giving a full URL. (If your tag includes '/' in its name, consider escaping it as '%2F')";
     }
-    $asset_edit['warning'] .= "The inputted download commit is not a valid git ref, please ensure you aren't giving a full URL. (If your tag includes '/' in its name, consider escaping it as '%2F')";
-  }
 
 
-  return $response->withJson($asset_edit, 200);
+    return $response->withJson($asset_edit, 200);
 };
 
 // Binding to multiple routes
 $app->get('/asset/edit/{id:[0-9]+}', $get_edit);
-if(FRONTEND) {
-  $app->get('/asset/edit/{id:[0-9]+}/edit', $get_edit);
+if (FRONTEND) {
+    $app->get('/asset/edit/{id:[0-9]+}/edit', $get_edit);
 }
 
 // Submit an asset
 $app->post('/asset', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    if ($error) {
+        return $response;
+    }
 
-  return _submit_asset_edit($this, $response, $body, $user['user_id'], -1);
+    return _submit_asset_edit($this, $response, $body, $user['user_id'], -1);
 });
 
 
 // Edit an existing asset
 $app->post('/asset/{id:[0-9]+}', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    if ($error) {
+        return $response;
+    }
 
-  // Ensure the author is editing the asset
-  $query_asset = $this->queries['asset']['get_one_bare'];
-  $query_asset->bindValue(':asset_id', (int) $args['id'], PDO::PARAM_INT);
-  $query_asset->execute();
+    // Ensure the author is editing the asset
+    $query_asset = $this->queries['asset']['get_one_bare'];
+    $query_asset->bindValue(':asset_id', (int) $args['id'], PDO::PARAM_INT);
+    $query_asset->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_asset);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_asset);
+    if ($error) {
+        return $response;
+    }
 
-  $asset = $query_asset->fetchAll()[0];
+    $asset = $query_asset->fetchAll()[0];
 
-  if((int) $asset['user_id'] !== (int) $user['user_id']) {
-    $error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'editor', 'You are not authorized to update this asset');
-    if($error) return $response;
-  }
+    if ((int) $asset['user_id'] !== (int) $user['user_id']) {
+        $error = $this->utils->errorResponseIfNotUserHasLevel($error, $response, $user, 'editor', 'You are not authorized to update this asset');
+        if ($error) {
+            return $response;
+        }
+    }
 
-  return _submit_asset_edit($this, $response, $body, $user['user_id'], (int) $args['id']);
+    return _submit_asset_edit($this, $response, $body, $user['user_id'], (int) $args['id']);
 });
 
 
 // Edit an existing edit
 $app->post('/asset/edit/{id:[0-9]+}', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    if ($error) {
+        return $response;
+    }
 
-  // Fetch the edit to check the user id
-  $query_edit = $this->queries['asset_edit']['get_one_bare'];
-  $query_edit->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query_edit->execute();
+    // Fetch the edit to check the user id
+    $query_edit = $this->queries['asset_edit']['get_one_bare'];
+    $query_edit->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query_edit->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_edit);
-  $error = $this->utils->error_reponse_if_query_no_results($error, $response, $query_edit);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_edit);
+    $error = $this->utils->errorResponseIfQueryNoResults($error, $response, $query_edit);
+    if ($error) {
+        return $response;
+    }
 
-  $asset_edit = $query_edit->fetchAll()[0];
+    $asset_edit = $query_edit->fetchAll()[0];
 
-  if((int) $asset_edit['user_id'] !== (int) $user['user_id']) {
-    return $response->withJson([
-      'error' => 'You are not authorized to update this asset edit',
-    ], 403);
-  }
+    if ((int) $asset_edit['user_id'] !== (int) $user['user_id']) {
+        return $response->withJson([
+            'error' => 'You are not authorized to update this asset edit',
+        ], 403);
+    }
 
-  if((int) $asset_edit['status'] !== $this->constants['edit_status']['new']) {
-    return $response->withJson([
-      'error' => 'You are no longer allowed to update this asset edit, please make a new one',
-    ], 403);
-  }
+    if ((int) $asset_edit['status'] !== $this->constants['edit_status']['new']) {
+        return $response->withJson([
+            'error' => 'You are no longer allowed to update this asset edit, please make a new one',
+        ], 403);
+    }
 
-  // Build query
-  $query = $this->queries['asset_edit']['update'];
-  $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    // Build query
+    $query = $this->queries['asset_edit']['update'];
+    $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
 
 
-  $asset = null;
-  if($asset_edit['asset_id'] != -1) {
-    $query_asset = $this->queries['asset']['get_one_bare'];
-    $query_asset->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
-    $query_asset->execute();
+    $asset = null;
+    if ($asset_edit['asset_id'] != -1) {
+        $query_asset = $this->queries['asset']['get_one_bare'];
+        $query_asset->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
+        $query_asset->execute();
 
-    $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_asset);
-    if($error) return $response;
+        $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_asset);
+        if ($error) {
+            return $response;
+        }
 
-    $asset = $query_asset->fetchAll()[0];
+        $asset = $query_asset->fetchAll()[0];
 
-    $error = _insert_asset_edit_fields($this, false, $response, $query, $body, false, $asset);
-    if($error) return $response;
-  } else {
-    $error = _insert_asset_edit_fields($this, false, $response, $query, $body, true, $asset_edit); // Edit of new asset, everything must be non-null
-    if($error) return $response;
-  }
+        $error = _insert_asset_edit_fields($this, false, $response, $query, $body, false, $asset);
+        if ($error) {
+            return $response;
+        }
+    } else {
+        $error = _insert_asset_edit_fields($this, false, $response, $query, $body, true, $asset_edit); // Edit of new asset, everything must be non-null
+        if ($error) {
+            return $response;
+        }
+    }
 
 
-  // Make a transaction, so we can roll back failed submissions
-  $this->db->beginTransaction();
+    // Make a transaction, so we can roll back failed submissions
+    $this->db->beginTransaction();
 
-  $query->execute();
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) {
-    $this->db->rollback();
-    return $response;
-  }
+    $query->execute();
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        $this->db->rollback();
+        return $response;
+    }
 
-  if(isset($body['previews'])) {
-    $error = _add_previews_to_edit($this, $error, $response, $args['id'], $body['previews'], $asset, false);
-    if($error) {
-      $this->db->rollback();
-      return $response;
+    if (isset($body['previews'])) {
+        $error = _add_previews_to_edit($this, $error, $response, $args['id'], $body['previews'], $asset, false);
+        if ($error) {
+            $this->db->rollback();
+            return $response;
+        }
     }
-  }
 
-  $this->db->commit();
+    $this->db->commit();
 
-  return $response->withJson([
-    'id' => $args['id'],
-    'url' => 'asset/edit/' . $args['id'],
-  ], 200);
+    return $response->withJson([
+        'id' => $args['id'],
+        'url' => 'asset/edit/' . $args['id'],
+    ], 200);
 });
 
 
 // Accept an edit
 $app->post('/asset/edit/{id:[0-9]+}/accept', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  $error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'moderator', 'You are not authorized to accept this asset edit');
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    $error = $this->utils->errorResponseIfNotUserHasLevel($error, $response, $user, 'moderator', 'You are not authorized to accept this asset edit');
+    if ($error) {
+        return $response;
+    }
 
-  // Get the edit
-  $query_edit = $this->queries['asset_edit']['get_one'];
-  $query_edit->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query_edit->execute();
+    // Get the edit
+    $query_edit = $this->queries['asset_edit']['get_one'];
+    $query_edit->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query_edit->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_edit);
-  $error = $this->utils->error_reponse_if_query_no_results($error, $response, $query_edit);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_edit);
+    $error = $this->utils->errorResponseIfQueryNoResults($error, $response, $query_edit);
+    if ($error) {
+        return $response;
+    }
 
-  $asset_edit_previews = $query_edit->fetchAll();
-  $asset_edit = $asset_edit_previews[0];
-  if((int) $asset_edit['status'] !== $this->constants['edit_status']['in_review']) {
-    return $response->withJson([
-      'error' => 'The edit should be in review in order to be accepted',
-    ], 403);
-  }
-
-  // Start building the query
-  $query = null;
-
-  if((int) $asset_edit['asset_id'] === -1) {
-    $query = $this->queries['asset']['apply_creational_edit'];
-    $query->bindValue(':user_id', (int) $asset_edit['user_id'], PDO::PARAM_INT);
-  } else {
-    $query = $this->queries['asset']['apply_edit'];
-    $query->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
-  }
-
-  // Params
-  $update_version = false;
-  foreach ($this->constants['asset_edit_fields'] as $i => $field) {
-    if(isset($asset_edit[$field]) && $asset_edit[$field] !== null) {
-      $query->bindValue(':' . $field, $asset_edit[$field]);
-      $update_version = $update_version || ($field === 'browse_url' || $field === 'download_provider' || $field === 'download_commit' || $field === 'version_string');
-    } else {
-      $query->bindValue(':' . $field, null, PDO::PARAM_NULL);
+    $asset_edit_previews = $query_edit->fetchAll();
+    $asset_edit = $asset_edit_previews[0];
+    if ((int) $asset_edit['status'] !== $this->constants['edit_status']['in_review']) {
+        return $response->withJson([
+            'error' => 'The edit should be in review in order to be accepted',
+        ], 403);
     }
-  }
 
-  if($update_version) {
-    $error = $this->utils->error_reponse_if_missing_or_not_string(false, $response, $body, 'hash');
-    if($error) return $response;
+    // Start building the query
+    $query = null;
 
-    $body['hash'] = trim($body['hash']);
-    if(sizeof(preg_grep('/^[a-f0-9]{64}$/', [$body['hash']])) == 0) {
-      return $response->withJson([
-        'error' => 'Invalid hash given. Expected 64 lowercase hexadecimal digits.',
-      ]);
+    if ((int) $asset_edit['asset_id'] === -1) {
+        $query = $this->queries['asset']['apply_creational_edit'];
+        $query->bindValue(':user_id', (int) $asset_edit['user_id'], PDO::PARAM_INT);
+    } else {
+        $query = $this->queries['asset']['apply_edit'];
+        $query->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
     }
 
-    $query->bindValue(':update_version', 1, PDO::PARAM_INT);
-    $query->bindValue(':download_hash', $body['hash']);
-  } else {
-    if(isset($body['hash']) && trim($body['hash']) != '') {
-      $body['hash'] = trim($body['hash']);
-      if(sizeof(preg_grep('/^[a-f0-9]{64}$/', [$body['hash']])) == 0) {
-        return $response->withJson([
-          'error' => 'Invalid hash given. Expected either nothing or 64 lowercase hexadecimal digits.',
-        ]);
-      }
-      $query->bindValue(':update_version', 1, PDO::PARAM_INT);
-      $query->bindValue(':download_hash', $body['hash']);
-    } else {
-      $query->bindValue(':update_version', 0, PDO::PARAM_INT);
-      $query->bindValue(':download_hash', null, PDO::PARAM_NULL);
+    // Params
+    $update_version = false;
+    foreach ($this->constants['asset_edit_fields'] as $i => $field) {
+        if (isset($asset_edit[$field]) && $asset_edit[$field] !== null) {
+            $query->bindValue(':' . $field, $asset_edit[$field]);
+            $update_version = $update_version || ($field === 'browse_url' || $field === 'download_provider' || $field === 'download_commit' || $field === 'version_string');
+        } else {
+            $query->bindValue(':' . $field, null, PDO::PARAM_NULL);
+        }
     }
-  }
 
-  // Update the status to prevent race conditions
-  $query_status = $this->queries['asset_edit']['set_status_and_reason'];
+    if ($update_version) {
+        $error = $this->utils->errorResponseIfMissingOrNotString(false, $response, $body, 'hash');
+        if ($error) {
+            return $response;
+        }
 
-  $query_status->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query_status->bindValue(':status', (int) $this->constants['edit_status']['accepted'], PDO::PARAM_INT);
-  $query_status->bindValue(':reason', '');
+        $body['hash'] = trim($body['hash']);
+        if (sizeof(preg_grep('/^[a-f0-9]{64}$/', [$body['hash']])) == 0) {
+            return $response->withJson([
+                'error' => 'Invalid hash given. Expected 64 lowercase hexadecimal digits.',
+            ]);
+        }
 
-  $query_status->execute();
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_status);
-  $error = $this->utils->error_reponse_if_query_no_results(false, $response, $query_status); // Important: Ensure that something was actually changed
-  if($error) return $response;
+        $query->bindValue(':update_version', 1, PDO::PARAM_INT);
+        $query->bindValue(':download_hash', $body['hash']);
+    } else {
+        if (isset($body['hash']) && trim($body['hash']) != '') {
+            $body['hash'] = trim($body['hash']);
+            if (sizeof(preg_grep('/^[a-f0-9]{64}$/', [$body['hash']])) == 0) {
+                return $response->withJson([
+                    'error' => 'Invalid hash given. Expected either nothing or 64 lowercase hexadecimal digits.',
+                ]);
+            }
+            $query->bindValue(':update_version', 1, PDO::PARAM_INT);
+            $query->bindValue(':download_hash', $body['hash']);
+        } else {
+            $query->bindValue(':update_version', 0, PDO::PARAM_INT);
+            $query->bindValue(':download_hash', null, PDO::PARAM_NULL);
+        }
+    }
 
-  // Run
-  $query->execute();
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    // Update the status to prevent race conditions
+    $query_status = $this->queries['asset_edit']['set_status_and_reason'];
 
-  // Update the id in case it was newly-created
-  if((int) $asset_edit['asset_id'] === -1) {
-    $asset_edit['asset_id'] = $this->db->lastInsertId();
+    $query_status->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query_status->bindValue(':status', (int) $this->constants['edit_status']['accepted'], PDO::PARAM_INT);
+    $query_status->bindValue(':reason', '');
 
-    $query_update_id = $this->queries['asset_edit']['set_asset_id'];
+    $query_status->execute();
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_status);
+    $error = $this->utils->errorResponseIfQueryNoResults(false, $response, $query_status); // Important: Ensure that something was actually changed
+    if ($error) {
+        return $response;
+    }
 
-    $query_update_id->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-    $query_update_id->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
+    // Run
+    $query->execute();
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-    $query_update_id->execute();
+    // Update the id in case it was newly-created
+    if ((int) $asset_edit['asset_id'] === -1) {
+        $asset_edit['asset_id'] = $this->db->lastInsertId();
 
-    $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_update_id);
-    if($error) return $response;
-    $query_update_id->closeCursor();
-  }
+        $query_update_id = $this->queries['asset_edit']['set_asset_id'];
 
-  $previews_processed = [];
-  foreach($asset_edit_previews as $i => $preview) {
-    if(!isset($preview['edit_preview_id']) || $preview['edit_preview_id'] == null || isset($previews_processed[$preview['edit_preview_id']])) {
-      continue;
-    }
-    $previews_processed[$preview['edit_preview_id']] = true;
-    $operation = $this->constants['edit_preview_operation'][$preview['operation']];
-    $query_apply_preview = $this->queries['asset']['apply_preview_edit_' . $operation];
+        $query_update_id->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+        $query_update_id->bindValue(':asset_id', (int) $asset_edit['asset_id'], PDO::PARAM_INT);
 
-    $query_apply_preview->bindValue(':asset_id', (int) $asset_edit['asset_id']);
+        $query_update_id->execute();
 
-    if($operation == 'remove' || $operation == 'update') {
-      $query_apply_preview->bindValue(':preview_id', (int) $preview['preview_id']);
+        $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_update_id);
+        if ($error) {
+            return $response;
+        }
+        $query_update_id->closeCursor();
     }
 
-    if($operation == 'insert' || $operation == 'update') {
-      foreach ($this->constants['asset_edit_preview_fields'] as $i => $field) {
-        if(isset($preview[$field])) {
-          $query_apply_preview->bindValue(':' . $field, $preview[$field]);
-        } else {
-          $query_apply_preview->bindValue(':' . $field, null, PDO::PARAM_NULL);
+    $previews_processed = [];
+    foreach ($asset_edit_previews as $i => $preview) {
+        if (!isset($preview['edit_preview_id']) || $preview['edit_preview_id'] == null || isset($previews_processed[$preview['edit_preview_id']])) {
+            continue;
         }
-      }
-    }
+        $previews_processed[$preview['edit_preview_id']] = true;
+        $operation = $this->constants['edit_preview_operation'][$preview['operation']];
+        $query_apply_preview = $this->queries['asset']['apply_preview_edit_' . $operation];
+
+        $query_apply_preview->bindValue(':asset_id', (int) $asset_edit['asset_id']);
 
-    $query_apply_preview->execute();
-    $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_apply_preview);
-    if($error) return $response;
-  }
+        if ($operation == 'remove' || $operation == 'update') {
+            $query_apply_preview->bindValue(':preview_id', (int) $preview['preview_id']);
+        }
+
+        if ($operation == 'insert' || $operation == 'update') {
+            foreach ($this->constants['asset_edit_preview_fields'] as $i => $field) {
+                if (isset($preview[$field])) {
+                    $query_apply_preview->bindValue(':' . $field, $preview[$field]);
+                } else {
+                    $query_apply_preview->bindValue(':' . $field, null, PDO::PARAM_NULL);
+                }
+            }
+        }
 
-  return $response->withJson([
-    'id' => $asset_edit['asset_id'],
-    'url' => 'asset/' . $asset_edit['asset_id'],
-  ], 200);
+        $query_apply_preview->execute();
+        $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_apply_preview);
+        if ($error) {
+            return $response;
+        }
+    }
+
+    return $response->withJson([
+        'id' => $asset_edit['asset_id'],
+        'url' => 'asset/' . $asset_edit['asset_id'],
+    ], 200);
 });
 
 // Review an edit
 $app->post('/asset/edit/{id:[0-9]+}/review', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  $error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'moderator', 'You are not authorized to put in review this asset edit');
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    $error = $this->utils->errorResponseIfNotUserHasLevel($error, $response, $user, 'moderator', 'You are not authorized to put in review this asset edit');
+    if ($error) {
+        return $response;
+    }
 
-  // Get the edit
-  $query_edit = $this->queries['asset_edit']['get_one_bare'];
-  $query_edit->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query_edit->execute();
+    // Get the edit
+    $query_edit = $this->queries['asset_edit']['get_one_bare'];
+    $query_edit->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query_edit->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_edit);
-  $error = $this->utils->error_reponse_if_query_no_results($error, $response, $query_edit);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_edit);
+    $error = $this->utils->errorResponseIfQueryNoResults($error, $response, $query_edit);
+    if ($error) {
+        return $response;
+    }
 
-  $asset_edit = $query_edit->fetchAll()[0];
-  if((int) $asset_edit['status'] > $this->constants['edit_status']['in_review']) {
-    return $response->withJson([
-      'error' => 'The edit should be new in order to be put in review',
-    ], 403);
-  }
+    $asset_edit = $query_edit->fetchAll()[0];
+    if ((int) $asset_edit['status'] > $this->constants['edit_status']['in_review']) {
+        return $response->withJson([
+            'error' => 'The edit should be new in order to be put in review',
+        ], 403);
+    }
 
-  // Do the change
-  $query = $this->queries['asset_edit']['set_status_and_reason'];
+    // Do the change
+    $query = $this->queries['asset_edit']['set_status_and_reason'];
 
-  $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query->bindValue(':status', (int) $this->constants['edit_status']['in_review'], PDO::PARAM_INT);
-  $query->bindValue(':reason', '');
+    $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query->bindValue(':status', (int) $this->constants['edit_status']['in_review'], PDO::PARAM_INT);
+    $query->bindValue(':reason', '');
 
-  $query->execute();
+    $query->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-  $asset_edit['status'] = 'in_review'; // Prepare to send
-  $asset_edit['url'] = 'asset/edit/' . $args['id'];
+    $asset_edit['status'] = 'in_review'; // Prepare to send
+    $asset_edit['url'] = 'asset/edit/' . $args['id'];
 
-  return $response->withJson($asset_edit, 200);
+    return $response->withJson($asset_edit, 200);
 });
 
 
 // Reject an edit
 $app->post('/asset/edit/{id:[0-9]+}/reject', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  $error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'moderator', 'You are not authorized to reject this asset edit');
-  $error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'reason');
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    $error = $this->utils->errorResponseIfNotUserHasLevel($error, $response, $user, 'moderator', 'You are not authorized to reject this asset edit');
+    $error = $this->utils->errorResponseIfMissingOrNotString($error, $response, $body, 'reason');
+    if ($error) {
+        return $response;
+    }
 
-  $query = $this->queries['asset_edit']['set_status_and_reason'];
+    $query = $this->queries['asset_edit']['set_status_and_reason'];
 
-  $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
-  $query->bindValue(':status', (int) $this->constants['edit_status']['rejected'], PDO::PARAM_INT);
-  $query->bindValue(':reason', $body['reason']);
+    $query->bindValue(':edit_id', (int) $args['id'], PDO::PARAM_INT);
+    $query->bindValue(':status', (int) $this->constants['edit_status']['rejected'], PDO::PARAM_INT);
+    $query->bindValue(':reason', $body['reason']);
 
-  $query->execute();
+    $query->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-  return $response->withJson([
-    'rejected' => true,
-    'url' => 'asset/edit/' . $args['id'],
-  ], 200);
+    return $response->withJson([
+        'rejected' => true,
+        'url' => 'asset/edit/' . $args['id'],
+    ], 200);
 });

+ 250 - 219
src/routes/auth.php

@@ -4,283 +4,314 @@
 
 // Initializes the connection by sending all categories available
 $app->get('/configure', function ($request, $response, $args) {
-  $params = $request->getQueryParams();
+    $params = $request->getQueryParams();
 
-  $category_type = $this->constants['category_type']['addon'];
+    $category_type = $this->constants['category_type']['addon'];
 
-  if(isset($params['type']) && isset($this->constants['category_type'][$params['type']])) {
-    $category_type = $this->constants['category_type'][$params['type']];
-  }
+    if (isset($params['type']) && isset($this->constants['category_type'][$params['type']])) {
+        $category_type = $this->constants['category_type'][$params['type']];
+    }
 
-  $query = $this->queries['category']['list'];
-  $query->bindValue(':category_type', $category_type);
-  $query->execute();
+    $query = $this->queries['category']['list'];
+    $query->bindValue(':category_type', $category_type);
+    $query->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-  if(isset($request->getQueryParams()['session'])) {
-    $id = openssl_random_pseudo_bytes($this->settings['auth']['tokenSessionBytesLength']);
-    $token = $this->tokens->generate([
-      'session' => base64_encode($id),
-    ]);
+    if (isset($request->getQueryParams()['session'])) {
+        $id = openssl_random_pseudo_bytes($this->settings['auth']['tokenSessionBytesLength']);
+        $token = $this->tokens->generate([
+            'session' => base64_encode($id),
+        ]);
 
-    return $response->withJson([
-      'categories' => $query->fetchAll(),
-      'token' => $token,
-      'login_url' => $_SERVER['HTTP_HOST'] .
-        (FRONTEND ? dirname($request->getUri()->getBasePath()) : $request->getUri()->getBasePath()) .
-        '/login#' . urlencode($token),
-      // ^ TODO: Make those routes actually work
-    ], 200);
-
-  } else {
-    return $response->withJson([
-      'categories' => $query->fetchAll(),
-    ], 200);
-  }
+        return $response->withJson([
+            'categories' => $query->fetchAll(),
+            'token' => $token,
+            'login_url' => $_SERVER['HTTP_HOST'] .
+                (FRONTEND ? dirname($request->getUri()->getBasePath()) : $request->getUri()->getBasePath()) .
+                '/login#' . urlencode($token),
+            // ^ TODO: Make those routes actually work
+        ], 200);
+    } else {
+        return $response->withJson([
+            'categories' => $query->fetchAll(),
+        ], 200);
+    }
 });
 
 $app->post('/register', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-  $query = $this->queries['user']['register'];
-  $query_check = $this->queries['user']['get_by_username'];
-
-  $error = $this->utils->error_reponse_if_missing_or_not_string(false, $response, $body, 'username');
-  $error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'email');
-  $error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'password');
-  if($error) return $response;
+    $body = $request->getParsedBody();
+    $query = $this->queries['user']['register'];
+    $query_check = $this->queries['user']['get_by_username'];
+
+    $error = $this->utils->errorResponseIfMissingOrNotString(false, $response, $body, 'username');
+    $error = $this->utils->errorResponseIfMissingOrNotString($error, $response, $body, 'email');
+    $error = $this->utils->errorResponseIfMissingOrNotString($error, $response, $body, 'password');
+    if ($error) {
+        return $response;
+    }
 
-  $query_check->bindValue(':username', $body['username']);
-  $query_check->execute();
+    $query_check->bindValue(':username', $body['username']);
+    $query_check->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_check);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_check);
+    if ($error) {
+        return $response;
+    }
 
-  if($query_check->rowCount() > 0) {
-    return $response->withJson([
-      'error' => 'Username already taken.',
-    ], 409);
-  }
+    if ($query_check->rowCount() > 0) {
+        return $response->withJson([
+            'error' => 'Username already taken.',
+        ], 409);
+    }
 
-  $password_hash = password_hash($body['password'], PASSWORD_BCRYPT, $this->get('settings')['auth']['bcryptOptions']);
+    $password_hash = password_hash($body['password'], PASSWORD_BCRYPT, $this->get('settings')['auth']['bcryptOptions']);
 
-  $query->bindValue(':username', $body['username']);
-  $query->bindValue(':email', $body['email']); // TODO: Verify email.
-  $query->bindValue(':password_hash', $password_hash);
+    $query->bindValue(':username', $body['username']);
+    $query->bindValue(':email', $body['email']); // TODO: Verify email.
+    $query->bindValue(':password_hash', $password_hash);
 
-  $query->execute();
+    $query->execute();
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
 
-  return $response->withJson([
-    'username' => $body['username'],
-    'registered' => true,
-    'url' => 'login',
-  ], 200);
+    return $response->withJson([
+        'username' => $body['username'],
+        'registered' => true,
+        'url' => 'login',
+    ], 200);
 });
 
 $app->post('/login', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-  $query = $this->queries['user']['get_by_username'];
-
-  $error = $this->utils->error_reponse_if_missing_or_not_string(false, $response, $body, 'username');
-  $error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'password');
-  if($error) return $response;
+    $body = $request->getParsedBody();
+    $query = $this->queries['user']['get_by_username'];
 
-  $query->bindValue(':username', $body['username']);
-  $query->execute();
+    $error = $this->utils->errorResponseIfMissingOrNotString(false, $response, $body, 'username');
+    $error = $this->utils->errorResponseIfMissingOrNotString($error, $response, $body, 'password');
+    if ($error) {
+        return $response;
+    }
 
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  $error = $this->utils->error_reponse_if_query_no_results(false, $response, $query, 'No such username: ' . $body['username']);
-  if($error) return $response;
+    $query->bindValue(':username', $body['username']);
+    $query->execute();
 
-  $user = $query->fetchAll()[0];
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    $error = $this->utils->errorResponseIfQueryNoResults(false, $response, $query, 'No such username: ' . $body['username']);
+    if ($error) {
+        return $response;
+    }
 
-  if(password_verify($body['password'], $user['password_hash'])) {
-    if(isset($body['authorize_token'])) {
-      $token_data = $this->tokens->validate($body['authorize_token']);
+    $user = $query->fetchAll()[0];
+
+    if (password_verify($body['password'], $user['password_hash'])) {
+        if (isset($body['authorize_token'])) {
+            $token_data = $this->tokens->validate($body['authorize_token']);
+
+            if (!$token_data || !isset($token_data->session)) {
+                return $response->withJson([
+                    'error' => 'Invalid token supplied'
+                ], 400);
+            }
+
+            $session_id = $token_data->session;
+            $token = $body['authorize_token'];
+        } else {
+            $session_id = openssl_random_pseudo_bytes($this->settings['auth']['tokenSessionBytesLength']);
+            $token = $this->tokens->generate([
+                'session' => base64_encode($session_id),
+            ]);
+        }
+
+        $query_session = $this->queries['user']['set_session_token'];
+        $query_session->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
+        $query_session->bindValue(':session_token', $session_id);
+        $query_session->execute();
+        $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_session);
+        if ($error) {
+            return $response;
+        }
 
-      if(!$token_data || !isset($token_data->session)) {
         return $response->withJson([
-          'error' => 'Invalid token supplied'
-        ], 400);
-      }
-
-      $session_id = $token_data->session;
-      $token = $body['authorize_token'];
+            'username' => $body['username'],
+            'token' => $token,
+            'authenticated' => true,
+            'url' => 'asset',
+        ], 200);
     } else {
-      $session_id = openssl_random_pseudo_bytes($this->settings['auth']['tokenSessionBytesLength']);
-      $token = $this->tokens->generate([
-        'session' => base64_encode($session_id),
-      ]);
+        return $response->withJson([
+            'authenticated' => false,
+            'error' => 'Password doesn\'t match',
+        ], 403);
     }
+});
+
+$logout = function ($request, $response, $args) {
+    $body = $request->getParsedBody();
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
 
-    $query_session = $this->queries['user']['set_session_token'];
-    $query_session->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
-    $query_session->bindValue(':session_token', $session_id);
-    $query_session->execute();
-    $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_session);
-    if($error) return $response;
+    $query = $this->queries['user']['set_session_token'];
+    $query->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
+    $query->bindValue(':session_token', null, PDO::PARAM_NULL);
+    $query->execute();
 
     return $response->withJson([
-      'username' => $body['username'],
-      'token' => $token,
-      'authenticated' => true,
-      'url' => 'asset',
+        'authenticated' => false,
+        'token' => '',
+        'url' => 'login',
     ], 200);
-  } else {
-    return $response->withJson([
-      'authenticated' => false,
-      'error' => 'Password doesn\'t match',
-    ], 403);
-  }
-});
-
-$logout = function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-
-  $query = $this->queries['user']['set_session_token'];
-  $query->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
-  $query->bindValue(':session_token', null, PDO::PARAM_NULL);
-  $query->execute();
-
-  return $response->withJson([
-    'authenticated' => false,
-    'token' => '',
-    'url' => 'login',
-  ], 200);
 };
 
-if(FRONTEND) {
-  $app->get('/logout', $logout); // Cookies would allow us to logout without post body.
+if (FRONTEND) {
+    $app->get('/logout', $logout); // Cookies would allow us to logout without post body.
 } else {
-  $app->post('/logout', $logout);
+    $app->post('/logout', $logout);
 }
 
 $app->post('/forgot_password', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-
-  $error = $this->utils->error_reponse_if_missing_or_not_string(false, $response, $body, 'email');
-  if($error) return $response;
+    $body = $request->getParsedBody();
 
-  $query_user = $this->queries['user']['get_by_email'];
-  $query_user->bindValue(':email', $body['email']);
-  $query_user->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_user);
-  if($error) return $response;
+    $error = $this->utils->errorResponseIfMissingOrNotString(false, $response, $body, 'email');
+    if ($error) {
+        return $response;
+    }
 
+    $query_user = $this->queries['user']['get_by_email'];
+    $query_user->bindValue(':email', $body['email']);
+    $query_user->execute();
 
-  if($query_user->rowCount() != 0) {
-    $user = $query_user->fetchAll()[0];
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_user);
+    if ($error) {
+        return $response;
+    }
 
-    $reset_id = openssl_random_pseudo_bytes($this->settings['auth']['tokenResetBytesLength']);
-    $token = $this->tokens->generate([
-      'reset' => base64_encode($reset_id),
-    ]);
 
-    $query = $this->queries['user']['set_reset_token'];
-    $query->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
-    $query->bindValue(':reset_token', $reset_id);
-    $query->execute();
-    $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-    if($error) return $response;
-
-    $reset_link = $request->getUri()->getScheme() . '://' . $_SERVER['HTTP_HOST'] .
-      (FRONTEND ? $request->getUri()->getBasePath() : dirname($request->getUri()->getBasePath())) .
-      '/reset_password?token=' . urlencode($token);
-
-    $mail = $this->mail->__invoke(); // Since its a function closure, we have to invoke it with magic methods
-    $mail->addAddress($user['email'], $user['username']);
-    $mail->isHTML(true);
-    $mail->Subject = "Password reset requested for $user[username]";
-    $mail->Body = $this->renderer->fetch('reset_password_email.phtml', [
-      'user' => $user,
-      'link' => $reset_link,
-    ]);
-    $mail->AltBody = "Reset your ($user[username]'s) password: $reset_link\n";
-    if(!$mail->send()) {
-      $this->logger->error('mailSendFail', [$mail->ErrorInfo]);
+    if ($query_user->rowCount() != 0) {
+        $user = $query_user->fetchAll()[0];
+
+        $reset_id = openssl_random_pseudo_bytes($this->settings['auth']['tokenResetBytesLength']);
+        $token = $this->tokens->generate([
+            'reset' => base64_encode($reset_id),
+        ]);
+
+        $query = $this->queries['user']['set_reset_token'];
+        $query->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
+        $query->bindValue(':reset_token', $reset_id);
+        $query->execute();
+        $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+        if ($error) {
+            return $response;
+        }
+
+        $reset_link = $request->getUri()->getScheme() . '://' . $_SERVER['HTTP_HOST'] .
+            (FRONTEND ? $request->getUri()->getBasePath() : dirname($request->getUri()->getBasePath())) .
+            '/reset_password?token=' . urlencode($token);
+
+        $mail = $this->mail->__invoke(); // Since its a function closure, we have to invoke it with magic methods
+        $mail->addAddress($user['email'], $user['username']);
+        $mail->isHTML(true);
+        $mail->Subject = "Password reset requested for $user[username]";
+        $mail->Body = $this->renderer->fetch('reset_password_email.phtml', [
+            'user' => $user,
+            'link' => $reset_link,
+        ]);
+        $mail->AltBody = "Reset your ($user[username]'s) password: $reset_link\n";
+        if (!$mail->send()) {
+            $this->logger->error('mailSendFail', [$mail->ErrorInfo]);
+        }
+        // $this->logger->info('mailLinkDebug', [$reset_link]);
     }
-    // $this->logger->info('mailLinkDebug', [$reset_link]);
-  }
 
-  return $response->withJson([
-    'email' => $body['email'],
-  ], 200);
+    return $response->withJson([
+        'email' => $body['email'],
+    ], 200);
 });
 
 $app->get('/reset_password', function ($request, $response, $args) {
-  $params = $request->getQueryParams();
-  $body = null !== $request->getParsedBody()? $request->getParsedBody() : [];
+    $params = $request->getQueryParams();
+    $body = null !== $request->getParsedBody()? $request->getParsedBody() : [];
 
-  $error = $this->utils->ensure_logged_in(false, $response, $params + $body, $user, $token_data, true);
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $params + $body, $user, $token_data, true);
+    if ($error) {
+        return $response;
+    }
 
-  $combined_body = $params + $body;
+    $combined_body = $params + $body;
 
-  return $response->withJson([
-    'token' => $combined_body['token'],
-  ], 200);
+    return $response->withJson([
+        'token' => $combined_body['token'],
+    ], 200);
 });
 
 $app->post('/reset_password', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user, $token_data, true);
-  $error = $this->utils->error_reponse_if_missing_or_not_string(false, $response, $body, 'password');
-  if($error) return $response;
-
-  $password_hash = password_hash($body['password'], PASSWORD_BCRYPT, $this->get('settings')['auth']['bcryptOptions']);
-
-  $query_password = $this->queries['user']['set_password_and_nullify_session'];
-  $query_password->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
-  $query_password->bindValue(':password_hash', $password_hash);
-  $query_password->execute();
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_password);
-  if($error) return $response;
-
-  $query = $this->queries['user']['set_reset_token'];
-  $query->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
-  $query->bindValue(':reset_token', null, PDO::PARAM_NULL);
-  $query->execute();
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
-
-  return $response->withJson([
-    'token' => null,
-    'url' => 'login',
-  ], 200);
+    $body = $request->getParsedBody();
+
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user, $token_data, true);
+    $error = $this->utils->errorResponseIfMissingOrNotString(false, $response, $body, 'password');
+    if ($error) {
+        return $response;
+    }
+
+    $password_hash = password_hash($body['password'], PASSWORD_BCRYPT, $this->get('settings')['auth']['bcryptOptions']);
+
+    $query_password = $this->queries['user']['set_password_and_nullify_session'];
+    $query_password->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
+    $query_password->bindValue(':password_hash', $password_hash);
+    $query_password->execute();
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_password);
+    if ($error) {
+        return $response;
+    }
+
+    $query = $this->queries['user']['set_reset_token'];
+    $query->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
+    $query->bindValue(':reset_token', null, PDO::PARAM_NULL);
+    $query->execute();
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
+
+    return $response->withJson([
+        'token' => null,
+        'url' => 'login',
+    ], 200);
 });
 
 $app->post('/change_password', function ($request, $response, $args) {
-  $body = $request->getParsedBody();
+    $body = $request->getParsedBody();
 
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user, $token_data);
-  $error = $this->utils->error_reponse_if_missing_or_not_string(false, $response, $body, 'new_password');
-  $error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'old_password');
-  if($error) return $response;
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user, $token_data);
+    $error = $this->utils->errorResponseIfMissingOrNotString(false, $response, $body, 'new_password');
+    $error = $this->utils->errorResponseIfMissingOrNotString($error, $response, $body, 'old_password');
+    if ($error) {
+        return $response;
+    }
+
+    if (!password_verify($body['old_password'], $user['password_hash'])) {
+        return $response->withJson([
+            'error' => 'Wrong old password supplied!',
+        ], 403);
+    }
+
+    $password_hash = password_hash($body['new_password'], PASSWORD_BCRYPT, $this->get('settings')['auth']['bcryptOptions']);
+
+    $query_password = $this->queries['user']['set_password_and_nullify_session'];
+    $query_password->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
+    $query_password->bindValue(':password_hash', $password_hash);
+    $query_password->execute();
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query_password);
+    if ($error) {
+        return $response;
+    }
 
-  if(!password_verify($body['old_password'], $user['password_hash'])) {
     return $response->withJson([
-      'error' => 'Wrong old password supplied!',
-    ], 403);
-  }
-
-  $password_hash = password_hash($body['new_password'], PASSWORD_BCRYPT, $this->get('settings')['auth']['bcryptOptions']);
-
-  $query_password = $this->queries['user']['set_password_and_nullify_session'];
-  $query_password->bindValue(':id', (int) $user['user_id'], PDO::PARAM_INT);
-  $query_password->bindValue(':password_hash', $password_hash);
-  $query_password->execute();
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query_password);
-  if($error) return $response;
-
-  return $response->withJson([
-    'token' => null,
-    'url' => 'login',
-  ], 200);
+        'token' => null,
+        'url' => 'login',
+    ], 200);
 });

+ 43 - 39
src/routes/user.php

@@ -2,47 +2,51 @@
 
 // Feed
 $get_feed = function ($request, $response, $args) {
-  $body = $request->getParsedBody();
-
-  $error = $this->utils->ensure_logged_in(false, $response, $body, $user);
-  if($error) return $response;
-
-  $page_size = 40;
-  $max_page_size = 500;
-  $page_offset = 0;
-  if(isset($params['max_results'])) {
-    $page_size = min(abs((int) $params['max_results']), $max_page_size);
-  }
-  if(isset($params['page'])) {
-    $page_offset = abs((int) $params['page']) * $page_size;
-  } elseif(isset($params['offset'])) {
-    $page_offset = abs((int) $params['offset']);
-  }
-
-  $query = $this->queries['user']['list_edit_events'];
-  $query->bindValue(':user_id', (int) $user['user_id'], PDO::PARAM_INT);
-  $query->bindValue(':page_size', $page_size, PDO::PARAM_INT);
-  $query->bindValue(':skip_count', $page_offset, PDO::PARAM_INT);
-  $query->execute();
-
-  $error = $this->utils->error_reponse_if_query_bad(false, $response, $query);
-  if($error) return $response;
-
-  $events = $query->fetchAll();
-
-  $context = $this;
-  $events = array_map(function($event) use($context) {
-    $event['status'] = $context->constants['edit_status'][(int) $event['status']];
-    return $event;
-  }, $events);
-
-  return $response->withJson([
-    'events' => $events,
-  ], 200);
+    $body = $request->getParsedBody();
+
+    $error = $this->utils->ensureLoggedIn(false, $response, $body, $user);
+    if ($error) {
+        return $response;
+    }
+
+    $page_size = 40;
+    $max_page_size = 500;
+    $page_offset = 0;
+    if (isset($params['max_results'])) {
+        $page_size = min(abs((int) $params['max_results']), $max_page_size);
+    }
+    if (isset($params['page'])) {
+        $page_offset = abs((int) $params['page']) * $page_size;
+    } elseif (isset($params['offset'])) {
+        $page_offset = abs((int) $params['offset']);
+    }
+
+    $query = $this->queries['user']['list_edit_events'];
+    $query->bindValue(':user_id', (int) $user['user_id'], PDO::PARAM_INT);
+    $query->bindValue(':page_size', $page_size, PDO::PARAM_INT);
+    $query->bindValue(':skip_count', $page_offset, PDO::PARAM_INT);
+    $query->execute();
+
+    $error = $this->utils->errorResponseIfQueryBad(false, $response, $query);
+    if ($error) {
+        return $response;
+    }
+
+    $events = $query->fetchAll();
+
+    $context = $this;
+    $events = array_map(function ($event) use ($context) {
+        $event['status'] = $context->constants['edit_status'][(int) $event['status']];
+        return $event;
+    }, $events);
+
+    return $response->withJson([
+        'events' => $events,
+    ], 200);
 };
 
 // Binding to multiple routes
 $app->post('/user/feed', $get_feed);
-if(FRONTEND) {
-  $app->get('/user/feed', $get_feed);
+if (FRONTEND) {
+    $app->get('/user/feed', $get_feed);
 }

+ 170 - 170
templates/_asset_fields.phtml

@@ -1,207 +1,207 @@
 <?php if(!isset($_asset_values)) {
-	$_asset_values = [];
+    $_asset_values = [];
 }
 $_asset_values = array_merge([
-	'title' => '',
-	'category_id' => '0',
-	'version_string' => '',
-	'download_provider' => '0',
-	'download_commit' => '',
-	'browse_url' => '',
-	'issues_url' => '',
-	'icon_url' => '',
-	'description' => '',
-	'cost' => '',
-	'previews' => [],
+    'title' => '',
+    'category_id' => '0',
+    'version_string' => '',
+    'download_provider' => '0',
+    'download_commit' => '',
+    'browse_url' => '',
+    'issues_url' => '',
+    'icon_url' => '',
+    'description' => '',
+    'cost' => '',
+    'previews' => [],
 ], $_asset_values);
 ?>
 <div class="form-group">
-		<label class="col-md-4 control-label" for="title">Asset Name</label>
-		<div class="col-md-5">
-				<input id="title" name="title" type="text" placeholder="Asset Name" class="form-control input-md" required="" value="<?php echo esc($_asset_values['title']) ?>">
-				<span class="help-block">Set the name of your asset</span>
-		</div>
+        <label class="col-md-4 control-label" for="title">Asset Name</label>
+        <div class="col-md-5">
+                <input id="title" name="title" type="text" placeholder="Asset Name" class="form-control input-md" required="" value="<?php echo esc($_asset_values['title']) ?>">
+                <span class="help-block">Set the name of your asset</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="category">Category</label>
-		<div class="col-md-5">
-				<select id="category" name="category_id" class="form-control">
-						<?php foreach($categories as $key => $category) { ?>
-							<option value="<?php echo esc($category['id']) ?>" <?php if($category['id'] == $_asset_values['category_id']) echo 'selected=""'; ?>>
-								<?php echo esc($category['name']) ?>
-							</option>
-						<?php } ?>
-				</select>
-		</div>
+        <label class="col-md-4 control-label" for="category">Category</label>
+        <div class="col-md-5">
+                <select id="category" name="category_id" class="form-control">
+                        <?php foreach($categories as $key => $category) { ?>
+                            <option value="<?php echo esc($category['id']) ?>" <?php if($category['id'] == $_asset_values['category_id']) echo 'selected=""'; ?>>
+                                <?php echo esc($category['name']) ?>
+                            </option>
+                        <?php } ?>
+                </select>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="version">Version</label>
-		<div class="col-md-5">
-				<input id="version" name="version_string" type="text" placeholder="Version" class="form-control input-md" required="" value="<?php echo esc($_asset_values['version_string']) ?>">
-				<span class="help-block">Set the version of your asset</span>
-		</div>
+        <label class="col-md-4 control-label" for="version">Version</label>
+        <div class="col-md-5">
+                <input id="version" name="version_string" type="text" placeholder="Version" class="form-control input-md" required="" value="<?php echo esc($_asset_values['version_string']) ?>">
+                <span class="help-block">Set the version of your asset</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="download_provider">Repository hoster</label>
-		<div class="col-md-5">
-				<select id="download_provider" name="download_provider" class="form-control">
-					<?php foreach($constants['download_provider'] as $id => $name) if(is_int($id)) { ?>
-						<option value="<?php echo esc($name) ?>" <?php if($name == $_asset_values['download_provider']) echo 'selected=""'; ?>>
-							<?php echo esc($name) ?>
-						</option>
-					<?php } ?>
-				</select>
-				<span class="help-block">We really need to know where your repository is hosted in order to compute the final download URL. If your Git repository provider is missing, you might like to <a href="https://github.com/godotengine/asset-library/issues">open an issue</a> about it.</span>
-		</div>
+        <label class="col-md-4 control-label" for="download_provider">Repository hoster</label>
+        <div class="col-md-5">
+                <select id="download_provider" name="download_provider" class="form-control">
+                    <?php foreach($constants['download_provider'] as $id => $name) if(is_int($id)) { ?>
+                        <option value="<?php echo esc($name) ?>" <?php if($name == $_asset_values['download_provider']) echo 'selected=""'; ?>>
+                            <?php echo esc($name) ?>
+                        </option>
+                    <?php } ?>
+                </select>
+                <span class="help-block">We really need to know where your repository is hosted in order to compute the final download URL. If your Git repository provider is missing, you might like to <a href="https://github.com/godotengine/asset-library/issues">open an issue</a> about it.</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="browse">Repository URL</label>
-		<div class="col-md-5">
-				<input id="browse" name="browse_url" type="text" placeholder="Repository URL" class="form-control input-md" required="" value="<?php echo esc($_asset_values['browse_url']) ?>">
-				<span class="help-block">Set the url to browse the asset's files (webpage). Should be similar to <code>https://github.com/&lt;user&gt;/&lt;project&gt;</code> (Might be different depending on your "provider")</span>
-		</div>
+        <label class="col-md-4 control-label" for="browse">Repository URL</label>
+        <div class="col-md-5">
+                <input id="browse" name="browse_url" type="text" placeholder="Repository URL" class="form-control input-md" required="" value="<?php echo esc($_asset_values['browse_url']) ?>">
+                <span class="help-block">Set the url to browse the asset's files (webpage). Should be similar to <code>https://github.com/&lt;user&gt;/&lt;project&gt;</code> (Might be different depending on your "provider")</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="issues">Issues URL</label>
-		<div class="col-md-5">
-				<input id="issues" name="issues_url" type="text" placeholder="Issues URL" class="form-control input-md" value="<?php echo esc($_asset_values['issues_url']) ?>">
-				<span class="help-block">Set the url to issues list of the  asset. Should be similar to <code>https://github.com/&lt;user&gt;/&lt;project&gt;/issues</code> (Might be different depending on your "provider"). If you use your provider's issue list, you can leave it empty.</span>
-		</div>
+        <label class="col-md-4 control-label" for="issues">Issues URL</label>
+        <div class="col-md-5">
+                <input id="issues" name="issues_url" type="text" placeholder="Issues URL" class="form-control input-md" value="<?php echo esc($_asset_values['issues_url']) ?>">
+                <span class="help-block">Set the url to issues list of the  asset. Should be similar to <code>https://github.com/&lt;user&gt;/&lt;project&gt;/issues</code> (Might be different depending on your "provider"). If you use your provider's issue list, you can leave it empty.</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="commit">Download Commit/tag</label>
-		<div class="col-md-5">
-				<input id="commit" name="download_commit" type="text" placeholder="Download Commit/tag" class="form-control input-md" required="" value="<?php echo esc($_asset_values['download_commit']) ?>">
-				<span class="help-block">Set the commit or tag to download the asset. Should be similar to <code>b1d3172f89b86e52465a74f63a74ac84c491d3e1</code> or <code>v1.0</code>. The final download url would be computed from this.</span>
-		</div>
+        <label class="col-md-4 control-label" for="commit">Download Commit/tag</label>
+        <div class="col-md-5">
+                <input id="commit" name="download_commit" type="text" placeholder="Download Commit/tag" class="form-control input-md" required="" value="<?php echo esc($_asset_values['download_commit']) ?>">
+                <span class="help-block">Set the commit or tag to download the asset. Should be similar to <code>b1d3172f89b86e52465a74f63a74ac84c491d3e1</code> or <code>v1.0</code>. The final download url would be computed from this.</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="icon">Icon URL</label>
-		<div class="col-md-5">
-				<input id="icon" name="icon_url" type="text" placeholder="Icon URL" class="form-control input-md" required="" value="<?php echo esc($_asset_values['icon_url']) ?>">
-				<span class="help-block">Set the url to the asset's icon (png or jpg image)</span>
-		</div>
+        <label class="col-md-4 control-label" for="icon">Icon URL</label>
+        <div class="col-md-5">
+                <input id="icon" name="icon_url" type="text" placeholder="Icon URL" class="form-control input-md" required="" value="<?php echo esc($_asset_values['icon_url']) ?>">
+                <span class="help-block">Set the url to the asset's icon (png or jpg image)</span>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="license">License</label>
-		<div class="col-md-5">
-				<select id="license" name="cost" class="form-control">
-					<?php $licenses = [
-						'MIT' => 'MIT',
-						'GPLv3' => 'GPL v3',
-						'GPLv2' => 'GPL v2',
-						'CC0' => 'CC0',
-						'BSD-2-Clause' => 'BSD 2-clause License',
-						'BSL-1.0' => 'Boost Software License'
-					] ?>
-					<?php foreach($licenses as $id => $name) { ?>
-						<option value="<?php echo raw($id) ?>" <?php if($id == $_asset_values['cost']) echo 'selected=""'; ?>>
-							<?php echo esc($name) ?>
-						</option>
-					<?php } ?>
-				</select>
-		</div>
+        <label class="col-md-4 control-label" for="license">License</label>
+        <div class="col-md-5">
+                <select id="license" name="cost" class="form-control">
+                    <?php $licenses = [
+                        'MIT' => 'MIT',
+                        'GPLv3' => 'GPL v3',
+                        'GPLv2' => 'GPL v2',
+                        'CC0' => 'CC0',
+                        'BSD-2-Clause' => 'BSD 2-clause License',
+                        'BSL-1.0' => 'Boost Software License'
+                    ] ?>
+                    <?php foreach($licenses as $id => $name) { ?>
+                        <option value="<?php echo raw($id) ?>" <?php if($id == $_asset_values['cost']) echo 'selected=""'; ?>>
+                            <?php echo esc($name) ?>
+                        </option>
+                    <?php } ?>
+                </select>
+        </div>
 </div>
 
 <div class="form-group">
-		<label class="col-md-4 control-label" for="description">Description</label>
-		<div class="col-md-5">
-				<textarea class="form-control" id="description" name="description" rows="7"><?php echo esc($_asset_values['description']) ?></textarea>
-		</div>
+        <label class="col-md-4 control-label" for="description">Description</label>
+        <div class="col-md-5">
+                <textarea class="form-control" id="description" name="description" rows="7"><?php echo esc($_asset_values['description']) ?></textarea>
+        </div>
 </div>
 
 <?php for ($i=0; $i < count($_asset_values['previews']) + 3; $i++) {
-	if($i < count($_asset_values['previews'])) $preview = $_asset_values['previews'][$i];
-	else $preview = ['type' => 'image', 'link' => '', 'thumbnail' => '']
-	?>
-	<div class="panel panel-default">
-		<div class="panel-heading form-inline">
-			<div class="text-center">
-				<span class="panel-title">
-					<?php if($i < count($_asset_values['previews'])) {
-						if(isset($preview['edit_preview_id'])) {
-							echo 'Revise ' . raw($preview['operation']) . ' operation';
-						} else {
-							echo 'Update original preview';
-						}
-					} else {
-						echo 'Add preview';
-					} ?>
-				</span>
-
-				<?php if($i < count($_asset_values['previews'])) { ?>
-					<?php if(isset($preview['edit_preview_id'])) { // Existing edit ?>
-
-						<input type="hidden" name="previews[<?php echo $i ?>][edit_preview_id]" value="<?php echo esc($preview['edit_preview_id']) ?>">
-						<input type="hidden" name="previews[<?php echo $i ?>][enabled]" value="true">
-						<label>
-							<input type="checkbox" name="previews[<?php echo $i ?>][remove]" value="true">
-							Cancel edit
-						</label>
-
-					<?php } else { // From base asset ?>
-						<input type="hidden" name="previews[<?php echo $i ?>][preview_id]" value="<?php echo esc($preview['preview_id']) ?>">
-						<label>
-							<input type="checkbox" name="previews[<?php echo $i ?>][enabled]" value="true">
-							Enable
-						</label>
-						<label>
-							<input type="radio" name="previews[<?php echo $i ?>][operation]" value="update" checked="">
-							Update
-						</label>
-						<label>
-							<input type="radio" name="previews[<?php echo $i ?>][operation]" value="remove">
-							Remove
-						</label>
-
-					<?php } ?>
-				<?php } else { ?>
-					<input type="hidden" name="previews[<?php echo $i ?>][operation]" value="insert">
-					<label>
-						<input type="checkbox" name="previews[<?php echo $i ?>][enabled]" value="true">
-						Enable
-					</label>
-				<?php } ?>
-			</div>
-	</div>
-
-		<div class="panel-body">
-			<div class="form-group">
-					<label class="col-md-4 control-label" for="previews[<?php echo $i ?>][type]">Type</label>
-					<div class="col-md-5">
-							<select id="license" name="previews[<?php echo $i ?>][type]" class="form-control">
-								<?php $types = ['image' => 'Image', 'video' => 'Video'] ?>
-								<?php foreach($types as $id => $name) { ?>
-									<option value="<?php echo raw($id) ?>" <?php if($id == $preview['type']) echo 'selected=""'; ?>>
-										<?php echo esc($name) ?>
-									</option>
-								<?php } ?>
-							</select>
-					</div>
-			</div>
-
-			<div class="form-group">
-				<label class="control-label col-md-4" for="previews[<?php echo $i ?>][link]">Image/Youtube Link</label>
-				<div class="col-md-5">
-					<input id="youtube-<?php echo $i ?>" name="previews[<?php echo $i ?>][link]" type="text" placeholder="Image/Youtube Link" class="form-control input-md" value="<?php echo esc($preview['link']) ?>">
-				</div>
-			</div>
-
-			<div class="form-group">
-				<label class="control-label col-md-4" for="previews[<?php echo $i ?>][thumbnail]">Link to thumbnail (To be removed)</label>
-				<div class="col-md-5">
-					<input id="youtube-<?php echo $i ?>" name="previews[<?php echo $i ?>][thumbnail]" type="text" placeholder="Image Link" class="form-control input-md" value="<?php echo esc($preview['thumbnail']) ?>">
-				</div>
-			</div>
-
-		</div>
-	</div>
+    if($i < count($_asset_values['previews'])) $preview = $_asset_values['previews'][$i];
+    else $preview = ['type' => 'image', 'link' => '', 'thumbnail' => '']
+    ?>
+    <div class="panel panel-default">
+        <div class="panel-heading form-inline">
+            <div class="text-center">
+                <span class="panel-title">
+                    <?php if($i < count($_asset_values['previews'])) {
+                        if(isset($preview['edit_preview_id'])) {
+                            echo 'Revise ' . raw($preview['operation']) . ' operation';
+                        } else {
+                            echo 'Update original preview';
+                        }
+                    } else {
+                        echo 'Add preview';
+                    } ?>
+                </span>
+
+                <?php if($i < count($_asset_values['previews'])) { ?>
+                    <?php if(isset($preview['edit_preview_id'])) { // Existing edit ?>
+
+                        <input type="hidden" name="previews[<?php echo $i ?>][edit_preview_id]" value="<?php echo esc($preview['edit_preview_id']) ?>">
+                        <input type="hidden" name="previews[<?php echo $i ?>][enabled]" value="true">
+                        <label>
+                            <input type="checkbox" name="previews[<?php echo $i ?>][remove]" value="true">
+                            Cancel edit
+                        </label>
+
+                    <?php } else { // From base asset ?>
+                        <input type="hidden" name="previews[<?php echo $i ?>][preview_id]" value="<?php echo esc($preview['preview_id']) ?>">
+                        <label>
+                            <input type="checkbox" name="previews[<?php echo $i ?>][enabled]" value="true">
+                            Enable
+                        </label>
+                        <label>
+                            <input type="radio" name="previews[<?php echo $i ?>][operation]" value="update" checked="">
+                            Update
+                        </label>
+                        <label>
+                            <input type="radio" name="previews[<?php echo $i ?>][operation]" value="remove">
+                            Remove
+                        </label>
+
+                    <?php } ?>
+                <?php } else { ?>
+                    <input type="hidden" name="previews[<?php echo $i ?>][operation]" value="insert">
+                    <label>
+                        <input type="checkbox" name="previews[<?php echo $i ?>][enabled]" value="true">
+                        Enable
+                    </label>
+                <?php } ?>
+            </div>
+    </div>
+
+        <div class="panel-body">
+            <div class="form-group">
+                    <label class="col-md-4 control-label" for="previews[<?php echo $i ?>][type]">Type</label>
+                    <div class="col-md-5">
+                            <select id="license" name="previews[<?php echo $i ?>][type]" class="form-control">
+                                <?php $types = ['image' => 'Image', 'video' => 'Video'] ?>
+                                <?php foreach($types as $id => $name) { ?>
+                                    <option value="<?php echo raw($id) ?>" <?php if($id == $preview['type']) echo 'selected=""'; ?>>
+                                        <?php echo esc($name) ?>
+                                    </option>
+                                <?php } ?>
+                            </select>
+                    </div>
+            </div>
+
+            <div class="form-group">
+                <label class="control-label col-md-4" for="previews[<?php echo $i ?>][link]">Image/Youtube Link</label>
+                <div class="col-md-5">
+                    <input id="youtube-<?php echo $i ?>" name="previews[<?php echo $i ?>][link]" type="text" placeholder="Image/Youtube Link" class="form-control input-md" value="<?php echo esc($preview['link']) ?>">
+                </div>
+            </div>
+
+            <div class="form-group">
+                <label class="control-label col-md-4" for="previews[<?php echo $i ?>][thumbnail]">Link to thumbnail (To be removed)</label>
+                <div class="col-md-5">
+                    <input id="youtube-<?php echo $i ?>" name="previews[<?php echo $i ?>][thumbnail]" type="text" placeholder="Image Link" class="form-control input-md" value="<?php echo esc($preview['thumbnail']) ?>">
+                </div>
+            </div>
+
+        </div>
+    </div>
 <?php } ?>

+ 33 - 33
templates/_footer.phtml

@@ -1,37 +1,37 @@
-    <footer>
-      <div class="row">
-        <div class="col-md-12">
-          <hr/>
-          <p>
-            Copyright &copy; 2016 The Godot Engine community - MIT Licensed.
-            <?php if(file_exists('.git/HEAD')) { $HEAD_contents = file_get_contents('.git/HEAD');?>
-              <?php if(preg_match('/^ref: (.+)$/m', $HEAD_contents, $ref_matches)) {
-                $ref = $ref_matches[1];
-                $commit_hash = trim(file_get_contents('.git/' . $ref));
-                ?>
-                <?php if(preg_match('/^[a-zA-Z0-9]+$/', $commit_hash)) { ?>
-                  <span class="text-muted pull-right">
-                    Currently running version <a href="https://github.com/godotengine/asset-library/commit/<?php echo url($commit_hash) ?>"><?php echo esc(substr($commit_hash, 0, 7)) ?></a>.
-                  </span>
-                <?php } ?>
-              <?php } ?>
-            <?php } ?>
-          </p>
-          <p class="text-muted text-right">
-            Links:
-            <a href="https://github.com/godotengine/asset-library">GitHub repository</a> |
-            <a href="https://github.com/godotengine/asset-library/issues">Issues</a> |
-            <a href="https://godotengine.org">Godot Engine homepage</a>
-          </p>
-        </div>
-      </div>
-    </footer>
-  </div>
+        <footer>
+            <div class="row">
+                <div class="col-md-12">
+                    <hr/>
+                    <p>
+                        Copyright &copy; 2016 The Godot Engine community - MIT Licensed.
+                        <?php if(file_exists('.git/HEAD')) { $HEAD_contents = file_get_contents('.git/HEAD');?>
+                            <?php if(preg_match('/^ref: (.+)$/m', $HEAD_contents, $ref_matches)) {
+                                $ref = $ref_matches[1];
+                                $commit_hash = trim(file_get_contents('.git/' . $ref));
+                                ?>
+                                <?php if(preg_match('/^[a-zA-Z0-9]+$/', $commit_hash)) { ?>
+                                    <span class="text-muted pull-right">
+                                        Currently running version <a href="https://github.com/godotengine/asset-library/commit/<?php echo url($commit_hash) ?>"><?php echo esc(substr($commit_hash, 0, 7)) ?></a>.
+                                    </span>
+                                <?php } ?>
+                            <?php } ?>
+                        <?php } ?>
+                    </p>
+                    <p class="text-muted text-right">
+                        Links:
+                        <a href="https://github.com/godotengine/asset-library">GitHub repository</a> |
+                        <a href="https://github.com/godotengine/asset-library/issues">Issues</a> |
+                        <a href="https://godotengine.org">Godot Engine homepage</a>
+                    </p>
+                </div>
+            </div>
+        </footer>
+    </div>
 
-  <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
-  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
-  <!-- Include all compiled plugins (below), or include individual files as needed -->
-  <script src="<?php echo raw($bowerpath) ?>/bootstrap/dist/js/bootstrap.min.js"></script>
+    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+    <!-- Include all compiled plugins (below), or include individual files as needed -->
+    <script src="<?php echo raw($bowerpath) ?>/bootstrap/dist/js/bootstrap.min.js"></script>
 </body>
 
 </html>

+ 66 - 66
templates/_header.phtml

@@ -1,79 +1,79 @@
 <?php // Utils
-  function esc($param) {
-    return htmlspecialchars($param);
-  }
-  function url($param) {
-    return htmlspecialchars(urlencode($param));
-  }
-  function raw($param) {
-    return $param;
-  }
+    function esc($param) {
+        return htmlspecialchars($param);
+    }
+    function url($param) {
+        return htmlspecialchars(urlencode($param));
+    }
+    function raw($param) {
+        return $param;
+    }
 ?>
 <!DOCTYPE html>
 <html lang="en">
 
 <head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge">
-  <meta name="viewport" content="width=device-width, initial-scale=1">
-  <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
-  <title><?php if(!empty($data['title'])){ echo(esc($data['title'].' - ')); } ?>Godot Asset Library</title>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
+    <title><?php if(!empty($data['title'])){ echo(esc($data['title'].' - ')); } ?>Godot Asset Library</title>
 
-  <!-- Bootstrap -->
-  <link href="<?php echo raw($bowerpath) ?>/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
+    <!-- Bootstrap -->
+    <link href="<?php echo raw($bowerpath) ?>/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
 
-  <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
-  <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
-  <!--[if lt IE 9]>
-    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
-    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
-  <![endif]-->
+    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
+    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+    <!--[if lt IE 9]>
+        <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+    <![endif]-->
 </head>
 
 <body>
-  <!-- Navigation -->
-  <nav class="navbar navbar-inverse navbar-static-top" role="navigation">
-    <div class="container">
-      <!-- Brand and toggle get grouped for better mobile display -->
-      <div class="navbar-header">
-        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
-          <span class="sr-only">Toggle navigation</span>
-          <span class="icon-bar"></span>
-          <span class="icon-bar"></span>
-          <span class="icon-bar"></span>
-        </button>
-        <a class="navbar-brand" href="<?php echo raw($basepath) ?>">Godot Asset Library</a>
-      </div>
-
-      <?php global $gPaths; $gPaths = [$basepath, $path];
-      function make_nav_link($name, $link='#') { global $gPaths; ?>
-        <li <?php if($gPaths[1] == $link) echo 'class="active"' ?>>
-          <a href="<?php echo raw($gPaths[0]) . '/' . raw($link) ?>"><?php echo esc($name) ?></a>
-        </li>
-      <?php } ?>
+    <!-- Navigation -->
+    <nav class="navbar navbar-inverse navbar-static-top" role="navigation">
+        <div class="container">
+            <!-- Brand and toggle get grouped for better mobile display -->
+            <div class="navbar-header">
+                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
+                    <span class="sr-only">Toggle navigation</span>
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                </button>
+                <a class="navbar-brand" href="<?php echo raw($basepath) ?>">Godot Asset Library</a>
+            </div>
 
-      <!-- Collect the nav links, forms, and other content for toggling -->
-      <div class="collapse navbar-collapse" id="navbar-collapse-1">
-        <ul class="nav navbar-nav navbar-left">
-          <?php make_nav_link('Assets', 'asset') ?>
-        </ul>
-        <ul class="nav navbar-nav navbar-right">
-          <?php if(isset($user)) { ?>
-            <?php make_nav_link('Feed', 'user/feed') ?>
-            <?php make_nav_link('My Assets', 'asset?user=' . url($user['username'])) ?>
-            <?php if($user['type'] >= $constants['user_type']['moderator']) { ?>
-              <?php make_nav_link('Moderate', 'asset/edit') ?>
+            <?php global $gPaths; $gPaths = [$basepath, $path];
+            function make_nav_link($name, $link='#') { global $gPaths; ?>
+                <li <?php if($gPaths[1] == $link) echo 'class="active"' ?>>
+                    <a href="<?php echo raw($gPaths[0]) . '/' . raw($link) ?>"><?php echo esc($name) ?></a>
+                </li>
             <?php } ?>
-            <li class="seperator"></li>
-            <?php make_nav_link('Submit Asset', 'asset/submit') ?>
-            <?php make_nav_link('Logout (' . esc($user['username']) . ')', 'logout') ?>
-          <?php } else { ?>
-            <?php make_nav_link('Login/Register', 'login') ?>
-          <?php } ?>
-        </ul>
-      </div>
-      <!-- /.navbar-collapse -->
-    </div>
-    <!-- /.container -->
-  </nav>
-  <div class="container">
+
+            <!-- Collect the nav links, forms, and other content for toggling -->
+            <div class="collapse navbar-collapse" id="navbar-collapse-1">
+                <ul class="nav navbar-nav navbar-left">
+                    <?php make_nav_link('Assets', 'asset') ?>
+                </ul>
+                <ul class="nav navbar-nav navbar-right">
+                    <?php if(isset($user)) { ?>
+                        <?php make_nav_link('Feed', 'user/feed') ?>
+                        <?php make_nav_link('My Assets', 'asset?user=' . url($user['username'])) ?>
+                        <?php if($user['type'] >= $constants['user_type']['moderator']) { ?>
+                            <?php make_nav_link('Moderate', 'asset/edit') ?>
+                        <?php } ?>
+                        <li class="seperator"></li>
+                        <?php make_nav_link('Submit Asset', 'asset/submit') ?>
+                        <?php make_nav_link('Logout (' . esc($user['username']) . ')', 'logout') ?>
+                    <?php } else { ?>
+                        <?php make_nav_link('Login/Register', 'login') ?>
+                    <?php } ?>
+                </ul>
+            </div>
+            <!-- /.navbar-collapse -->
+        </div>
+        <!-- /.container -->
+    </nav>
+    <div class="container">

+ 51 - 51
templates/_pagination.phtml

@@ -1,64 +1,64 @@
 <nav aria-label="Page navigation">
-  <ul class="pagination">
+    <ul class="pagination">
 
-    <?php if($data['page'] - 1 >= 0) { ?>
-      <li>
-        <a href="?<?php echo esc(http_build_query(['page' => $data['page'] - 1] + $params)) ?>" aria-label="Previous">
-          <span aria-hidden="true">&laquo;</span>
-        </a>
-      </li>
-    <?php } else { ?>
-      <li class="disabled" aria-hidden="true"><a>&laquo;</a></li>
-    <?php } ?>
+        <?php if($data['page'] - 1 >= 0) { ?>
+            <li>
+                <a href="?<?php echo esc(http_build_query(['page' => $data['page'] - 1] + $params)) ?>" aria-label="Previous">
+                    <span aria-hidden="true">&laquo;</span>
+                </a>
+            </li>
+        <?php } else { ?>
+            <li class="disabled" aria-hidden="true"><a>&laquo;</a></li>
+        <?php } ?>
 
-    <?php $page = 0; $edge_pages = 1; $mid_pages = 2; ?>
-    <?php for(; $page < $edge_pages && $page < $data['page'] && $page < $data['pages']; $page++) { ?>
-      <li><a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a></li>
-    <?php } ?>
+        <?php $page = 0; $edge_pages = 1; $mid_pages = 2; ?>
+        <?php for(; $page < $edge_pages && $page < $data['page'] && $page < $data['pages']; $page++) { ?>
+            <li><a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a></li>
+        <?php } ?>
 
-    <?php if($page < $data['page'] && $page < $data['page'] - $mid_pages) { ?>
-      <li class="disabled"><a>…</a></li>
-    <?php } ?>
+        <?php if($page < $data['page'] && $page < $data['page'] - $mid_pages) { ?>
+            <li class="disabled"><a>…</a></li>
+        <?php } ?>
 
-    <?php for($page = max($page, $data['page'] - $mid_pages); $page < $data['page'] + $mid_pages + 1 && $page < $data['pages']; $page++) { ?>
-      <?php if($page == $data['page']) { ?>
-        <li class="active">
-          <a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a>
-        </li>
-        <span class="sr-only">(current)</span>
-      <?php } else { ?>
-        <li><a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a></li>
-      <?php } ?>
-    <?php } ?>
+        <?php for($page = max($page, $data['page'] - $mid_pages); $page < $data['page'] + $mid_pages + 1 && $page < $data['pages']; $page++) { ?>
+            <?php if($page == $data['page']) { ?>
+                <li class="active">
+                    <a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a>
+                </li>
+                <span class="sr-only">(current)</span>
+            <?php } else { ?>
+                <li><a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a></li>
+            <?php } ?>
+        <?php } ?>
 
-    <?php if($page < $data['pages'] - $edge_pages) { ?>
-      <li class="disabled"><a>…</a></li>
-    <?php } ?>
+        <?php if($page < $data['pages'] - $edge_pages) { ?>
+            <li class="disabled"><a>…</a></li>
+        <?php } ?>
 
-    <?php for($page = max($page, $data['pages'] - $edge_pages); $page < $data['pages']; $page++) { ?>
-      <li><a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a></li>
-    <?php } ?>
+        <?php for($page = max($page, $data['pages'] - $edge_pages); $page < $data['pages']; $page++) { ?>
+            <li><a href="?<?php echo esc(http_build_query(['page' => $page] + $params)) ?>"><?php echo $page + 1; ?></a></li>
+        <?php } ?>
 
-    <?php if($data['page'] + 1 < $data['pages']) { ?>
-      <li>
-        <a href="?<?php echo esc(http_build_query(['page' => $data['page'] + 1] + $params)) ?>" aria-label="Next">
-          <span aria-hidden="true">&raquo;</span>
-        </a>
-      </li>
-    <?php } else { ?>
-      <li class="disabled" aria-hidden="true"><a>&raquo;</a></li>
-    <?php } ?>
-  </ul>
+        <?php if($data['page'] + 1 < $data['pages']) { ?>
+            <li>
+                <a href="?<?php echo esc(http_build_query(['page' => $data['page'] + 1] + $params)) ?>" aria-label="Next">
+                    <span aria-hidden="true">&raquo;</span>
+                </a>
+            </li>
+        <?php } else { ?>
+            <li class="disabled" aria-hidden="true"><a>&raquo;</a></li>
+        <?php } ?>
+    </ul>
 </nav>
 <p>
-  <?php echo esc($data['page_length']) ?> item<?php if($data['page_length'] != 1) echo 's' ?> per page, <?php echo esc($data['total_items']) ?> item<?php if($data['total_items'] != 1) echo 's' ?> total.
+    <?php echo esc($data['page_length']) ?> item<?php if($data['page_length'] != 1) echo 's' ?> per page, <?php echo esc($data['total_items']) ?> item<?php if($data['total_items'] != 1) echo 's' ?> total.
 </p>
 <p>
-  Change items per page to: <span class="btn-group btn-group-xs" role="group" aria-label="Page size">
-    <?php foreach ([10, 20, 50, 100, 200, 500] as $amount) { ?>
-      <a href="?<?php echo esc(http_build_query(['max_results' => $amount, 'page' => floor($data['page'] * $data['page_length'] / $amount)] + $params)) ?>" class="btn btn-default" aria-label="Per page">
-        <?php echo raw($amount); ?>
-      </a>
-    <?php } ?>
-  </span>
+    Change items per page to: <span class="btn-group btn-group-xs" role="group" aria-label="Page size">
+        <?php foreach ([10, 20, 50, 100, 200, 500] as $amount) { ?>
+            <a href="?<?php echo esc(http_build_query(['max_results' => $amount, 'page' => floor($data['page'] * $data['page_length'] / $amount)] + $params)) ?>" class="btn btn-default" aria-label="Per page">
+                <?php echo raw($amount); ?>
+            </a>
+        <?php } ?>
+    </span>
 </p>

+ 73 - 73
templates/asset.phtml

@@ -1,82 +1,82 @@
 <?php include("_header.phtml") ?>
 <div class="media">
-  <div class="media-left">
-    <img class="media-object" src="<?php echo esc($data['icon_url']) ?>" alt="<?php echo esc($data['title']) ?>'s icon" width="80" height="80">
-  </div>
-  <div class="media-body">
-    <h4 class="media-heading">
-      <?php echo esc($data['title']) ?>
-      <small><?php echo esc($data['version_string']) ?></small>
-      <?php for ($star=1; $star <= 5; $star++) { ?>
-        <i class="glyphicon glyphicon-star<?php if($data['rating'] < $star) echo '-empty'; ?>"></i>
-      <?php } ?>
-      <span class="label label-primary"><?php echo esc($data['category']) ?></span>
-      <span class="label label-<?php echo raw([
-        'official' => 'success',
-        'community' => 'info',
-        'testing' => 'default',
-      ][$data['support_level']]) ?>"><?php echo esc(ucfirst($data['support_level'])) ?></span>
-    </h4>
+    <div class="media-left">
+        <img class="media-object" src="<?php echo esc($data['icon_url']) ?>" alt="<?php echo esc($data['title']) ?>'s icon" width="80" height="80">
+    </div>
+    <div class="media-body">
+        <h4 class="media-heading">
+            <?php echo esc($data['title']) ?>
+            <small><?php echo esc($data['version_string']) ?></small>
+            <?php for ($star=1; $star <= 5; $star++) { ?>
+                <i class="glyphicon glyphicon-star<?php if($data['rating'] < $star) echo '-empty'; ?>"></i>
+            <?php } ?>
+            <span class="label label-primary"><?php echo esc($data['category']) ?></span>
+            <span class="label label-<?php echo raw([
+                'official' => 'success',
+                'community' => 'info',
+                'testing' => 'default',
+            ][$data['support_level']]) ?>"><?php echo esc(ucfirst($data['support_level'])) ?></span>
+        </h4>
 
-    <p class="text-muted">Submitted by user <?php echo esc($data['author']) ?>; <?php echo esc($data['cost']) ?></p>
-    <p>
-      <?php echo nl2br(esc($data['description']), false) ?>
-    </p>
-    <hr/>
-    <p>
-      <a class="btn btn-default" href="<?php echo esc($data['browse_url']) ?>">
-        <i class="glyphicon glyphicon-folder-open"></i> View files
-      </a>
-      <a class="btn btn-primary" href="<?php echo esc($data['download_url']) ?>">
-        <i class="glyphicon glyphicon-download"></i> Download
-      </a>
-      <?php if($data['issues_url'] != "") { ?>
-        <a class="btn btn-success" href="<?php echo esc($data['issues_url']) ?>">
-          <i class="glyphicon glyphicon-check"></i> Submit an issue
-        </a>
-      <?php } ?>
-      <?php if(isset($user) && ($user['user_id'] == $data['author_id'] || $user['type'] >= $constants['user_type']['editor'])) { ?>
-        <a class="btn btn-success" href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>/edit">
-          <i class="glyphicon glyphicon-pencil"></i> Edit
-        </a>
-      <?php } ?>
-      <a class="btn btn-warning" href="<?php echo raw($basepath) ?>/asset/edit?asset=<?php echo url($data['asset_id']) ?>&amp;status=accepted+rejected">
-        <i class="glyphicon glyphicon-list"></i> Recent Edits
-      </a>
-    </p>
-    <?php if(isset($user) && ($user['type'] >= $constants['user_type']['moderator'])) { ?>
-      <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>/support_level" method="post">
-        <?php include("_csrf.phtml") ?>
-        <div class="btn-group">
-          <select id="support_level" name="support_level" class="form-control btn btn-default">
-            <?php foreach($constants['support_level'] as $id => $name) if(is_int($id)) { ?>
-              <option value="<?php echo esc($name) ?>" <?php if($name == $data['support_level']) echo 'selected=""'; ?>>
-                <?php echo esc(ucfirst($name)) ?>
-              </option>
+        <p class="text-muted">Submitted by user <?php echo esc($data['author']) ?>; <?php echo esc($data['cost']) ?></p>
+        <p>
+            <?php echo nl2br(esc($data['description']), false) ?>
+        </p>
+        <hr/>
+        <p>
+            <a class="btn btn-default" href="<?php echo esc($data['browse_url']) ?>">
+                <i class="glyphicon glyphicon-folder-open"></i> View files
+            </a>
+            <a class="btn btn-primary" href="<?php echo esc($data['download_url']) ?>">
+                <i class="glyphicon glyphicon-download"></i> Download
+            </a>
+            <?php if($data['issues_url'] != "") { ?>
+                <a class="btn btn-success" href="<?php echo esc($data['issues_url']) ?>">
+                    <i class="glyphicon glyphicon-check"></i> Submit an issue
+                </a>
             <?php } ?>
-          </select>
-          <button type="submit" class="btn btn-danger">Change support level</button>
-        </div>
-      </form>
-    <?php } ?>
-    <p class="text-muted">Sha256 Hash: <code><?php echo esc($data['download_hash']) ?></code></p>
-    <hr/>
-  </div>
+            <?php if(isset($user) && ($user['user_id'] == $data['author_id'] || $user['type'] >= $constants['user_type']['editor'])) { ?>
+                <a class="btn btn-success" href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>/edit">
+                    <i class="glyphicon glyphicon-pencil"></i> Edit
+                </a>
+            <?php } ?>
+            <a class="btn btn-warning" href="<?php echo raw($basepath) ?>/asset/edit?asset=<?php echo url($data['asset_id']) ?>&amp;status=accepted+rejected">
+                <i class="glyphicon glyphicon-list"></i> Recent Edits
+            </a>
+        </p>
+        <?php if(isset($user) && ($user['type'] >= $constants['user_type']['moderator'])) { ?>
+            <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>/support_level" method="post">
+                <?php include("_csrf.phtml") ?>
+                <div class="btn-group">
+                    <select id="support_level" name="support_level" class="form-control btn btn-default">
+                        <?php foreach($constants['support_level'] as $id => $name) if(is_int($id)) { ?>
+                            <option value="<?php echo esc($name) ?>" <?php if($name == $data['support_level']) echo 'selected=""'; ?>>
+                                <?php echo esc(ucfirst($name)) ?>
+                            </option>
+                        <?php } ?>
+                    </select>
+                    <button type="submit" class="btn btn-danger">Change support level</button>
+                </div>
+            </form>
+        <?php } ?>
+        <p class="text-muted">Sha256 Hash: <code><?php echo esc($data['download_hash']) ?></code></p>
+        <hr/>
+    </div>
 </div>
 <div class="row">
-  <?php foreach($data['previews'] as $key => $preview) { ?>
-    <div class="col-xs-6 col-md-4 col-lg-3 text-center">
-      <a href="<?php echo esc($preview['link']) ?>" target="_blank" class="thumbnail">
-        <?php if($preview['type'] == 'image') { ?>
-          <img src="<?php echo esc($preview['link']) ?>" width="100%"/>
-        <?php } else { ?>
-          <img src="<?php echo esc($preview['thumbnail']) ?>" width="100%"/>
-          <div class="btn btn-primary btn-lg" style="position: absolute; top: 50%; left: 50%; transform:translate(-50%,-50%); opacity: 0.8;">
-            <i class="glyphicon glyphicon-play" style="font-size:2em"></i>
-          </div>
+    <?php foreach($data['previews'] as $key => $preview) { ?>
+        <div class="col-xs-6 col-md-4 col-lg-3 text-center">
+            <a href="<?php echo esc($preview['link']) ?>" target="_blank" class="thumbnail">
+                <?php if($preview['type'] == 'image') { ?>
+                    <img src="<?php echo esc($preview['link']) ?>" width="100%"/>
+                <?php } else { ?>
+                    <img src="<?php echo esc($preview['thumbnail']) ?>" width="100%"/>
+                    <div class="btn btn-primary btn-lg" style="position: absolute; top: 50%; left: 50%; transform:translate(-50%,-50%); opacity: 0.8;">
+                        <i class="glyphicon glyphicon-play" style="font-size:2em"></i>
+                    </div>
+                <?php } ?>
+            </a>
+        </div>
         <?php } ?>
-      </a>
-    </div>
-    <?php } ?>
 </div>
 <?php include("_footer.phtml") ?>

+ 158 - 158
templates/asset_edit.phtml

@@ -1,192 +1,192 @@
 <?php include("_header.phtml") ?>
 <?php $field_names = [
-  'title' => 'Title',
-  'description' => 'Description',
-  'category_id' => 'Category',
-  'version_string' => 'Version String',
-  'cost' => 'License',
-  'browse_url' => 'Repository Url',
-  'issues_url' => 'Issues Url',
-  'download_provider' => 'Repository Provider',
-  'download_commit' => 'Download Commit',
-  'download_url' => 'Download Url (Computed)',
-  'icon_url' => 'Icon Url',
+    'title' => 'Title',
+    'description' => 'Description',
+    'category_id' => 'Category',
+    'version_string' => 'Version String',
+    'cost' => 'License',
+    'browse_url' => 'Repository Url',
+    'issues_url' => 'Issues Url',
+    'download_provider' => 'Repository Provider',
+    'download_commit' => 'Download Commit',
+    'download_url' => 'Download Url (Computed)',
+    'icon_url' => 'Icon Url',
 ];
 $preview_field_names = [
-  'type' => 'Type',
-  'link' => 'Image/Video URL',
-  'thumbnail' => 'Thumbnail',
+    'type' => 'Type',
+    'link' => 'Image/Video URL',
+    'thumbnail' => 'Thumbnail',
 ]; ?>
 
 <?php function output_field($data, $name, $categories = []) { ?>
-  <?php if (strpos($name, 'url') !== false || strpos($name, 'link') !== false || strpos($name, 'thumbnail') !== false) { ?>
-    <a href="<?php echo esc($data) ?>"><?php echo esc($data) ?></a>
-    <?php if ($name == 'icon_url') { ?>
-      <br><img src="<?php echo esc($data) ?>" width="80" height="80"></a>
-    <?php }?>
-    <?php if ($name == 'preview_link') { ?>
-      <br><img src="<?php echo esc($data) ?>" style="max-height:80px"></a>
-    <?php }?>
-    <?php if ($name == 'preview_thumbnail') { ?>
-      <br><img src="<?php echo esc($data) ?>" style="max-height:345px"></a>
-    <?php }?>
-  <?php } elseif($name == 'category_id') { ?>
-    <?php echo raw($categories[$data]['name']) ?>
-  <?php } elseif($name == 'description') { ?>
-    <?php echo nl2br(esc($data)) ?>
-  <?php } else { ?>
-    <?php echo esc($data) ?>
-  <?php } ?>
+    <?php if (strpos($name, 'url') !== false || strpos($name, 'link') !== false || strpos($name, 'thumbnail') !== false) { ?>
+        <a href="<?php echo esc($data) ?>"><?php echo esc($data) ?></a>
+        <?php if ($name == 'icon_url') { ?>
+            <br><img src="<?php echo esc($data) ?>" width="80" height="80"></a>
+        <?php }?>
+        <?php if ($name == 'preview_link') { ?>
+            <br><img src="<?php echo esc($data) ?>" style="max-height:80px"></a>
+        <?php }?>
+        <?php if ($name == 'preview_thumbnail') { ?>
+            <br><img src="<?php echo esc($data) ?>" style="max-height:345px"></a>
+        <?php }?>
+    <?php } elseif($name == 'category_id') { ?>
+        <?php echo raw($categories[$data]['name']) ?>
+    <?php } elseif($name == 'description') { ?>
+        <?php echo nl2br(esc($data)) ?>
+    <?php } else { ?>
+        <?php echo esc($data) ?>
+    <?php } ?>
 <?php } ?>
 
 <h1>
-  <?php if(isset($data['original'])) { ?>
-    Edit of asset
-    <a href="<?php echo raw($basepath) ?>/asset/<?php echo raw($data['asset_id']) ?>">"<?php echo esc($data['original']['title']) ?>"</a>
-  <?php } else { ?>
-    Creation of asset
-    <a href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>">"<?php echo esc($data['title']) ?>"</a>
-  <?php } ?>
-  <span class="label label-<?php echo raw(['new' => 'info', 'in_review' => 'primary', 'rejected' => 'danger', 'accepted' => 'success'][$data['status']]) ?>">
-    <?php echo raw(ucfirst(str_replace('_', ' ', $data['status']))) ?>
-  </span>
+    <?php if(isset($data['original'])) { ?>
+        Edit of asset
+        <a href="<?php echo raw($basepath) ?>/asset/<?php echo raw($data['asset_id']) ?>">"<?php echo esc($data['original']['title']) ?>"</a>
+    <?php } else { ?>
+        Creation of asset
+        <a href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>">"<?php echo esc($data['title']) ?>"</a>
+    <?php } ?>
+    <span class="label label-<?php echo raw(['new' => 'info', 'in_review' => 'primary', 'rejected' => 'danger', 'accepted' => 'success'][$data['status']]) ?>">
+        <?php echo raw(ucfirst(str_replace('_', ' ', $data['status']))) ?>
+    </span>
 </h1>
 
 <?php if(isset($user) && $data['user_id'] == $user['user_id'] && $data['status'] == 'new') { ?>
-  <div class="form-group">
-    <a class="btn btn-success" href="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/edit">Edit modifications</a>
-  </div>
-  <div class="alert alert-info" role="alert">
-    <?php if($data['asset_id'] != -1) { ?>
-      This edit you made is currently pending approval by our moderators. <strong>When it is approved, changes would finally go live</strong>. To access this page again later, you can use the "View pending" button on the asset's page, or just use the "Feed" button in the toolbar. <!--You will be notified by email when decision is made.-->
-    <?php } else { ?>
-      This new asset is currently pending approval by our moderators. <strong>Only when it is approved, it would be searchable</strong>. To access this page again later, you can use the <em>"View pending"</em> button on the "My assets" page, or just use the "Feed" button in the toolbar. <!--You will be notified by email when decision is made.-->
-    <?php } ?>
-  </div>
+    <div class="form-group">
+        <a class="btn btn-success" href="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/edit">Edit modifications</a>
+    </div>
+    <div class="alert alert-info" role="alert">
+        <?php if($data['asset_id'] != -1) { ?>
+            This edit you made is currently pending approval by our moderators. <strong>When it is approved, changes would finally go live</strong>. To access this page again later, you can use the "View pending" button on the asset's page, or just use the "Feed" button in the toolbar. <!--You will be notified by email when decision is made.-->
+        <?php } else { ?>
+            This new asset is currently pending approval by our moderators. <strong>Only when it is approved, it would be searchable</strong>. To access this page again later, you can use the <em>"View pending"</em> button on the "My assets" page, or just use the "Feed" button in the toolbar. <!--You will be notified by email when decision is made.-->
+        <?php } ?>
+    </div>
 <?php } ?>
 
 <?php if($data['status'] == 'rejected') { ?>
-  <div class="alert alert-danger" role="alert">
-    This asset <?php if($data['asset_id'] != -1) echo 'edit ' ?>has been rejected. Reason: <?php echo esc($data['reason']) ?>
-  </div>
+    <div class="alert alert-danger" role="alert">
+        This asset <?php if($data['asset_id'] != -1) echo 'edit ' ?>has been rejected. Reason: <?php echo esc($data['reason']) ?>
+    </div>
 <?php } ?>
 
 <?php if(isset($data['warning'])) { ?>
-  <div class="alert alert-warning" role="alert">
-    <strong>Warning:</strong> <?php echo nl2br(esc($data['warning'])) ?>
-    <br><br>
-    <em>If you think that this warning should not be here, you can always <a href="https://github.com/godotengine/asset-library/issues">open an issue</a>.</em>
-  </div>
+    <div class="alert alert-warning" role="alert">
+        <strong>Warning:</strong> <?php echo nl2br(esc($data['warning'])) ?>
+        <br><br>
+        <em>If you think that this warning should not be here, you can always <a href="https://github.com/godotengine/asset-library/issues">open an issue</a>.</em>
+    </div>
 <?php } ?>
 
 <table class="table table-bordered">
-  <tbody>
-    <tr>
-      <th>Property</th>
-      <?php if(isset($data['original'])) { ?>
-        <th style="min-width: 50%" class="text-center">Old/Current</th>
-      <?php } ?>
-      <th style="min-width: 50%" class="text-center">New/Edit</th>
-    </tr>
-    <?php foreach($field_names as $field => $name) { ?>
-      <tr>
-        <td>
-          <?php echo raw($name) ?>
-        </td>
-        <?php if(isset($data['original']) && $data[$field] == null) { ?>
-
-          <td colspan="2" class="text-center active">
-            <?php output_field($data['original'][$field], $field, $categories) ?>
-          </td>
-
-        <?php } else { ?>
-          <?php if(isset($data['original'])) { ?>
-
-            <td class="text-right danger">
-              <?php output_field($data['original'][$field], $field, $categories) ?>
-            </td>
-
-          <?php } ?>
+    <tbody>
+        <tr>
+            <th>Property</th>
+            <?php if(isset($data['original'])) { ?>
+                <th style="min-width: 50%" class="text-center">Old/Current</th>
+            <?php } ?>
+            <th style="min-width: 50%" class="text-center">New/Edit</th>
+        </tr>
+        <?php foreach($field_names as $field => $name) { ?>
+            <tr>
+                <td>
+                    <?php echo raw($name) ?>
+                </td>
+                <?php if(isset($data['original']) && $data[$field] == null) { ?>
 
-          <td class="text-left success">
-            <?php output_field($data[$field], $field, $categories) ?>
-          </td>
+                    <td colspan="2" class="text-center active">
+                        <?php output_field($data['original'][$field], $field, $categories) ?>
+                    </td>
 
-        <?php } ?>
-      </tr>
-    <?php } ?>
-    <?php foreach($data['previews'] as $i => $preview) if(isset($preview['edit_preview_id'])) { ?>
-      <tr>
-        <th colspan="3" class="text-center">
-          Preview
-          <span class="label label-danger"><?php output_field(ucfirst($preview['operation']), 'preview_operation') ?></span>
-        </th>
-      </tr>
-      <?php foreach($preview_field_names as $field => $name) { ?>
-        <tr>
-          <td>
-            <?php echo raw($name) ?>
-          </td>
-          <?php if(isset($preview['original']) && $preview['operation'] != "remove" && ($preview[$field] === null || $preview[$field] === $preview['original'][$field])) { ?>
+                <?php } else { ?>
+                    <?php if(isset($data['original'])) { ?>
 
-            <td colspan="2" class="text-center active">
-              <?php output_field($preview['original'][$field], 'preview_' . $field, $categories) ?>
-            </td>
+                        <td class="text-right danger">
+                            <?php output_field($data['original'][$field], $field, $categories) ?>
+                        </td>
 
-          <?php } else { ?>
-            <?php if(isset($preview['original'])) { ?>
+                    <?php } ?>
 
-              <?php if($preview['operation'] == "remove") { ?>
-                <td class="text-center danger" colspan="2">
-                  <?php output_field($preview['original'][$field], 'preview_' . $field, $categories) ?>
-                </td>
-              <?php } else { ?>
-                <td class="text-right danger">
-                  <?php output_field($preview['original'][$field], 'preview_' . $field, $categories) ?>
-                </td>
-                <td class="text-left success">
-                  <?php output_field($preview[$field], 'preview_' . $field, $categories) ?>
-                </td>
-              <?php } ?>
+                    <td class="text-left success">
+                        <?php output_field($data[$field], $field, $categories) ?>
+                    </td>
 
-            <?php } else { ?>
-              <td class="text-center success" colspan="2">
-                <?php output_field($preview[$field], 'preview_' . $field, $categories) ?>
-              </td>
+                <?php } ?>
+            </tr>
+        <?php } ?>
+        <?php foreach($data['previews'] as $i => $preview) if(isset($preview['edit_preview_id'])) { ?>
+            <tr>
+                <th colspan="3" class="text-center">
+                    Preview
+                    <span class="label label-danger"><?php output_field(ucfirst($preview['operation']), 'preview_operation') ?></span>
+                </th>
+            </tr>
+            <?php foreach($preview_field_names as $field => $name) { ?>
+                <tr>
+                    <td>
+                        <?php echo raw($name) ?>
+                    </td>
+                    <?php if(isset($preview['original']) && $preview['operation'] != "remove" && ($preview[$field] === null || $preview[$field] === $preview['original'][$field])) { ?>
+
+                        <td colspan="2" class="text-center active">
+                            <?php output_field($preview['original'][$field], 'preview_' . $field, $categories) ?>
+                        </td>
+
+                    <?php } else { ?>
+                        <?php if(isset($preview['original'])) { ?>
+
+                            <?php if($preview['operation'] == "remove") { ?>
+                                <td class="text-center danger" colspan="2">
+                                    <?php output_field($preview['original'][$field], 'preview_' . $field, $categories) ?>
+                                </td>
+                            <?php } else { ?>
+                                <td class="text-right danger">
+                                    <?php output_field($preview['original'][$field], 'preview_' . $field, $categories) ?>
+                                </td>
+                                <td class="text-left success">
+                                    <?php output_field($preview[$field], 'preview_' . $field, $categories) ?>
+                                </td>
+                            <?php } ?>
+
+                        <?php } else { ?>
+                            <td class="text-center success" colspan="2">
+                                <?php output_field($preview[$field], 'preview_' . $field, $categories) ?>
+                            </td>
+                        <?php } ?>
+
+                    <?php } ?>
+                </tr>
             <?php } ?>
-
-          <?php } ?>
-        </tr>
-      <?php } ?>
-    <?php } ?>
-  </tbody>
+        <?php } ?>
+    </tbody>
 </table>
 <?php if(isset($user)) { ?>
-  <?php if($user['type'] >= $constants['user_type']['moderator']) { ?>
-    <?php if($data['status'] == 'new') { ?>
-      <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/review" method="post">
-        <?php include("_csrf.phtml") ?>
-        <button type="submit" class="btn btn-primary">Put in queue</button>
-      </form>
-    <?php } elseif($data['status'] == 'in_review') { ?>
-      <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/accept" method="post">
-        <?php include("_csrf.phtml") ?>
-        <div class="form-group panel">
-          <button type="submit" class="btn btn-success">Accept</button>
-          <label class="control-label" for="hash">Hash:</label>
-          <input type="text" class="form-control" id="hash" name="hash">
-        </div>
-      </form>
-
-      <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/reject" method="post">
-        <?php include("_csrf.phtml") ?>
-        <div class="form-group panel">
-          <button type="submit" class="btn btn-danger">Reject</button>
-          <label class="control-label" for="reason" required>Reason:</label>
-          <input type="text" class="form-control" id="reason" name="reason">
-        </div>
-      </form>
+    <?php if($user['type'] >= $constants['user_type']['moderator']) { ?>
+        <?php if($data['status'] == 'new') { ?>
+            <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/review" method="post">
+                <?php include("_csrf.phtml") ?>
+                <button type="submit" class="btn btn-primary">Put in queue</button>
+            </form>
+        <?php } elseif($data['status'] == 'in_review') { ?>
+            <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/accept" method="post">
+                <?php include("_csrf.phtml") ?>
+                <div class="form-group panel">
+                    <button type="submit" class="btn btn-success">Accept</button>
+                    <label class="control-label" for="hash">Hash:</label>
+                    <input type="text" class="form-control" id="hash" name="hash">
+                </div>
+            </form>
+
+            <form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/reject" method="post">
+                <?php include("_csrf.phtml") ?>
+                <div class="form-group panel">
+                    <button type="submit" class="btn btn-danger">Reject</button>
+                    <label class="control-label" for="reason" required>Reason:</label>
+                    <input type="text" class="form-control" id="reason" name="reason">
+                </div>
+            </form>
+        <?php } ?>
     <?php } ?>
-  <?php } ?>
 <?php } ?>
 <?php include("_footer.phtml") ?>

+ 63 - 63
templates/asset_edits.phtml

@@ -1,76 +1,76 @@
 <?php include("_header.phtml") ?>
 
 <form method="get" action="edit">
-  <div class="form-inline">
-    <div class="form-group">
-      <label>Status</label>
-      <?php foreach($constants['edit_status'] as $id => $status) if(is_int($id)) { ?>
-        <label>
-          <input type="checkbox" name="status[<?php echo esc($status) ?>]" value="1"
-            <?php if(isset($params['status']) && (is_array($params['status']) ?
-              isset($params['status'][$status]) && $params['status'][$status] :
-              in_array($status, explode(' ', $params['status'])))
-            ) echo 'checked=""';
-            ?>>
-          <?php echo esc(ucfirst(str_replace('_', ' ', $status))) ?>
-        </label>
-      <?php } ?>
+    <div class="form-inline">
+        <div class="form-group">
+            <label>Status</label>
+            <?php foreach($constants['edit_status'] as $id => $status) if(is_int($id)) { ?>
+                <label>
+                    <input type="checkbox" name="status[<?php echo esc($status) ?>]" value="1"
+                        <?php if(isset($params['status']) && (is_array($params['status']) ?
+                            isset($params['status'][$status]) && $params['status'][$status] :
+                            in_array($status, explode(' ', $params['status'])))
+                        ) echo 'checked=""';
+                        ?>>
+                    <?php echo esc(ucfirst(str_replace('_', ' ', $status))) ?>
+                </label>
+            <?php } ?>
+        </div>
+        <?php if(isset($params['asset'])) { ?>
+            <div style="display:inline-block;width:40px;"></div>
+            <div class="form-group bg-primary" style="padding:0 5px;">
+                <label>
+                    <input type="checkbox" name="asset" value="<?php echo esc($params['asset']) ?>" checked="">
+                    <?php if($params['asset'] == -1) { ?>
+                        Only new assets
+                    <?php } else { ?>
+                        Only asset #<?php echo esc($params['asset']) ?>
+                    <?php } ?>
+                </label>
+            </div>
+        <?php } ?>
+        <?php if(isset($params['user'])) { ?>
+            <div style="display:inline-block;width:40px;"></div>
+            <div class="form-group bg-primary" style="padding:0 5px;">
+                <label>
+                    <input type="checkbox" name="user" value="<?php echo esc($params['user']) ?>" checked="">
+                    Only by <?php echo esc($params['user']) ?>
+                </label>
+            </div>
+        <?php } ?>
+    </div>
+    <div class="input-group">
+        <input type="text" class="form-control" name="filter" placeholder="Search for..." value="<?php if(isset($params['filter'])) echo esc($params['filter']) ?>">
+        <span class="input-group-btn">
+            <button class="btn btn-default" type="submit">Search</button>
+        </span>
     </div>
-    <?php if(isset($params['asset'])) { ?>
-      <div style="display:inline-block;width:40px;"></div>
-      <div class="form-group bg-primary" style="padding:0 5px;">
-        <label>
-          <input type="checkbox" name="asset" value="<?php echo esc($params['asset']) ?>" checked="">
-          <?php if($params['asset'] == -1) { ?>
-            Only new assets
-          <?php } else { ?>
-            Only asset #<?php echo esc($params['asset']) ?>
-          <?php } ?>
-        </label>
-      </div>
-    <?php } ?>
-    <?php if(isset($params['user'])) { ?>
-      <div style="display:inline-block;width:40px;"></div>
-      <div class="form-group bg-primary" style="padding:0 5px;">
-        <label>
-          <input type="checkbox" name="user" value="<?php echo esc($params['user']) ?>" checked="">
-          Only by <?php echo esc($params['user']) ?>
-        </label>
-      </div>
-    <?php } ?>
-  </div>
-  <div class="input-group">
-    <input type="text" class="form-control" name="filter" placeholder="Search for..." value="<?php if(isset($params['filter'])) echo esc($params['filter']) ?>">
-    <span class="input-group-btn">
-      <button class="btn btn-default" type="submit">Search</button>
-    </span>
-  </div>
 </form>
 
 <?php foreach($data['result'] as $i => $asset_edit) { ?>
-    <div class="media">
-      <div class="media-left">
-        <a href="<?php echo raw($basepath) . '/asset/edit/' . url($asset_edit['edit_id']) ?>">
-          <img class="media-object" src="<?php echo esc($asset_edit['icon_url']) ?>" alt="<?php echo esc($asset_edit['title']) ?>'s icon" width=80 height=80>
-        </a>
-      </div>
-      <div class="media-body">
-        <h4 class="media-heading">
-          <a href="<?php echo raw($basepath) . '/asset/edit/' . url($asset_edit['edit_id']) ?>"><?php echo ($asset_edit['asset_id'] == -1 ? 'Create ' : 'Edit ') . esc($asset_edit['title']) ?></a>
+        <div class="media">
+            <div class="media-left">
+                <a href="<?php echo raw($basepath) . '/asset/edit/' . url($asset_edit['edit_id']) ?>">
+                    <img class="media-object" src="<?php echo esc($asset_edit['icon_url']) ?>" alt="<?php echo esc($asset_edit['title']) ?>'s icon" width=80 height=80>
+                </a>
+            </div>
+            <div class="media-body">
+                <h4 class="media-heading">
+                    <a href="<?php echo raw($basepath) . '/asset/edit/' . url($asset_edit['edit_id']) ?>"><?php echo ($asset_edit['asset_id'] == -1 ? 'Create ' : 'Edit ') . esc($asset_edit['title']) ?></a>
 
-          <span class="label label-<?php echo raw(['new' => 'info', 'in_review' => 'primary', 'rejected' => 'danger', 'accepted' => 'success'][$asset_edit['status']]) ?>"><?php echo raw(ucfirst(str_replace('_', ' ', $asset_edit['status']))) ?></span>
+                    <span class="label label-<?php echo raw(['new' => 'info', 'in_review' => 'primary', 'rejected' => 'danger', 'accepted' => 'success'][$asset_edit['status']]) ?>"><?php echo raw(ucfirst(str_replace('_', ' ', $asset_edit['status']))) ?></span>
 
-          <span class="label label-<?php echo raw([
-            'official' => 'danger',
-            'community' => 'info',
-            'testing' => 'success',
-          ][$asset_edit['support_level']]) ?>"><?php echo raw(ucfirst($asset_edit['support_level'])) ?></span>
-        </h4>
+                    <span class="label label-<?php echo raw([
+                        'official' => 'danger',
+                        'community' => 'info',
+                        'testing' => 'success',
+                    ][$asset_edit['support_level']]) ?>"><?php echo raw(ucfirst($asset_edit['support_level'])) ?></span>
+                </h4>
 
-        <p>Submitted by user <?php echo esc($asset_edit['author']) ?></p>
-        <?php if($asset_edit['status'] == 'rejected' && $asset_edit['reason']) echo 'Rejection reason: ' . esc($asset_edit['reason']) ?>
-      </div>
-    </div>
+                <p>Submitted by user <?php echo esc($asset_edit['author']) ?></p>
+                <?php if($asset_edit['status'] == 'rejected' && $asset_edit['reason']) echo 'Rejection reason: ' . esc($asset_edit['reason']) ?>
+            </div>
+        </div>
 <?php } ?>
 <?php include("_pagination.phtml") ?>
 <?php include("_footer.phtml") ?>

+ 83 - 83
templates/assets.phtml

@@ -1,97 +1,97 @@
 <?php include("_header.phtml") ?>
 <form method="get" action="asset">
-  <div class="form-inline">
-    <div class="form-group">
-      <label for="category">Category</label>
-      <select id="category" name="category" class="form-control">
-        <option value="">
-          Any
-        </option>
+    <div class="form-inline">
+        <div class="form-group">
+            <label for="category">Category</label>
+            <select id="category" name="category" class="form-control">
+                <option value="">
+                    Any
+                </option>
 
-        <?php foreach($categories as $key => $category) { ?>
-          <option value="<?php echo esc($category['id']) ?>" <?php if(isset($params['category']) && $category['id'] == $params['category']) echo 'selected=""'; ?>>
-            <?php echo esc($category['name']) ?>
-          </option>
+                <?php foreach($categories as $key => $category) { ?>
+                    <option value="<?php echo esc($category['id']) ?>" <?php if(isset($params['category']) && $category['id'] == $params['category']) echo 'selected=""'; ?>>
+                        <?php echo esc($category['name']) ?>
+                    </option>
+                <?php } ?>
+            </select>
+        </div>
+        <div style="display:inline-block;width:40px;"></div>
+        <div class="form-group">
+            <label>Support level</label>
+            <?php foreach($constants['support_level'] as $id => $level) if(is_int($id)) { ?>
+                <label>
+                    <input type="checkbox" name="support[<?php echo esc($level) ?>]" value="1"
+                        <?php if(isset($params['support']) && (is_array($params['support']) ?
+                            isset($params['support'][$level]) && $params['support'][$level] :
+                            in_array($level, explode(' ', $params['support'])))
+                        ) echo 'checked=""';
+                        ?>>
+                    <?php echo esc(ucfirst($level)) ?>
+                </label>
+            <?php } ?>
+        </div>
+        <div style="display:inline-block;width:40px;"></div>
+        <div class="form-group">
+            <label for="sort">Order by</label>
+            <select id="sort" name="sort" class="form-control">
+                <?php if(!isset($params['sort'])) $params['sort'] = 'updated'; foreach(['rating', 'cost', 'name', 'updated'] as $id => $order) { ?>
+                    <option value="<?php echo esc($order) ?>" <?php if(isset($params['sort']) && $order == $params['sort']) echo 'selected=""'; ?>>
+                        <?php echo esc(ucfirst($order)) ?>
+                    </option>
+                <?php } ?>
+            </select>
+            <label>
+                <input type="checkbox" name="reverse" <?php if(isset($params['reverse'])) echo 'checked=""'; ?>>
+                Reverse
+            </label>
+        </div>
+        <?php if(isset($params['user'])) { ?>
+            <div style="display:inline-block;width:40px;"></div>
+            <div class="form-group bg-primary" style="padding:0 5px;">
+                <label>
+                    <input type="checkbox" name="user" value="<?php echo esc($params['user']) ?>" checked="">
+                    Only by <?php echo esc($params['user']) ?>
+                </label>
+            </div>
         <?php } ?>
-      </select>
-    </div>
-    <div style="display:inline-block;width:40px;"></div>
-    <div class="form-group">
-      <label>Support level</label>
-      <?php foreach($constants['support_level'] as $id => $level) if(is_int($id)) { ?>
-        <label>
-          <input type="checkbox" name="support[<?php echo esc($level) ?>]" value="1"
-            <?php if(isset($params['support']) && (is_array($params['support']) ?
-              isset($params['support'][$level]) && $params['support'][$level] :
-              in_array($level, explode(' ', $params['support'])))
-            ) echo 'checked=""';
-            ?>>
-          <?php echo esc(ucfirst($level)) ?>
-        </label>
-      <?php } ?>
     </div>
-    <div style="display:inline-block;width:40px;"></div>
-    <div class="form-group">
-      <label for="sort">Order by</label>
-      <select id="sort" name="sort" class="form-control">
-        <?php if(!isset($params['sort'])) $params['sort'] = 'updated'; foreach(['rating', 'cost', 'name', 'updated'] as $id => $order) { ?>
-          <option value="<?php echo esc($order) ?>" <?php if(isset($params['sort']) && $order == $params['sort']) echo 'selected=""'; ?>>
-            <?php echo esc(ucfirst($order)) ?>
-          </option>
-        <?php } ?>
-      </select>
-      <label>
-        <input type="checkbox" name="reverse" <?php if(isset($params['reverse'])) echo 'checked=""'; ?>>
-        Reverse
-      </label>
+    <div class="input-group">
+        <input type="text" class="form-control" name="filter" placeholder="Search for..." value="<?php if(isset($params['filter'])) echo esc($params['filter']) ?>">
+        <span class="input-group-btn">
+            <button class="btn btn-default" type="submit">Search</button>
+        </span>
     </div>
-    <?php if(isset($params['user'])) { ?>
-      <div style="display:inline-block;width:40px;"></div>
-      <div class="form-group bg-primary" style="padding:0 5px;">
-        <label>
-          <input type="checkbox" name="user" value="<?php echo esc($params['user']) ?>" checked="">
-          Only by <?php echo esc($params['user']) ?>
-        </label>
-      </div>
-    <?php } ?>
-  </div>
-  <div class="input-group">
-    <input type="text" class="form-control" name="filter" placeholder="Search for..." value="<?php if(isset($params['filter'])) echo esc($params['filter']) ?>">
-    <span class="input-group-btn">
-      <button class="btn btn-default" type="submit">Search</button>
-    </span>
-  </div>
 </form>
 <br/>
 <div class="row">
-  <?php foreach($data['result'] as $i => $asset) { ?>
-    <div class="col-md-6" style="height:90px;">
-      <div class="media">
-        <div class="media-left">
-          <a href="<?php echo raw($basepath) . '/asset/' . url($asset['asset_id']) ?>" class="img-thumbnail">
-            <img class="media-object" src="<?php echo esc($asset['icon_url']) ?>" alt="<?php echo esc($asset['title']) ?>'s icon" width=80 height=80>
-          </a>
-        </div>
-        <div class="media-body">
-          <h4 class="media-heading">
-            <a href="<?php echo raw($basepath) . '/asset/' . url($asset['asset_id']) ?>"><?php echo esc($asset['title']) ?></a>
-            <small><?php echo esc($asset['version_string']) ?></small>
-            <?php for ($star=1; $star <= 5; $star++) { ?>
-              <i class="glyphicon glyphicon-star<?php if($asset['rating'] < $star) echo '-empty'; ?>"></i>
-            <?php } ?>
-            <span class="label label-primary"><?php echo esc($asset['category']) ?></span>
-            <span class="label label-<?php echo raw([
-              'official' => 'success',
-              'community' => 'info',
-              'testing' => 'default',
-            ][$asset['support_level']]) ?>"><?php echo esc(ucfirst($asset['support_level'])) ?></span>
-          </h4>
+    <?php foreach($data['result'] as $i => $asset) { ?>
+        <div class="col-md-6" style="height:90px;">
+            <div class="media">
+                <div class="media-left">
+                    <a href="<?php echo raw($basepath) . '/asset/' . url($asset['asset_id']) ?>" class="img-thumbnail">
+                        <img class="media-object" src="<?php echo esc($asset['icon_url']) ?>" alt="<?php echo esc($asset['title']) ?>'s icon" width=80 height=80>
+                    </a>
+                </div>
+                <div class="media-body">
+                    <h4 class="media-heading">
+                        <a href="<?php echo raw($basepath) . '/asset/' . url($asset['asset_id']) ?>"><?php echo esc($asset['title']) ?></a>
+                        <small><?php echo esc($asset['version_string']) ?></small>
+                        <?php for ($star=1; $star <= 5; $star++) { ?>
+                            <i class="glyphicon glyphicon-star<?php if($asset['rating'] < $star) echo '-empty'; ?>"></i>
+                        <?php } ?>
+                        <span class="label label-primary"><?php echo esc($asset['category']) ?></span>
+                        <span class="label label-<?php echo raw([
+                            'official' => 'success',
+                            'community' => 'info',
+                            'testing' => 'default',
+                        ][$asset['support_level']]) ?>"><?php echo esc(ucfirst($asset['support_level'])) ?></span>
+                    </h4>
 
-          <p>Submitted by user <?php echo esc($asset['author']) ?>; <?php echo esc($asset['cost']) ?></p>
+                    <p>Submitted by user <?php echo esc($asset['author']) ?>; <?php echo esc($asset['cost']) ?></p>
+                </div>
+            </div>
         </div>
-      </div>
-    </div>
-  <?php } ?>
+    <?php } ?>
 </div>
 <?php include("_pagination.phtml") ?>
 <a href="<?php echo raw($basepath) . '/asset/edit?' . raw($query) . '&asset=-1' ?>" class="btn btn-warning"><i class="glyphicon glyphicon-hourglass"></i> View Pending</a>

+ 13 - 13
templates/change_password.phtml

@@ -2,21 +2,21 @@
 
 
 <?php if(isset($data['error'])) { ?>
-  <div class="alert alert-danger" role="alert"><b>Error: </b> <?php echo esc($data['error']) ?></div>
+    <div class="alert alert-danger" role="alert"><b>Error: </b> <?php echo esc($data['error']) ?></div>
 <?php } ?>
 
 <form action="<?php echo raw($basepath) ?>/change_password" method="post">
-  <?php include("_csrf.phtml") ?>
-  <div class="form-group">
-    <label for="new_password">Old password:</label>
-    <input type="password" name="old_password" class="form-control" id="old_password" placeholder="Current password">
-  </div>
-  <div class="form-group">
-    <label for="new_password">New password:</label>
-    <input type="password" name="new_password" class="form-control" id="new_password" placeholder="Password">
-  </div>
-  <div class="btn-group">
-    <button type="submit" class="btn btn-primary">Change password and logout</button>
-  </div>
+    <?php include("_csrf.phtml") ?>
+    <div class="form-group">
+        <label for="new_password">Old password:</label>
+        <input type="password" name="old_password" class="form-control" id="old_password" placeholder="Current password">
+    </div>
+    <div class="form-group">
+        <label for="new_password">New password:</label>
+        <input type="password" name="new_password" class="form-control" id="new_password" placeholder="Password">
+    </div>
+    <div class="btn-group">
+        <button type="submit" class="btn btn-primary">Change password and logout</button>
+    </div>
 </form>
 <?php include("_footer.phtml") ?>

+ 20 - 20
templates/edit_asset.phtml

@@ -1,28 +1,28 @@
 <?php include("_header.phtml") ?>
 <?php $_asset_values = $data ?>
 <form class="form-horizontal" action="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>" method="post">
-		<?php include("_csrf.phtml") ?>
-		<fieldset>
-				<!-- Form Name -->
-				<legend>
-					Edit Asset
-					<a class="btn btn-default btn-sm" href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>">
-						Back
-					</a>
-				</legend>
+        <?php include("_csrf.phtml") ?>
+        <fieldset>
+                <!-- Form Name -->
+                <legend>
+                    Edit Asset
+                    <a class="btn btn-default btn-sm" href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>">
+                        Back
+                    </a>
+                </legend>
 
-				<?php include("_asset_fields.phtml") ?>
+                <?php include("_asset_fields.phtml") ?>
 
-				<div class="form-group">
-						<label class="col-md-4 control-label" for="submit"></label>
-						<div class="col-md-4">
-								<button id="submit" class="btn btn-primary">Submit edit</button>
-								<a class="btn btn-default" href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>">
-									Cancel
-								</a>
-						</div>
-				</div>
+                <div class="form-group">
+                        <label class="col-md-4 control-label" for="submit"></label>
+                        <div class="col-md-4">
+                                <button id="submit" class="btn btn-primary">Submit edit</button>
+                                <a class="btn btn-default" href="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>">
+                                    Cancel
+                                </a>
+                        </div>
+                </div>
 
-		</fieldset>
+        </fieldset>
 </form>
 <?php include("_footer.phtml") ?>

+ 27 - 27
templates/edit_asset_edit.phtml

@@ -1,41 +1,41 @@
 <?php include("_header.phtml") ?>
 <?php if(isset($data['original'])) {
-	$_asset_values = array_merge($data['original'], array_filter($data, function($value){return $value !== null;}));
+    $_asset_values = array_merge($data['original'], array_filter($data, function($value){return $value !== null;}));
 } else {
-	$_asset_values = $data;
+    $_asset_values = $data;
 } ?>
 
 <?php if(isset($data['warning'])) { ?>
-  <div class="alert alert-warning" role="alert">
-    <strong>Warning:</strong> <?php echo nl2br(esc($data['warning'])) ?>
-    <br><br>
-    <em>If you think that this warning should not be here, you can always <a href="https://github.com/godotengine/asset-library/issues">open an issue</a>.</em>
-  </div>
+    <div class="alert alert-warning" role="alert">
+        <strong>Warning:</strong> <?php echo nl2br(esc($data['warning'])) ?>
+        <br><br>
+        <em>If you think that this warning should not be here, you can always <a href="https://github.com/godotengine/asset-library/issues">open an issue</a>.</em>
+    </div>
 <?php } ?>
 
 <form class="form-horizontal" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>" method="post">
-	<?php include("_csrf.phtml") ?>
-		<fieldset>
-				<!-- Form Name -->
-				<legend>
-					Change edit
-					<a class="btn btn-default btn-sm" href="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>">
-						Back
-					</a>
-				</legend>
+    <?php include("_csrf.phtml") ?>
+        <fieldset>
+                <!-- Form Name -->
+                <legend>
+                    Change edit
+                    <a class="btn btn-default btn-sm" href="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>">
+                        Back
+                    </a>
+                </legend>
 
-				<?php include("_asset_fields.phtml") ?>
+                <?php include("_asset_fields.phtml") ?>
 
-				<div class="form-group">
-						<label class="col-md-4 control-label" for="submit"></label>
-						<div class="col-md-4">
-								<button id="submit" class="btn btn-primary">Submit changed edit</button>
-								<a class="btn btn-default" href="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>">
-									Cancel
-								</a>
-						</div>
-				</div>
+                <div class="form-group">
+                        <label class="col-md-4 control-label" for="submit"></label>
+                        <div class="col-md-4">
+                                <button id="submit" class="btn btn-primary">Submit changed edit</button>
+                                <a class="btn btn-default" href="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>">
+                                    Cancel
+                                </a>
+                        </div>
+                </div>
 
-		</fieldset>
+        </fieldset>
 </form>
 <?php include("_footer.phtml") ?>

+ 1 - 1
templates/error.phtml

@@ -1,5 +1,5 @@
 <?php include("_header.phtml") ?>
 <div class="alert alert-danger">
-  <strong>Error:</strong> <?php echo esc($data['error']) ?>
+    <strong>Error:</strong> <?php echo esc($data['error']) ?>
 </div>
 <?php include("_footer.phtml") ?>

+ 19 - 19
templates/feed.phtml

@@ -1,25 +1,25 @@
 <?php include("_header.phtml") ?>
 <?php foreach($data['events'] as $i => $event) { ?>
-  <div class="media"> <!-- TODO: Get real feed from @alketii -->
-    <div class="media-left">
+    <div class="media"> <!-- TODO: Get real feed from @alketii -->
+        <div class="media-left">
 
-      <i class="glyphicon glyphicon-<?php echo raw([
-        'new' => 'unchecked text-default',
-        'in_review' => 'check text-primary',
-        'rejected' => 'remove text-danger',
-        'accepted' => 'ok text-success'][$event['status']])
-      ?>" style="font-size:30px"></i>
+            <i class="glyphicon glyphicon-<?php echo raw([
+                'new' => 'unchecked text-default',
+                'in_review' => 'check text-primary',
+                'rejected' => 'remove text-danger',
+                'accepted' => 'ok text-success'][$event['status']])
+            ?>" style="font-size:30px"></i>
+        </div>
+        <div class="media-body">
+            <h4 class="media-heading">
+                <span><?php echo ($event['asset_id'] == -1 ? 'Create ' : 'Edit ') ?></span>
+                <a href="<?php echo raw($basepath) . '/asset/edit/' . url($event['edit_id']) ?>">"<?php echo esc($event['title']) ?>"</a>
+                <span class="label label-<?php
+                echo raw(['new' => 'info', 'in_review' => 'primary', 'rejected' => 'danger', 'accepted' => 'success'][$event['status']])
+                ?>"><?php echo raw(ucfirst(str_replace('_', ' ', $event['status']))) ?></span>
+            </h4>
+            <?php if($event['reason']) echo 'Reason: ' . esc($event['reason']) ?>
+        </div>
     </div>
-    <div class="media-body">
-      <h4 class="media-heading">
-        <span><?php echo ($event['asset_id'] == -1 ? 'Create ' : 'Edit ') ?></span>
-        <a href="<?php echo raw($basepath) . '/asset/edit/' . url($event['edit_id']) ?>">"<?php echo esc($event['title']) ?>"</a>
-        <span class="label label-<?php
-        echo raw(['new' => 'info', 'in_review' => 'primary', 'rejected' => 'danger', 'accepted' => 'success'][$event['status']])
-        ?>"><?php echo raw(ucfirst(str_replace('_', ' ', $event['status']))) ?></span>
-      </h4>
-      <?php if($event['reason']) echo 'Reason: ' . esc($event['reason']) ?>
-    </div>
-  </div>
 <?php } ?>
 <?php include("_footer.phtml") ?>

+ 9 - 9
templates/forgot_password.phtml

@@ -1,17 +1,17 @@
 <?php include("_header.phtml") ?>
 
 <?php if(isset($user)) { ?>
-  <div class="alert alert-info" role="alert">You are already logged in as <?php echo esc($user['username']) ?></div>
+    <div class="alert alert-info" role="alert">You are already logged in as <?php echo esc($user['username']) ?></div>
 <?php } ?>
 
 <form action="<?php echo raw($basepath) ?>/forgot_password" method="post">
-  <?php include("_csrf.phtml") ?>
-  <div class="form-group">
-    <label for="login-form-email">Email</label>
-    <input type="text" name="email" class="form-control" id="login-form-email" placeholder="Email">
-  </div>
-  <div class="btn-group">
-    <button type="submit" class="btn btn-primary">Send reset link</button>
-  </div>
+    <?php include("_csrf.phtml") ?>
+    <div class="form-group">
+        <label for="login-form-email">Email</label>
+        <input type="text" name="email" class="form-control" id="login-form-email" placeholder="Email">
+    </div>
+    <div class="btn-group">
+        <button type="submit" class="btn btn-primary">Send reset link</button>
+    </div>
 </form>
 <?php include("_footer.phtml") ?>

+ 3 - 3
templates/index.html

@@ -14,9 +14,9 @@
     <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
     <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
     <!--[if lt IE 9]>
-			<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
-			<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
-		<![endif]-->
+        <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+    <![endif]-->
 </head>
 
 <body>

+ 20 - 20
templates/login.phtml

@@ -1,34 +1,34 @@
 <?php include("_header.phtml") ?>
 
 <?php if(isset($user)): ?>
-  <div class="alert alert-info" role="alert">You are already logged in as <?php echo esc($user['username']) ?></div>
+    <div class="alert alert-info" role="alert">You are already logged in as <?php echo esc($user['username']) ?></div>
 <?php endif ?>
 
 <?php if(isset($reset_user)): ?>
-  <div class="alert alert-info" role="alert">
-    You are currently resetting the password for <?php echo esc($reset_user['username']) ?>.
-    <a href="<?php echo raw($basepath) ?>/reset_password">Continue</a>
-  </div>
+    <div class="alert alert-info" role="alert">
+        You are currently resetting the password for <?php echo esc($reset_user['username']) ?>.
+        <a href="<?php echo raw($basepath) ?>/reset_password">Continue</a>
+    </div>
 <?php endif ?>
 
 <?php if(isset($data['error'])): ?>
-  <div class="alert alert-danger" role="alert"><b>Error: </b> <?php echo esc($data['error']) ?></div>
+    <div class="alert alert-danger" role="alert"><b>Error: </b> <?php echo esc($data['error']) ?></div>
 <?php endif ?>
 
 <form action="<?php echo raw($basepath) ?>/login" method="post">
-  <?php include("_csrf.phtml") ?>
-  <div class="form-group">
-    <label for="login-form-username">Username</label>
-    <input type="text" name="username" class="form-control" id="login-form-username" placeholder="Username">
-  </div>
-  <div class="form-group">
-    <label for="login-form-password">Password</label>
-    <input type="password" name="password" class="form-control" id="login-form-password" placeholder="Password">
-  </div>
-  <div class="btn-group">
-    <button type="submit" class="btn btn-primary">Login</button>
-    <a href="<?php echo raw($basepath) ?>/register" class="btn btn-default">Register</a>
-    <a href="<?php echo raw($basepath) ?>/forgot_password" class="btn btn-link">Forgot password</a>
-  </div>
+    <?php include("_csrf.phtml") ?>
+    <div class="form-group">
+        <label for="login-form-username">Username</label>
+        <input type="text" name="username" class="form-control" id="login-form-username" placeholder="Username">
+    </div>
+    <div class="form-group">
+        <label for="login-form-password">Password</label>
+        <input type="password" name="password" class="form-control" id="login-form-password" placeholder="Password">
+    </div>
+    <div class="btn-group">
+        <button type="submit" class="btn btn-primary">Login</button>
+        <a href="<?php echo raw($basepath) ?>/register" class="btn btn-default">Register</a>
+        <a href="<?php echo raw($basepath) ?>/forgot_password" class="btn btn-link">Forgot password</a>
+    </div>
 </form>
 <?php include("_footer.phtml") ?>

+ 19 - 19
templates/register.phtml

@@ -1,30 +1,30 @@
 <?php include("_header.phtml") ?>
 
 <?php if(isset($user)): ?>
-  <div class="alert alert-info" role="alert">Your are already logged in as <?php echo esc($user['username']) ?></div>
+    <div class="alert alert-info" role="alert">Your are already logged in as <?php echo esc($user['username']) ?></div>
 <?php endif ?>
 
 <?php if(isset($data['error'])): ?>
-  <div class="alert alert-danger" role="alert"><b>Error: </b> <?php echo esc($data['error']) ?></div>
+    <div class="alert alert-danger" role="alert"><b>Error: </b> <?php echo esc($data['error']) ?></div>
 <?php endif ?>
 
 <form action="<?php echo raw($basepath) ?>/register" method="post">
-  <?php include("_csrf.phtml") ?>
-  <div class="form-group">
-    <label for="login-form-username">Username</label>
-    <input type="text" name="username" class="form-control" id="login-form-username" placeholder="Username">
-  </div>
-  <div class="form-group">
-    <label for="login-form-email">Email</label>
-    <input type="email" name="email" class="form-control" id="login-form-email" placeholder="Email">
-  </div>
-  <div class="form-group">
-    <label for="login-form-password">Password</label>
-    <input type="password" name="password" class="form-control" id="login-form-password" placeholder="Password">
-  </div>
-  <div class="btn-group">
-    <button type="submit" class="btn btn-primary">Register</button>
-    <a href="<?php echo raw($basepath) ?>/login" class="btn btn-default">Login</a>
-  </div>
+    <?php include("_csrf.phtml") ?>
+    <div class="form-group">
+        <label for="login-form-username">Username</label>
+        <input type="text" name="username" class="form-control" id="login-form-username" placeholder="Username">
+    </div>
+    <div class="form-group">
+        <label for="login-form-email">Email</label>
+        <input type="email" name="email" class="form-control" id="login-form-email" placeholder="Email">
+    </div>
+    <div class="form-group">
+        <label for="login-form-password">Password</label>
+        <input type="password" name="password" class="form-control" id="login-form-password" placeholder="Password">
+    </div>
+    <div class="btn-group">
+        <button type="submit" class="btn btn-primary">Register</button>
+        <a href="<?php echo raw($basepath) ?>/login" class="btn btn-default">Login</a>
+    </div>
 </form>
 <?php include("_footer.phtml") ?>

+ 8 - 8
templates/reset_password.phtml

@@ -1,13 +1,13 @@
 <?php include("_header.phtml") ?>
 
 <form action="<?php echo raw($basepath) ?>/reset_password" method="post">
-  <?php include("_csrf.phtml") ?>
-  <div class="form-group">
-    <label for="new_password">New password for <?php if(isset($reset_user)) echo $reset_user['username'] ?></label>
-    <input type="password" name="password" class="form-control" id="new_password" placeholder="Password">
-  </div>
-  <div class="btn-group">
-    <button type="submit" class="btn btn-primary">Change password</button>
-  </div>
+    <?php include("_csrf.phtml") ?>
+    <div class="form-group">
+        <label for="new_password">New password for <?php if(isset($reset_user)) echo $reset_user['username'] ?></label>
+        <input type="password" name="password" class="form-control" id="new_password" placeholder="Password">
+    </div>
+    <div class="btn-group">
+        <button type="submit" class="btn btn-primary">Change password</button>
+    </div>
 </form>
 <?php include("_footer.phtml") ?>

+ 19 - 19
templates/reset_password_email.phtml

@@ -1,21 +1,21 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-    <title>Reset password for <?php echo $user['username'] ?> on Godot asset library</title>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-  </head>
-  <body>
-    <h1>Password reset requested for Godot asset library</h1>
-    <p>
-      If you haven't requested the password reset you can disregard this email.
-    </p>
-    <p>
-      If you aren't <?php echo htmlspecialchars($user['username']) ?>, you should disregard this email completely (or try to get in touch with the real <?php echo $user['username'] ?>, and forward it to him).
-    </p>
-    <p>
-      <a href="<?php echo htmlspecialchars($link) ?>">Click this link to reset your password.</a>
-      (In case it isn't working, you can type/copy this url manually: <a href="<?php echo htmlspecialchars($link) ?>"><?php echo htmlspecialchars($link) ?></a>)
-    </p>
-  </body>
-</html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+        <title>Reset password for <?php echo $user['username'] ?> on Godot asset library</title>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+    </head>
+    <body>
+        <h1>Password reset requested for Godot asset library</h1>
+        <p>
+            If you haven't requested the password reset you can disregard this email.
+        </p>
+        <p>
+            If you aren't <?php echo htmlspecialchars($user['username']) ?>, you should disregard this email completely (or try to get in touch with the real <?php echo $user['username'] ?>, and forward it to him).
+        </p>
+        <p>
+            <a href="<?php echo htmlspecialchars($link) ?>">Click this link to reset your password.</a>
+            (In case it isn't working, you can type/copy this url manually: <a href="<?php echo htmlspecialchars($link) ?>"><?php echo htmlspecialchars($link) ?></a>)
+        </p>
+    </body>
+</html>

+ 12 - 12
templates/submit_asset.phtml

@@ -1,20 +1,20 @@
 <?php include("_header.phtml") ?>
 <form class="form-horizontal" action="<?php echo raw($basepath) ?>/asset" method="post">
-	<?php include("_csrf.phtml") ?>
-		<fieldset>
+    <?php include("_csrf.phtml") ?>
+        <fieldset>
 
-				<!-- Form Name -->
-				<legend>Submit Asset</legend>
+                <!-- Form Name -->
+                <legend>Submit Asset</legend>
 
-				<?php include("_asset_fields.phtml") ?>
+                <?php include("_asset_fields.phtml") ?>
 
-				<div class="form-group">
-						<label class="col-md-4 control-label" for="submit"></label>
-						<div class="col-md-4">
-								<button id="submit" class="btn btn-primary">Submit</button>
-						</div>
-				</div>
+                <div class="form-group">
+                        <label class="col-md-4 control-label" for="submit"></label>
+                        <div class="col-md-4">
+                                <button id="submit" class="btn btn-primary">Submit</button>
+                        </div>
+                </div>
 
-		</fieldset>
+        </fieldset>
 </form>
 <?php include("_footer.phtml") ?>