PHP 8.2.30
Preview: api-controller.js Size: 10.05 KB
//proc/thread-self/root/home/byroehnu/.trash/node_modules11/adminjs/lib/backend/controllers/api-controller.js

/* eslint-disable max-len */
/* eslint no-unused-vars: 0 */
import populator from '../utils/populator/populator.js';
import ViewHelpers from '../utils/view-helpers/view-helpers.js';
import ConfigurationError from '../utils/errors/configuration-error.js';
import NotFoundError from '../utils/errors/not-found-error.js';
import ForbiddenError from '../utils/errors/forbidden-error.js';
import { requestParser } from '../utils/request-parser/index.js';
import actionErrorHandler from '../services/action-error-handler/action-error-handler.js';
import { validateParam } from '../../utils/param-converter/validate-param.js';
/**
 * Controller responsible for the auto-generated API: `/admin_root/api/...`, where
 * _admin_root_ is the `rootPath` given in {@link AdminJSOptions}.
 *
 * The best way to utilise it is to use {@link ApiClient} on the frontend.
 *
 * ### Available API endpoints
 *
 * <div class='table-container'>
 *
 * | Endpoint                 | Method                | Description |
 * |--------------------------|-----------------------|-------------|
 * | .../api/resources/{resourceId}/actions/{action} | {@link ApiController#resourceAction} | Perform customized resource action |
 * | .../api/resources/{resourceId}/records/{recordId}/{action} | {@link ApiController#recordAction} | Perform customized record action |
 * | .../api/resources/{resourceId}/bulk/{action}?recordIds={recordIds} | {@link ApiController#bulkAction} | Perform customized bulk action |
 * | .../api/pages/{pageName}_ | {@link ApiController#page} | Perform customized page action |
 * | .../api/dashboard_ | {@link ApiController#dashboard} | Perform customized dashboard action |
 *
 * </div>
 *
 * ### Responsibility
 *
 * In general this controllers takes handler functions you define in {@link AdminJSOptions} and:
 * - find all the [context information]{@link ActionContext} which is needed by the action
 *   and is passed to the {@link Action#handler}, {@link Action#before} and {@link Action#after}
 * - checks if action can be invoked by particular user {@link Action#isAccessible}
 * - invokes {@link Action#before} and {@link Action#after} hooks
 *
 * You probably don't want to modify it, but you can call its methods by using {@link ApiClient}
 *
 * @hideconstructor
 */
class ApiController {
  /**
   * @param {Object} options
   * @param {AdminJSOptions} options.admin
   * @param {CurrentAdmin} [currentAdmin]
   */
  constructor({
    admin
  }, currentAdmin) {
    this._admin = admin;
    this.currentAdmin = currentAdmin;
  }

  /**
   * Returns context for given action
   * @private
   *
   * @param   {ActionRequest}  request  request object
   * @return  {Promise<ActionContext>} action context
   */
  async getActionContext(request) {
    const {
      resourceId,
      action: actionName
    } = request.params;
    const h = new ViewHelpers(this._admin);
    const resource = this._admin.findResource(resourceId);
    const action = resource.decorate().actions[actionName];
    return {
      resource,
      action,
      h,
      currentAdmin: this.currentAdmin,
      _admin: this._admin
    };
  }

  /**
   * Search records by query string.
   *
   * Handler function responsible for a _.../api/resources/{resourceId}/search/{query}_ route
   *
   * @param   {ActionRequest}  request with __params.query__ set
   * @param   {any}            response
   *
   * @return  {Promise<SearchActionResponse>}    found records
   */
  async search(request, response) {
    request.params.action = 'search';
    // eslint-disable-next-line no-console
    console.log(['Using ApiController#search is deprecated in favour of resourceAction', 'It will be removed in the next version'].join('\n'));
    return this.resourceAction(request, response);
  }

  /**
   * Performs a customized {@link Action resource action}.
   * To call it use {@link ApiClient#resourceAction} method.
   *
   * Handler function responsible for a _.../api/resources/{resourceId}/actions/{action}_
   *
   * @param   {ActionRequest}  originalRequest
   * @param   {any}            response object from the plugin (i.e. adminjs-expressjs)
   *
   * @return  {Promise<ActionResponse>}  action response
   */
  async resourceAction(originalRequest, response) {
    const actionContext = await this.getActionContext(originalRequest);
    const request = requestParser(originalRequest, actionContext.resource);
    return actionContext.action.handler(request, response, actionContext);
  }

  /**
   * Performs a customized {@link Action record action}.
   * To call it use {@link ApiClient#recordAction} method.
   *
   * Handler function responsible for a _.../api/resources/{resourceId}/records/{recordId}/{action}_
   *
   * @param   {ActionRequest}  originalRequest
   * @param   {any}  response
   *
   * @return  {Promise<RecordActionResponse>}  action response
   * @throws  ConfigurationError      When given record action doesn't return {@link RecordJSON}
   * @throws  ConfigurationError      when action handler doesn't return Promise<{@link RecordActionResponse}>
   */
  async recordAction(originalRequest, response) {
    const {
      recordId,
      resourceId
    } = originalRequest.params;
    const actionContext = await this.getActionContext(originalRequest);
    const request = requestParser(originalRequest, actionContext.resource);
    if (!recordId) {
      throw new NotFoundError(['You have to pass recordId to the recordAction'].join('\n'), 'Action#handler');
    }
    const idProperty = Object.values(actionContext.resource.decorate()?.properties).find(p => p.isId());
    if (!idProperty || !validateParam(recordId, idProperty)) {
      const invalidRecordError = actionErrorHandler(new ForbiddenError(['You have to pass a valid recordId to the recordAction'].join('\n')), actionContext);
      return invalidRecordError;
    }
    let record = await actionContext.resource.findOne(recordId, actionContext);
    if (!record) {
      const missingRecordError = actionErrorHandler(new NotFoundError([`Record with given id: "${recordId}" cannot be found in resource "${resourceId}"`].join('\n'), 'Action#handler'), actionContext);
      return missingRecordError;
    }
    [record] = await populator([record], actionContext);
    actionContext.record = record;
    const jsonWithRecord = await actionContext.action.handler(request, response, actionContext);
    const isValidRecord = !!(jsonWithRecord && jsonWithRecord.record && jsonWithRecord.record.recordActions);
    const anErrorWasHandled = jsonWithRecord && jsonWithRecord.notice && jsonWithRecord.notice.type === 'error';
    if (isValidRecord || anErrorWasHandled) {
      return jsonWithRecord;
    }
    throw new ConfigurationError('handler of a recordAction should return a RecordJSON object', 'Action#handler');
  }

  /**
   * Performs a customized {@link Action bulk action}.
   * To call it use {@link ApiClient#bulkAction} method.
   *
   * Handler function responsible for a _.../api/resources/{resourceId}/bulk/{action}?recordIds={recordIds}_
   *
   * @param   {ActionRequest}  request
   * @param   {any}  response
   *
   * @return  {Promise<BulkActionResponse>}  action response
   * @throws  NotFoundError           when recordIds are missing in query or they don't exists in
   *                                  the database
   * @throws  ConfigurationError      when action handler doesn't return Promise<{@link BulkActionResponse}>
   */
  async bulkAction(originalRequest, response) {
    const {
      resourceId
    } = originalRequest.params;
    const {
      recordIds
    } = originalRequest.query || {};
    const actionContext = await this.getActionContext(originalRequest);
    const request = requestParser(originalRequest, actionContext.resource);
    if (!recordIds) {
      throw new NotFoundError(['You have to pass "recordIds" to the bulkAction via search params: ?recordIds=...'].join('\n'), 'Action#handler');
    }
    let records = await actionContext.resource.findMany(recordIds.split(','), actionContext);
    if (!records || !records.length) {
      throw new NotFoundError([`record with given id: "${recordIds}" cannot be found in resource "${resourceId}"`].join('\n'), 'Action#handler');
    }
    records = await populator(records, actionContext);
    const jsonWithRecord = await actionContext.action.handler(request, response, {
      ...actionContext,
      records
    });
    if (jsonWithRecord && jsonWithRecord.records) {
      return jsonWithRecord;
    }
    throw new ConfigurationError('handler of a bulkAction should return an Array of RecordJSON object', 'Action#handler');
  }

  /**
   * Gets optional data needed by the dashboard.
   * To call it use {@link ApiClient#getDashboard} method.
   *
   * Handler function responsible for a _.../api/dashboard_
   *
   * @param   {ActionRequest}  request
   * @param   {any}  response
   *
   * @return  {Promise<any>}  action response
   */
  async dashboard(request, response) {
    const h = new ViewHelpers(this._admin);
    const handler = this._admin.options.dashboard && this._admin.options.dashboard.handler;
    if (handler) {
      return handler(request, response, {
        h,
        currentAdmin: this.currentAdmin,
        _admin: this._admin
      });
    }
    return {
      message: ['You can override this method by setting up dashboard.handler', 'function in AdminJS options'].join('\n')
    };
  }

  /**
   * Gets optional data needed by the page.
   * To call it use {@link ApiClient#getPage} method.
   *
   * Handler function responsible for a _.../api/pages/{pageName}_
   *
   * @param   {ActionRequest}  request
   * @param   {any}  response
   *
   * @return  {Promise<any>}  action response
   */
  async page(request, response) {
    const h = new ViewHelpers(this._admin);
    const {
      pages = {}
    } = this._admin.options;
    const {
      pageName
    } = request.params;
    const {
      handler
    } = pages[pageName] || {};
    if (handler) {
      return handler(request, response, {
        h,
        currentAdmin: this.currentAdmin,
        _admin: this._admin
      });
    }
    return {
      message: ['You can override this method by setting up pages[pageName].handler', 'function in AdminJS options'].join('\n')
    };
  }
}
export default ApiController;

Directory Contents

Dirs: 0 × Files: 4

Name Size Perms Modified Actions
10.05 KB lrw-r--r-- 2026-02-28 00:29:24
Edit Download
3.53 KB lrw-r--r-- 2026-02-28 00:29:28
Edit Download
2.60 KB lrw-r--r-- 2026-02-28 00:31:14
Edit Download
127 B lrw-r--r-- 2026-02-28 00:31:40
Edit Download

If ZipArchive is unavailable, a .tar will be created (no compression).