基于TypeScript自定义Strapi users-permissions插件接口

Strapi的官方文档提供了扩展插件的方式,例如在src/extensions/users-permissions/strapi-server.ts中自定义,但文档提供的例子直接重写了原有插件的函数,而无法通过类似自定义API调用super.find()等方式调用原有插件的函数。

// 自定义API的方式

const uid: Common.UID.ContentType = 'api::api-name···';
export default factories.createCoreController(uid, ({ strapi: Strapi }) => ({
    async find(ctx: Context) {
        // TODO ...
        return await super.find(ctx);
    },
}));

此时需要将原插件的函数复制出来,并在重写的函数里调用,以自定义/users/me接口为例。

users-permissions的/users/me接口提供了对获得当前用户信息的方法,若需要自定义获得哪些信息,可通过修改原有me函数实现,users-permissions对me函数的定义位于@strapi/plugin-users-permissions/server/controllers/user.js中,尝试通过导入这个函数,并在自定义的me函数中调用这个函数。

失败的方案

进一步观察代码,该me函数位于user.js的导出对象中,user.js的导出对象是controllers导出对象的成员,位于@strapi/plugin-users-permissions/server/controllers/index.js中,controllers又是server导出函数的返回值成员,位于@strapi/plugin-users-permissions/server/index.js中,故要访问user.js中的方法,可通过以下方式。

const { controllers } = server();
controllers.user.me(ctx);

导入原有me函数时,要注意users-permissions插件的导出对象名,查看/@strapi/plugin-users-permissions/package.json发现,其exports对象导出名为strapi-server,故实际引用users-permissions的server对象,需要使用

import server from '@strapi/plugin-users-permissions/strapi-server';

此时,如果在重写的me函数中直接调用controllers.user.me(ctx);则会陷入死递归,因为Strapi初始化时已经将原有的me函数覆盖为自定义的me函数,实际上调用controllers.user.me(ctx);即调用的当前函数,故该方法无法实现。

可行的方案

既然如此,就把整个原有的me函数照搬过来,相当于复制了一份me函数,进入@strapi/plugin-users-permissions/server/controllers/user.js中,发现me函数的定义如下:

/**
   * Retrieve authenticated user.
   * @return {Object|Array}
   */
  async me(ctx) {
    const authUser = ctx.state.user;
    const { query } = ctx;

    if (!authUser) {
      return ctx.unauthorized();
    }

    await validateQuery(query, ctx);
    const sanitizedQuery = await sanitizeQuery(query, ctx);
    const user = await getService('user').fetch(authUser.id, sanitizedQuery);

    ctx.body = await sanitizeOutput(user, ctx);
  },

其调用了validateQuerysanitizeQuerygetServicesanitizeOutput4个方法,其中validateQuerysanitizeQuerysanitizeOutput均在user.js中有定义,可直接照搬

// @strapi/plugin-users-permissions/server/controllers/user.js
const utils = require('@strapi/utils');
const { sanitize, validate } = utils;

const sanitizeOutput = async (user, ctx) => {
  const schema = strapi.getModel('plugin::users-permissions.user');
  const { auth } = ctx.state;

  return sanitize.contentAPI.output(user, schema, { auth });
};

const validateQuery = async (query, ctx) => {
  const schema = strapi.getModel('plugin::users-permissions.user');
  const { auth } = ctx.state;

  return validate.contentAPI.query(query, schema, { auth });
};

const sanitizeQuery = async (query, ctx) => {
  const schema = strapi.getModel('plugin::users-permissions.user');
  const { auth } = ctx.state;

  return sanitize.contentAPI.query(query, schema, { auth });
};

getService位于@strapi/plugin-users-permissions/server/utils/index.js

// @strapi/plugin-users-permissions/server/utils/index.js
const sanitize = require('./sanitize');

const getService = (name) => {
  return strapi.plugin('users-permissions').service(name);
};

module.exports = {
  getService,
  sanitize,
};

观察@strapi/plugin-users-permissions/server/index.js发现,utils并未被server导出,故无法在外部引用该函数

// @strapi/plugin-users-permissions/server/index.js
const register = require('./register');
const bootstrap = require('./bootstrap');
const contentTypes = require('./content-types');
const middlewares = require('./middlewares');
const services = require('./services');
const routes = require('./routes');
const controllers = require('./controllers');
const config = require('./config');

module.exports = () => ({
  register,
  bootstrap,
  config,
  routes,
  controllers,
  contentTypes,
  middlewares,
  services,
});

不过所幸getService仅为一句简单的return strapi.plugin('users-permissions').service(name);并未引用新的外部依赖,故可以在自定义的文件中重新定义一次该函数。

故最终实现代码如下:

// src/extensions/users-permissions/strapi-server.ts

import type { Strapi, Common, CoreApi } from '@strapi/types';
import { sanitize, validate } from '@strapi/utils';

const getService = (name) => {
    return strapi.plugin('users-permissions').service(name);
};
const validateQuery = async (query, ctx) => {
    const schema = strapi.getModel('plugin::users-permissions.user');
    const { auth } = ctx.state;

    return validate.contentAPI.query(query, schema, { auth });
};

const sanitizeQuery = async (query, ctx) => {
    const schema = strapi.getModel('plugin::users-permissions.user');
    const { auth } = ctx.state;

    return sanitize.contentAPI.query(query, schema, { auth });
};

const sanitizeOutput = async (user, ctx) => {
    const schema = strapi.getModel('plugin::users-permissions.user');
    const { auth } = ctx.state;

    return sanitize.contentAPI.output(user, schema, { auth });
};

const originMe = async (ctx) => {
    const authUser = ctx.state.user;
    const { query } = ctx;

    if (!authUser) {
        return ctx.unauthorized();
    }

    await validateQuery(query, ctx);
    const sanitizedQuery = await sanitizeQuery(query, ctx);
    const user = await getService('user').fetch(authUser.id, sanitizedQuery);

    // ctx.body = await sanitizeOutput(user, ctx);
    return await sanitizeOutput(user, ctx);
};

export default async (plugin) => {
    const uid: Common.UID.ContentType = 'plugin::users-permissions.user';
    plugin.controllers.user.me = async (ctx) => {
        // Custom code here;
        const res = await originMe(ctx); // 调用了原有的me函数
        return res;
    };
    return plugin;
};
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值