Deeplinked relations

System Information
  • Strapi Version: 3.6.2
  • Operating System: Ubuntu Server 20.04 / Mac OSX 11.3
  • Database: MariaDB
  • Node Version: 14.16.0
  • NPM Version: 7.14.0
  • Yarn Version: 1.22.10

I don’t know how to generalize my issue, so I’ll just show my use case.

I am using the out of the box users-permissionsmodel for authentication. I have a collection type named user_profiles and related it to users by "User Profile has and belongs to one User". I changed the controller for user_profiles to add a new field named age by calculating its field birthdate:

async find (ctx) {
  let entities;
  if (ctx.query._q) {
    entities = await['user-profiles'].search(ctx.query);
  } else {
    entities = await['user-profiles'].find(ctx.query);
  } => {
    entity['age'] = _calculateAge(entity.birthdate);
    return entity;
  return => sanitizeEntity(entity, { model: strapi.models['user-profiles'] }));
async findOne(ctx) {
  const { id } = ctx.params;
  let entity = await['user-profiles'].findOne({ id });
  if (!entity) {
    return ctx.notFound();
  entity['age'] = _calculateAge(entity.birthdate);
  return sanitizeEntity(entity, { model: strapi.models['user-profiles'] });

Now I also have a collection type named profile_references which is linked to user_profiles by "User Profile belongs to many Profile References". The profile_references contains a deleted boolean.

When a user logges in and fetches /users/me, he receives only user_profile but no deeplink to the profile_references collection. I fixed that by editing the me() function in /extensions/users-permissions/controllers/User.js:

const user = ctx.state.user;
if (!user) {
  return ctx.badRequest(null, [{ messages: [{ id: 'No authorization header was found' }] }]);
if(user.user_profile) {
  let entity = await['user-profiles'].findOne(user.user_profile)
  delete entity.user;
  user.user_profile = entity;
ctx.body = sanitizeUser(user);

Now I get the profile_references collection deeplinked in the /users/me response.

Issue 1:
When requesting /users/me, the field age does not appear in the response. Does the['user-profiles'].findOne(user.user_profile) skip the modified controller?

Issue 2:
I dont want to show the deleted === truerecords from profile_references. How can I accomplish that? What is the best way?
I tried by adding a afterFind() and afterFindOne() function to the user_profiles model:

afterFindOne: async (result, params, populate) => {
  result.profile_references = await['profile-references'].find()

And in the profile_references I created before functions:

beforeFind: async (params) => {
  params.deleted = false
beforeFindOne: async (params) => {
  params.deleted = false
beforeCount: async (params) => {
  params.deleted = false

This solution breaks the accessibility in the admin panel, which is quite wrong. I mean, I can hardcode to check if a user has a specific role, but it doesn’t look like the right way to me.

Hopefully, I could explain my issues. I appreciate any help.

For issue 2 I guess you could use strapi utility function ‘sanitizeEntity’ :

const { sanitizeEntity } = require('strapi-utils')
let profile_references = await strapi.query(' profile_references').find(params)
return sanitizeEntity(profile_references, { model: strapi.models.profile_references})

It will clean the response as removing the private fields of the model :slight_smile: