. // }}} namespace Plugin\FileQuota; use App\Core\Cache; use App\Core\DB; use App\Core\Event; use function App\Core\I18n\_m; use App\Core\Modules\Plugin; use App\Util\Common; use App\Util\Exception\ClientException; use App\Util\Exception\ServerException; use EventResult; /** * Check attachment file size quotas * * @package GNUsocial * * @ccategory Attachment * * @author Hugo Sales * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ class FileQuota extends Plugin { public static function version(): string { return '1.0.0'; } /** * Check file size to ensure it respects configured file size * quotas. Handles per file, per user and per user-month quotas. * Throws on quota violations * * @throws ClientException * @throws ServerException */ public function onEnforceUserFileQuota(int $filesize, int $user_id): EventResult { $query = <<<'END' select sum(at.size) as total from attachment at join actor_to_attachment ua with at.id = ua.attachment_id where ua.actor_id = :actor_id and at.size is not null END; $max_user_quota = Common::config('attachments', 'user_quota'); if ($max_user_quota !== false) { // If not disabled $cache_key_user_total = "FileQuota-total-user-{$user_id}"; $user_total = Cache::get($cache_key_user_total, fn () => DB::dql($query, ['actor_id' => $user_id])[0]['total']); Cache::set($cache_key_user_total, $user_total + $filesize); if ($user_total + $filesize > $max_user_quota) { // TRANS: Message given if an upload would exceed user quota. throw new ClientException(_m('A file this large would exceed your user quota of {quota} bytes.', ['quota' => $max_user_quota])); } } $query .= ' AND MONTH(at.modified) = MONTH(CURRENT_DATE())' . ' AND YEAR(at.modified) = YEAR(CURRENT_DATE())'; $monthly_quota = Common::config('attachments', 'monthly_quota'); if ($monthly_quota !== false) { // If not disabled $cache_key_user_monthly = "FileQuota-monthly-user-{$user_id}"; $monthly_total = Cache::get($cache_key_user_monthly, fn () => DB::dql($query, ['actor_id' => $user_id])[0]['total']); Cache::set($cache_key_user_monthly, $monthly_total + $filesize); if ($monthly_total + $filesize > $monthly_quota) { // TRANS: Message given if an upload would exceed user quota. throw new ClientException(_m('A file this large would exceed your monthly quota of {quota} bytes.', ['quota' => $monthly_quota])); } } return Event::next; } /** * Event raised when GNU social polls the plugin for information about it. * Adds this plugin's version information to $versions array * * @param array $versions inherited from parent */ public function onPluginVersion(array &$versions): EventResult { $versions[] = [ 'name' => 'FileQuota', 'version' => $this->version(), 'author' => 'Hugo Sales', 'homepage' => GNUSOCIAL_PROJECT_URL, 'description', // TRANS: Plugin description. => _m('Plugin to manage user quotas.'), ]; return Event::next; } }