2020-10-27 16:01:46 +01:00
|
|
|
'use strict';
|
|
|
|
|
2022-08-10 19:14:04 +02:00
|
|
|
const { prop, isEmpty, isNil } = require('lodash/fp');
|
|
|
|
const { convertFiltersQueryParams } = require('@strapi/utils/lib/convert-query-params');
|
2022-08-09 19:35:48 +02:00
|
|
|
const { hasDraftAndPublish } = require('@strapi/utils').contentTypes;
|
2021-04-29 13:51:12 +02:00
|
|
|
const { PUBLISHED_AT_ATTRIBUTE } = require('@strapi/utils').contentTypes.constants;
|
2020-10-27 16:01:46 +01:00
|
|
|
|
|
|
|
const { getService } = require('../utils');
|
2022-08-11 15:52:58 +02:00
|
|
|
const { validateFindAvailable } = require('./validation/relations');
|
2020-10-27 16:01:46 +01:00
|
|
|
|
|
|
|
module.exports = {
|
2022-08-11 15:52:58 +02:00
|
|
|
async findAvailable(ctx) {
|
|
|
|
const { userAbility } = ctx.state;
|
2020-10-27 16:01:46 +01:00
|
|
|
const { model, targetField } = ctx.params;
|
|
|
|
|
2022-08-11 15:52:58 +02:00
|
|
|
await validateFindAvailable(ctx.request.query);
|
2022-08-05 16:05:52 +02:00
|
|
|
|
2022-08-11 15:52:58 +02:00
|
|
|
const { component, entityId, idsToOmit, page = 1, pageSize = 10, _q } = ctx.request.query;
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-09 19:35:48 +02:00
|
|
|
const sourceModelUid = component || model;
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-09 19:35:48 +02:00
|
|
|
const sourceModel = strapi.getModel(sourceModelUid);
|
|
|
|
if (!sourceModel) {
|
2022-08-05 16:05:52 +02:00
|
|
|
return ctx.badRequest("The model doesn't exist");
|
2020-10-27 16:01:46 +01:00
|
|
|
}
|
|
|
|
|
2022-08-11 15:52:58 +02:00
|
|
|
// permission check
|
|
|
|
if (entityId) {
|
|
|
|
const entityManager = getService('entity-manager');
|
|
|
|
const permissionChecker = getService('permission-checker').create({
|
|
|
|
userAbility,
|
|
|
|
model: sourceModel,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (permissionChecker.cannot.read()) {
|
|
|
|
return ctx.forbidden();
|
|
|
|
}
|
|
|
|
|
|
|
|
const entity = await entityManager.findOneWithCreatorRoles(entityId, model);
|
|
|
|
|
|
|
|
if (!entity) {
|
|
|
|
return ctx.notFound();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (permissionChecker.cannot.read(entity)) {
|
|
|
|
return ctx.forbidden();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-09 19:35:48 +02:00
|
|
|
const attribute = sourceModel.attributes[targetField];
|
2021-07-08 18:15:32 +02:00
|
|
|
if (!attribute || attribute.type !== 'relation') {
|
2022-08-05 16:05:52 +02:00
|
|
|
return ctx.badRequest("This relational field doesn't exist");
|
2020-10-27 16:01:46 +01:00
|
|
|
}
|
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
const targetedModel = strapi.getModel(attribute.target);
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
const offset = Math.max(page - 1, 0) * pageSize;
|
|
|
|
const limit = Number(pageSize);
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
const modelConfig = component
|
2022-08-09 19:35:48 +02:00
|
|
|
? await getService('components').findConfiguration(sourceModel)
|
|
|
|
: await getService('content-types').findConfiguration(sourceModel);
|
2022-08-05 16:05:52 +02:00
|
|
|
const mainField = prop(`metadatas.${targetField}.edit.mainField`, modelConfig) || 'id';
|
2021-01-25 17:58:18 +01:00
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
const query = strapi.db.queryBuilder(targetedModel.uid);
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-11 15:52:58 +02:00
|
|
|
if (!isNil(_q)) {
|
|
|
|
query.search(_q);
|
2022-08-05 16:05:52 +02:00
|
|
|
}
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-10 19:14:04 +02:00
|
|
|
if (!isNil(ctx.request.query.filters)) {
|
|
|
|
query.where(convertFiltersQueryParams(ctx.request.query.filters, targetedModel));
|
|
|
|
}
|
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
if (!isEmpty(idsToOmit)) {
|
|
|
|
query.where({ id: { $notIn: idsToOmit } });
|
2020-10-27 16:01:46 +01:00
|
|
|
}
|
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
if (entityId) {
|
2022-08-09 19:35:48 +02:00
|
|
|
const joinTable = strapi.db.metadata.get(sourceModelUid).attributes[targetField].joinTable;
|
2022-08-05 16:05:52 +02:00
|
|
|
const sourceColumn = component ? joinTable.joinColumn.name : joinTable.inverseJoinColumn.name;
|
|
|
|
const targetColumn = component ? joinTable.inverseJoinColumn.name : joinTable.joinColumn.name;
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-10 19:14:04 +02:00
|
|
|
// Select ids of targeted entities already having a relation with entityId
|
2022-08-05 16:05:52 +02:00
|
|
|
const knexSubQuery = strapi.db
|
|
|
|
.queryBuilder(joinTable.name)
|
|
|
|
.select([targetColumn])
|
|
|
|
.where({ [sourceColumn]: entityId })
|
|
|
|
.getKnexQuery();
|
|
|
|
|
|
|
|
query.where({ id: { $notIn: knexSubQuery } });
|
|
|
|
}
|
2020-10-27 16:01:46 +01:00
|
|
|
|
2022-08-05 16:05:52 +02:00
|
|
|
const { count } = await query
|
|
|
|
.clone()
|
|
|
|
.count()
|
|
|
|
.first()
|
|
|
|
.execute();
|
2022-08-09 19:35:48 +02:00
|
|
|
|
|
|
|
const fieldsToSelect = ['id', mainField];
|
|
|
|
if (hasDraftAndPublish(targetedModel)) {
|
|
|
|
fieldsToSelect.push(PUBLISHED_AT_ATTRIBUTE);
|
|
|
|
}
|
2022-08-05 16:05:52 +02:00
|
|
|
const entities = await query
|
2022-08-09 19:35:48 +02:00
|
|
|
.select(fieldsToSelect)
|
2022-08-05 16:05:52 +02:00
|
|
|
.orderBy(mainField)
|
|
|
|
.offset(offset)
|
|
|
|
.limit(limit)
|
|
|
|
.execute();
|
|
|
|
|
|
|
|
ctx.body = {
|
|
|
|
results: entities,
|
|
|
|
pagination: {
|
|
|
|
page: Number(page),
|
|
|
|
pageSize: Number(pageSize),
|
|
|
|
total: count,
|
|
|
|
},
|
|
|
|
};
|
2020-10-27 16:01:46 +01:00
|
|
|
},
|
|
|
|
};
|