Главная/Статьи/Битрикс24: автоматическая дисковая квота для новых пользователей

Битрикс24: автоматическая дисковая квота для новых пользователей

Настраиваем автоматическое назначение дисковой квоты при создании пользователя в Битрикс24. Обработчик события onAfterUserAdd.

ДМ
Дмитрий Мещеряков
📅 22 декабря 2024 г.📖 5 мин чтения

Дисковое пространство на портале Битрикс24 заканчивается всегда одинаково: несколько человек годами хранят на диске всё подряд, а расширять тариф приходится всей компании. Квоты решают вопрос на входе — но только если назначаются автоматически, потому что вручную про нового сотрудника вспомнят не всегда.

Задача

При создании нового сотрудника в Битрикс24 автоматически назначать ему дисковую квоту определённого размера. Это позволяет контролировать использование дискового пространства на портале.

Предварительная настройка

Прежде всего активируйте функцию квот в модуле Диск:

  1. Перейдите в Настройки → Настройки модулей → Диск
  2. Включите опцию "Устанавливать квоту для дисков сотрудников"
💡 Совет

Без активации этой опции методы API для работы с квотами не будут работать — причём тихо: вызов отработает без ошибки, а лимит не установится. Проверяйте результат, а не факт выполнения кода.

Реализация

Класс обработчика

Создайте файл /local/php_interface/classes/UserDiskQuotaHandler.php:

php
<?php

namespace Local\Handlers;

use Bitrix\Main\Loader;
use Bitrix\Disk\Driver;

class UserDiskQuotaHandler
{
    /**
     * Размер квоты по умолчанию (в байтах)
     * 100 MB = 100 * 1024 * 1024
     */
    private const DEFAULT_QUOTA_SIZE = 104857600;

    /**
     * Квоты для разных отделов (в байтах)
     */
    private const DEPARTMENT_QUOTAS = [
        1 => 524288000,   // Руководство: 500 MB
        5 => 209715200,   // Разработка: 200 MB
        10 => 104857600,  // Продажи: 100 MB
    ];

    /**
     * Обработчик события создания пользователя
     */
    public static function onAfterUserAdd(array &$fields): void
    {
        if (empty($fields['ID']) || (int)$fields['ID'] <= 0) {
            return;
        }

        $userId = (int)$fields['ID'];
        
        // Определяем размер квоты
        $quotaSize = self::getQuotaForUser($fields);
        
        // Устанавливаем квоту
        self::setDiskQuota($userId, $quotaSize);
        
        // Логируем
        self::logQuotaAssignment($userId, $quotaSize);
    }

    /**
     * Определение квоты на основе отдела пользователя
     */
    private static function getQuotaForUser(array $fields): int
    {
        // Если указаны отделы, проверяем наличие специальной квоты
        if (!empty($fields['UF_DEPARTMENT']) && is_array($fields['UF_DEPARTMENT'])) {
            foreach ($fields['UF_DEPARTMENT'] as $departmentId) {
                if (isset(self::DEPARTMENT_QUOTAS[$departmentId])) {
                    return self::DEPARTMENT_QUOTAS[$departmentId];
                }
            }
        }

        return self::DEFAULT_QUOTA_SIZE;
    }

    /**
     * Установка дисковой квоты
     */
    private static function setDiskQuota(int $userId, int $quotaSize): bool
    {
        if (!Loader::includeModule('disk')) {
            return false;
        }

        try {
            $storage = Driver::getInstance()->getStorageByUserId($userId);
            
            if ($storage) {
                $storage->setSizeLimit($quotaSize);
                return true;
            }
        } catch (\Exception $e) {
            // Логируем ошибку
            AddMessage2Log(
                "Ошибка установки квоты для пользователя {$userId}: " . $e->getMessage(),
                "disk_quota"
            );
        }

        return false;
    }

    /**
     * Логирование назначения квоты
     */
    private static function logQuotaAssignment(int $userId, int $quotaSize): void
    {
        $quotaMb = round($quotaSize / 1024 / 1024, 2);
        
        AddMessage2Log(
            "Пользователю ID={$userId} назначена дисковая квота: {$quotaMb} MB",
            "disk_quota"
        );
    }

    /**
     * Форматирование размера для отображения
     */
    public static function formatSize(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $i = 0;
        
        while ($bytes >= 1024 && $i < count($units) - 1) {
            $bytes /= 1024;
            $i++;
        }
        
        return round($bytes, 2) . ' ' . $units[$i];
    }
}

Регистрация обработчика

В файле /local/php_interface/init.php:

php
<?php

// Автозагрузка классов
spl_autoload_register(function ($class) {
    $prefix = 'Local\\';
    $baseDir = __DIR__ . '/classes/';

    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        return;
    }

    $relativeClass = substr($class, $len);
    $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';

    if (file_exists($file)) {
        require $file;
    }
});

// Регистрация обработчика события
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'main',
    'OnAfterUserAdd',
    ['\\Local\\Handlers\\UserDiskQuotaHandler', 'onAfterUserAdd'],
    false,
    9999  // Высокий приоритет — выполняется после создания диска
);
⚠️ Важно

Важно: Параметр приоритета 9999 критически важен. Он гарантирует, что установка квоты произойдёт после инициализации диска пользователя системой.

Проверка установленной квоты

php
<?php
use Bitrix\Main\Loader;
use Bitrix\Disk\Driver;

Loader::includeModule('disk');

$userId = 123;
$storage = Driver::getInstance()->getStorageByUserId($userId);

if ($storage) {
    $sizeLimit = $storage->getSizeLimit();
    $usedSize = $storage->getUsedSize();
    
    echo "Квота: " . \Local\Handlers\UserDiskQuotaHandler::formatSize($sizeLimit) . "\n";
    echo "Использовано: " . \Local\Handlers\UserDiskQuotaHandler::formatSize($usedSize) . "\n";
    echo "Свободно: " . \Local\Handlers\UserDiskQuotaHandler::formatSize($sizeLimit - $usedSize) . "\n";
}

Массовое назначение квот существующим пользователям

php
<?php
use Bitrix\Main\Loader;
use Bitrix\Main\UserTable;
use Bitrix\Disk\Driver;

Loader::includeModule('disk');
Loader::includeModule('main');

$quotaSize = 100 * 1024 * 1024; // 100 MB

$users = UserTable::getList([
    'filter' => ['ACTIVE' => 'Y'],
    'select' => ['ID'],
]);

while ($user = $users->fetch()) {
    $storage = Driver::getInstance()->getStorageByUserId($user['ID']);
    
    if ($storage && $storage->getSizeLimit() === null) {
        $storage->setSizeLimit($quotaSize);
        echo "Установлена квота для пользователя {$user['ID']}\n";
    }
}
⚠️ Важно

Квота меньше уже занятого объёма — это заблокированный диск. Если сотрудник хранит 12 ГБ, а вы назначаете лимит 10 ГБ, он не сможет загрузить ни одного файла, пока не удалит лишнее. Массовое назначение квоты без проверки текущего занятого объёма превращается в поток обращений в поддержку на следующее утро.

Перед массовым назначением соберите статистику: сколько сотрудников уже превышают планируемый лимит. Если таких единицы — предупредите их лично. Если это половина компании — лимит выбран неверно.

Обратите внимание, что в скрипте выше квота ставится только тем, у кого её нет (getSizeLimit() === null). Это правильное поведение: индивидуально настроенные лимиты не должны затираться массовой операцией.

Итоги

Квота на новых сотрудников — обработчик события, квота на существующих — разовый скрипт. Это две разные задачи, и вторая требует предварительного анализа занятого места.

Проверяйте результат установки, а не факт вызова метода: при выключенной опции модуля код отработает молча.

Не затирайте индивидуальные лимиты. Кому-то по работе действительно нужно больше, и это решение руководителя, а не скрипта.

Предупреждайте до того, как ограничение сработает. Уведомление «занято 90% квоты» решает проблему заранее; сообщение «файл не загружен» в момент срочной работы — нет.

💡 Совет

Квота — инструмент планирования, а не наказания. Прежде чем ограничивать, стоит посмотреть, чем занято место: обычно значительная часть — это старые версии файлов и содержимое корзины, которые чистятся настройками хранения версий без всяких квот и без разговоров с сотрудниками.

🚀

Хотите такое же решение?

Настрою окружение под ваш проект, учту специфику инфраструктуры и обучу команду.

Обсудить проект →
Бесплатная консультация · Ответ в течение дня

Комментарии

Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.