Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add plugin transform support #82

Merged
merged 2 commits into from
Apr 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,21 @@ yarn add strapi-plugin-transformer

The plugin configuration is stored in a config file located at `./config/plugins.js`. If this file doesn't exists, you will need to create it.

A sample configuration
### Minimal Configuration


```javascript
module.exports = ({ env }) => ({
// ..
'transformer': {
enabled: true,
config: {}
},
// ..
});
```

### Sample configuration

```javascript
module.exports = ({ env }) => ({
Expand All @@ -61,6 +75,11 @@ module.exports = ({ env }) => ({
'GET':true,
}
}
},
plugins: {
ids: {
'slugify': true,
}
}
}
},
Expand All @@ -83,10 +102,11 @@ module.exports = ({ env }) => ({
| hooks.preResponseTransform | A hook that executes before the Response Transforms are applied | Function | () => {} | No |
| hooks.postResponseTransform | A hook that executes after the Response Transforms are applied | Function | () => {} | No |
| contentTypeFilter | The content types to deny or allow the middleware to be regiestered on. Defaults to allow all content types | Object | N/A | No |
| cotentTypeFilter.mode | The filter mode. Current supported modes are `none`, `allow` or `deny` | String | 'none' | No |
| contentTypeFilter.mode | The filter mode. Current supported modes are `none`, `allow` or `deny` | String | 'none' | No |
| contentTypeFilter.uids | The uids to filter | Object | {} | No |
| denyList.uids[uid] | The uid of the content type to filter | Boolean or Object | false | No |
| denyList.uids[uid].method | The specific method of the uid to filter | Boolean | false | No |
| plugins | The plugins to deny or allow the middleware to be regiestered on. Defaults to deny all plugins | Object | N/A | No |
| plugins.mode | The filter mode. Current supported modes are `none`, `allow` or `deny` | String | 'none' | No |
| plugins.ids | The plugin ids to filter. The plugin id is the name you set in the `plugins.js` file | Object | {} | No |
## Usage

Once the plugin has been installed, configured and enabled any request to the Strapi API will be auto transformed.
Expand Down
4 changes: 4 additions & 0 deletions server/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ module.exports = {
mode: 'none',
uids: {},
},
plugins: {
mode: 'none',
ids: {},
},
}),
validator: (config) => {
pluginConfigSchema.validateSync(config);
Expand Down
4 changes: 4 additions & 0 deletions server/config/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const pluginConfigSchema = yup.object().shape({
mode: yup.string().oneOf(['allow', 'deny', 'none']),
uids: yup.object(),
}),
plugins: yup.object().shape({
mode: yup.string().oneOf(['allow', 'deny', 'none']),
ids: yup.object(),
}),
});

module.exports = {
Expand Down
125 changes: 78 additions & 47 deletions server/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,94 @@ const _ = require('lodash');
const { transform } = require('./middleware/transform');
const { getPluginService } = require('./util/getPluginService');

module.exports = ({ strapi }) => {
function addTransformMiddleware(route) {
// ensure path exists
if (!_.has(route, ['config', 'middlewares'])) {
_.set(route, ['config', 'middlewares'], []);
}

// register route middleware
route.config.middlewares.push((ctx, next) => transform(strapi, ctx, next));
}

function isAllowableAPI({ mode, uid, filterValues }) {
// respect ct uid filter
const filterUID = _.get(filterValues, [uid], false);
if (mode === 'allow' && !filterUID && _.isBoolean(filterUID)) {
return false;
} else if (mode === 'deny' && filterUID && _.isBoolean(filterUID)) {
return false;
}

return true;
}

function isAllowableMethod({ mode, uid, method, filterValues }) {
// respect ct uid method filter
const filterMethod = _.get(filterValues, [uid, method], null);
if (mode === 'allow' && !filterMethod && _.isBoolean(filterMethod)) {
return false;
} else if (mode === 'deny' && filterMethod && _.isBoolean(filterMethod)) {
return false;
}

return true;
}

function register({ strapi }) {
const settings = getPluginService('settingsService').get();
let ctFilterMode = _.get(settings, ['contentTypeFilter', 'mode'], 'none');
let pluginFilterMode = _.get(settings, ['plugins', 'mode'], 'allow');
const ctFilterUIDs = _.get(settings, ['contentTypeFilter', 'uids'], {});
const pluginFilterIDs = _.get(settings, ['plugins', 'ids'], {});
const apiTypes = ['api'];

// default uid list to all apis
if (_.size(ctFilterUIDs) === 0) {
ctFilterMode = 'none';
}

// register transforms on all api routes
const apis = _.get(strapi, ['api'], {});
for (const ct in apis) {
// ensure we are only processing direct properties
if (!Object.hasOwnProperty.call(apis, ct)) {
continue;
}

const uid = _.get(apis, [ct, 'contentTypes', ct, 'uid'], false);

// skip routes that do not have an associated content type (i.e. routes not using createCoreRouter)
if (!uid) {
continue;
}

// respect ct uid filter
const filterUID = _.get(settings, ['contentTypeFilter', 'uids', uid], false);
if (ctFilterMode === 'allow' && !filterUID && _.isBoolean(filterUID)) {
continue;
} else if (ctFilterMode === 'deny' && filterUID && _.isBoolean(filterUID)) {
continue;
}

const apiRoutes = _.get(apis, [ct, 'routes', ct, 'routes'], []);
for (let i = 0; i < apiRoutes.length; i++) {
// respect ct uid method filter
const method = apiRoutes[i].method;
const filterMethod = _.get(settings, ['contentTypeFilter', 'uids', uid, method], false);
if (ctFilterMode === 'allow' && !filterMethod) {
continue;
} else if (ctFilterMode === 'deny' && filterMethod) {
continue;
}
// default plugins list to none
if (_.size(pluginFilterIDs) !== 0) {
apiTypes.push('plugins');
}

// ensure path exists
if (!_.has(apiRoutes[i], 'config')) {
_.set(strapi, ['api', ct, 'routes', ct, 'routes', i, 'config'], {});
_.forEach(apiTypes, (apiType) => {
const mode = apiType === 'api' ? ctFilterMode : pluginFilterMode;
const filterValues = apiType === 'api' ? ctFilterUIDs : pluginFilterIDs;
_.forEach(strapi[apiType], (api, apiName) => {
const uid = _.get(api, ['contentTypes', apiName, 'uid'], apiName);
if (!isAllowableAPI({ uid, mode, filterValues })) {
return;
}

if (!_.has(apiRoutes[i], ['config', 'middlewares'])) {
_.set(strapi, ['api', ct, 'routes', ct, 'routes', i, 'config', 'middlewares'], []);
}
_.forEach(api.routes, (router) => {
// skip admin routes
if (router.type && router.type === 'admin') {
return;
}

// register route middleware
strapi.api[ct].routes[ct].routes[i].config.middlewares.push((ctx, next) =>
transform(strapi, ctx, next)
);
}
}
};
if (router.routes) {
// process routes
_.forEach(router.routes, (route) => {
if (!isAllowableMethod({ uid, mode, filterValues, method: route.method })) {
return;
}

addTransformMiddleware(route);
});
return;
}

if (!isAllowableMethod({ uid, mode, filterValues, method: router.method })) {
return;
}

// process route
addTransformMiddleware(router);
});
});
});
}

module.exports = register;