...

4.4. Серверные сценарии

Тема в разделе "Руководство по настройке форм и сценариев", создана пользователем ELMA365, 24 авг 2023.

  1. ELMA365

    ELMA365 Moderator

    Серверные сценарии

    Как говорилось выше, использование серверных сценариев — это чаще всего затратная операция. Но есть случаи, когда без использования серверных сценариев задачу выполнить невозможно. Разберём самые популярные случаи.

    Получение настроек модулей
    В системе ELMA365 для получения настроек модуля можно использовать только серверные сценарии. Такое ограничение определено подходом к безопасности хранения данных, так как в настройках часто используются ключи и токены для доступа к сторонним системам.

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

    [​IMG]

    Пример виджета для прослушивания файлов формата .mp3, который создан внутри модуля предпросмотра:

    Спойлер: Контекст
    [​IMG]

    Спойлер: Виджет «Код»
    Код:
    
    <% if (Context.data.link) { %>
        <
    audio controls src="<%= Context.data.link%>">
            
    Ваш браузер не поддерживает встроенное аудиоПопробуйте скачать его
            
    <a href="<%= Context.data.link%>" download>по ссылке</a>.
        </
    audio>
    <% } %>

    Спойлер: Сценарий (Клиент)
    Код:
    
    /** Загрузка виджета */
    async function onInit() {
        if (
    Context.data.extension![0] !== 'mp3') {
            return;
        }
        if (!
    await Allow()) {
            return;
        }
        const 
    file_link await Context.data.file?.getDownloadUrl();
        if (!
    file_link) {
            return;
        }
        
    Context.data.link file_link;
    }
    /** Проверить, разрешено ли данное расширение */
    async function Allow(): Promise<boolean> {
        if (
    typeof Context.data.allow === 'undefined') {
            
    await LoadSettings();
        }
        return 
    Context.data.allow!;
    }
    async function LoadSettings(): Promise<void> {
        
    Context.data.allow false;
        
    await Server.rpc.LoadSettings();
    }
    /** Загрузить настройки модуля */
    async function LoadSettings(): Promise<void> {
        const 
    extension = Namespace.params.data.extensions.find(ext => ext.extension === 'mp3');
        
    Context.data.allow extension?.allow;
    }

    Данный подход можно улучшить, сохранив результат получения настроек в кэш. Подробный пример описан в статье «Работа с настройками модуля» в ELMA365 Community.

    Обход CORS
    Вторая причина для использования серверных сценариев — обход запрета с кроссдоменными запросами (CORS). Браузер защищает пользователя, отслеживая запросы, которые выполняются на сайте. Если вы зашли на домен my-elma.com, а запросы уходят на домен other-site.com, то браузер заблокирует такие запросы и выдаст ошибку в консоли.

    При выполнении запроса через серверные сценарии запрос будет выполняться не в браузере, а с сервера, где таких блокировок нет.

    Чтобы адаптировать свой клиентский метод с запросом к внешнему источнику, достаточно просто перенести его в серверную часть. Главное требование — сигнатура метода должна быть следующей:
    Код:
    
    async function MyServerFunc(): Promise<void> {}
    
    
    На клиентской стороне метод можно использовать через следующую конструкцию:
    Код:
    
    await Server.rpc.MyServerFunc();
    
    
    Поиск с повышенными привилегиями
    Мы создали виджет, который находит пересечения по отпускам. Если поиск будет осуществляться на клиенте, то мы получим только свои отпуска и отпуска подчинённых (если вы руководитель). Чтобы иметь возможность получить все отпуска, достаточно перенести метод в серверные сценарии.

    На данный момент клиентский сценарий для поиска отпусков выглядит следующим образом:
    Код:
    
    async function mySearch(): Promise<void> {
      
    Context.data.result await Application.search()
        .
    where(item => item.__deletedAt.eq(null))
        .
    all();
      for(
    let item of   Context.data.result) {
        
    /* обработка списка */
      
    }
    }
    Перенесём получение данных в серверный сценарий, а в клиентском просто выполняем вызов серверного метода.

    Серверный сценарий
    Код:
    
    async function mySearch(): Promise<void> {
      
    Context.data.result await Application.search()
        .
    where(item => item.__deletedAt.eq(null))
        .
    all();
    }
    Клиентский сценарий
    Код:
    
    async function mySearch(): Promise<void> {
      
    await Server.rpc.mySearch();
      for(
    let item of Context.data.result) {
        
    /* обработка списка */
      
    }
    }