strapi icon indicating copy to clipboard operation
strapi copied to clipboard

Can't add field in user (users-permissions)

Open M1CK431 opened this issue 3 years ago • 22 comments

Feature request

Please describe your feature request

  • [ ] I have created my request on the Product Board before I submitted this issue
  • [x] I have looked at all the other requests on the Product Board before I submitted this issue

Summary

I would like to add some extra fields in user like firstName and lastName but adding them using Content-Type Builder doesn't make them available in GraphQL API

Steps to reproduce the behavior

  1. Using the Content-Type Build, add a Text field in User
  2. Go on http://localhost:1337/graphql and check GraphQL documentation
  3. The added text field isn't exposed

Screenshots

firstName and lastName text fields added in user using Content-Type Builder: image

Added fields not available in GraphQL API: image

Why is it needed?

Since user is a central part for most authenticated API and adding extra fields or relations to user is a very common use case. For now, we have to manually write specific code to add extra fields (in addition to Content-Type Builder). Thanks @iicdii to remember me the way we do it in v3.

Suggested solution(s)

The added text field should be exposed, both on query and mutation.

Related issue(s)/PR(s)

None, since I have "transform" the current issue from "bug report" to "feature request" :wink:

M1CK431 avatar Dec 24 '21 20:12 M1CK431

You can just extend UsersPermissionsMe type with your custom fields. path: src/index.js

'use strict';

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register({ strapi }) {
    const extensionService = strapi.plugin('graphql').service('extension');
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: 'UsersPermissionsMe',
          definition(t) {
            // here define fields you need
            t.string('testing');
          },
        }),
      ]
    }));
  },

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap({ strapi }) {},

  /**
   * An asynchronous destroy function that runs before
   * your application gets shut down.
   *
   * This gives you an opportunity to gracefully stop services you run.
   */
  destroy({ strapi }) {},
};

iicdii avatar Dec 26 '21 03:12 iicdii

Hi @iicdii and thanks for your quick reply.

Just to be sure, the proposed solution is a workaround? The v3 behavior (where we just need to add fields using Content-Type builder) is the target?

Thanks again

M1CK431 avatar Dec 26 '21 20:12 M1CK431

I remember you had to add fields manually in UsersPermissionsMe type in v3 either like below.

// api/extensions/users-permissions/config/schema.graphql.js
module.exports = {
  definition: `
    extend type UsersPermissionsMe {
      picture: String
      country: String
    }
  `,
  query: ``,
  resolver: {},
};

I'm not sure if Strapi team want to generate UsersPermissionsMe type dynamically, because they have some security concerns and etc..

iicdii avatar Dec 27 '21 03:12 iicdii

You are right @iicdii , I have that file in v3 (sorry I forgot). So now I have to do the same in v4, thanks a lot for explanations about how to do it :kissing_heart:

Still, I think that Content-Type Builder looks like the intuitive way to extend the user schema and I can't see any drawback (because it's just extra fields, no impact on existing, locked, ones).

However, this issue should now be considered as a feature request and so I will edit my original message to reflect that.

Again, thanks a lot for your help, explanations and quick reply :heart:

M1CK431 avatar Dec 27 '21 09:12 M1CK431

Can confirm: manually extending the schema works as expected :+1: One of my two show stopper is now solved :ok_hand:

M1CK431 avatar Dec 27 '21 09:12 M1CK431

This issue has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/strapi-v4-cant-access-custom-fields-from-users-me-via-graphql/13744/2

derrickmehaffy avatar Dec 30 '21 15:12 derrickmehaffy

You can just extend UsersPermissionsMe type with your custom fields. path: src/index.js

'use strict';

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register({ strapi }) {
    const extensionService = strapi.plugin('graphql').service('extension');
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: 'UsersPermissionsMe',
          definition(t) {
            // here define fields you need
            t.string('testing');
          },
        }),
      ]
    }));
  },

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap({ strapi }) {},

  /**
   * An asynchronous destroy function that runs before
   * your application gets shut down.
   *
   * This gives you an opportunity to gracefully stop services you run.
   */
  destroy({ strapi }) {},
};

Looks like this solutions doesn't work for relationships.

nexus.extendType({
  type: "UsersPermissionsMe",
  definition(t) {
    t.string("name");
    t.string("phone");
    t.field("orders", {
      type: "OrderRelationResponseCollection",
    });
  },
})

In my example, name and phone works well, but orders don't.

vitor-mariano avatar Jan 08 '22 20:01 vitor-mariano

Hi @iicdii and @derrickmehaffy,

With your approbation, I guess some tags should be added to this issue:

  • issue-type: feature request
  • severity: low
  • source: plugin:users-permissions (or perhaps source: core:content-type-builder :man_shrugging: )
  • status: confirmed

I would be very happy to do it myself but I haven't enough "karma" (yet) :stuck_out_tongue_closed_eyes:

M1CK431 avatar Jan 11 '22 21:01 M1CK431

Hi @iicdii and @derrickmehaffy,

With your approbation, I guess some tags should be added to this issue:

  • issue-type: feature request
  • severity: low
  • source: plugin:users-permissions (or perhaps source: core:content-type-builder man_shrugging )
  • status: confirmed

I would be very happy to do it myself but I haven't enough "karma" (yet) stuck_out_tongue_closed_eyes

We don't allow anyone but us and selected moderators to add labels yes :P

derrickmehaffy avatar Jan 11 '22 22:01 derrickmehaffy

While this was opened as a feature request, it's actually more like a bug, this part of the schema should be automatically generated. Assuming we can limit the population which I believe should be possible.

derrickmehaffy avatar Jan 11 '22 22:01 derrickmehaffy

Thanks a lot for adding tags (and seriously considering a potential futur implementation for it) :pray:

While this was opened as a feature request, it's actually more like a bug

In fact it was created as a bug report (because I forgot I was forced to add some custom code in my previous v3 setup to make it work) and, after precious @iicdii advises, I "transform" :magic_wand: it as a feature request by editing my original message :shushing_face:

I'm proud to see that the result of my "transformation" is so "plausible" that no one can detect it now :laughing:

M1CK431 avatar Jan 11 '22 22:01 M1CK431

You can just extend UsersPermissionsMe type with your custom fields. path: src/index.js

'use strict';

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register({ strapi }) {
    const extensionService = strapi.plugin('graphql').service('extension');
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: 'UsersPermissionsMe',
          definition(t) {
            // here define fields you need
            t.string('testing');
          },
        }),
      ]
    }));
  },

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap({ strapi }) {},

  /**
   * An asynchronous destroy function that runs before
   * your application gets shut down.
   *
   * This gives you an opportunity to gracefully stop services you run.
   */
  destroy({ strapi }) {},
};

Looks like this solutions doesn't work for relationships.

nexus.extendType({
  type: "UsersPermissionsMe",
  definition(t) {
    t.string("name");
    t.string("phone");
    t.field("orders", {
      type: "OrderRelationResponseCollection",
    });
  },
})

In my example, name and phone works well, but orders don't.

is their any way to make it work

ntkien2192 avatar Feb 10 '22 07:02 ntkien2192

I have the same issue as @ntkien2192 and @vitor-mariano, How can you extend you query to relations, components and dynamic zones.

TekinaTawar avatar Feb 15 '22 13:02 TekinaTawar

Maybe it helps someone. This is how I add a relation to UsersPermissionsMe. (I don't know if it's the best solution but it does work.)

"use strict";

module.exports = {
  register({ strapi }) {
    const { toEntityResponseCollection } = strapi.plugin("graphql").service("format").returnTypes;
    const extensionService = strapi.plugin("graphql").service("extension");

    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: "UsersPermissionsMe",
          definition(t) {
            t.field("solvedQuizzes", {
              type: "QuizRelationResponseCollection",
              resolve: async (root, args) => {
                const userData = await strapi.db.query("plugin::users-permissions.user").findOne({
                  select: [], // solvedQuizzes are there due to populate
                  where: { id: root.id },
                  populate: { solvedQuizzes: true },
                });
                return toEntityResponseCollection(userData.solvedQuizzes ?? [], {
                  args,
                  resourceUID: "api::institution.quiz",
                });
              },
            });
          },
        }),
      ],
    }));
  },
  bootstrap(/*{ strapi }*/) {},
};

JannikWempe avatar Feb 15 '22 15:02 JannikWempe

Thanks for the inspiration, I was able to add the user role relation to the me query based on your example. My code for completeness.

  register({ strapi }) {
    const extensionService = strapi.plugin("graphql").service("extension");
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: "UsersPermissionsMe",
          definition(t) {
            // here define fields you need
            t.field("role", {
              type: "String",
              resolve: async (root, args) => {
                const userData = await strapi.db
                  .query("plugin::users-permissions.user")
                  .findOne({
                    select: [],
                    where: { id: root.id },
                    populate: { role: true },
                  });
                return userData.role.type;
              },
            });
          },
        }),
      ],
    }));
  },

Would this be adjustable to solve the issue with user roles not coming back? https://github.com/strapi/strapi/issues/11957

james-theretreater avatar Apr 20 '22 10:04 james-theretreater

This issue has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/cannot-query-field-firstname-on-type-userspermissionsuser/17884/1

strapi-bot avatar Apr 21 '22 19:04 strapi-bot

This issue has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/cannot-query-field-firstname-on-type-userspermissionsuser/17884/2

strapi-bot avatar Apr 26 '22 19:04 strapi-bot

This issue has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/user-role-info-when-logging-in/18147/2

strapi-bot avatar May 01 '22 19:05 strapi-bot

This issue has been mentioned on Strapi Community Forum. There might be relevant details there:

https://forum.strapi.io/t/strapi-v4-graphql-update-only-specific-collection-entries-with-authentication/18258/1

strapi-bot avatar May 04 '22 13:05 strapi-bot

I have tried to modify the work around and add custom field's to the register mutation, this has not worked can any one point me in the right direction, i need to be able to fill in the user details on sign up.

register({ strapi }) { const extensionService = strapi.plugin("graphql").service("extension"); extensionService.use(({ nexus }) => ({ types: [ nexus.extendType({ type: "UsersPermissionsRegisterInput", definition(t) { // here define fields you need t.string("firstname"); t.string("lastname"); }, }), ], })); },

cdennis121 avatar Aug 23 '22 15:08 cdennis121

What about the REST? Is there a way to retrieve these additional fields on user login? (/api/auth/local)

ShahriarKh avatar Sep 29 '22 13:09 ShahriarKh

I added the function as indicated in ./src/index.js like this :

register({ strapi }) {
    const extensionService = strapi.plugin('graphql').service('extension');
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: 'UsersPermissionsMe',
          definition(t) {
            t.string('user_firstname');
          },
        }),
      ],
    }));
  }

I no longer have the error :

Cannot query field "user_firstname" on type "UsersPermissionsMe".

but I still have the following error:

Field "user_firstname" is not defined by type "UsersPermissionsRegisterInput".

I have these settings in Users-permissions for Authenticated user

settings

and this for public user

Capture d’écran 2022-12-26 à 11 11 16

Does anyone have an idea where the problem comes from ? Thanks

xaviersenente avatar Dec 25 '22 11:12 xaviersenente

I added the function as indicated in ./src/index.js like this :

register({ strapi }) {
    const extensionService = strapi.plugin('graphql').service('extension');
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: 'UsersPermissionsMe',
          definition(t) {
            t.string('user_firstname');
          },
        }),
      ],
    }));
  }

I no longer have the error :

Cannot query field "user_firstname" on type "UsersPermissionsMe".

but I still have the following error:

Field "user_firstname" is not defined by type "UsersPermissionsRegisterInput".

I have these settings in Users-permissions for Authenticated user

settings

and this for public user

Capture d’écran 2022-12-26 à 11 11 16

Does anyone have an idea where the problem comes from ? Thanks

Solved this by adding this:

  nexus.extendInputType({
          type: 'UsersPermissionsRegisterInput',
          definition(t) {
            // here define fields you need
            t.string('lastName');
          },
        }),

hamedor avatar Jan 30 '23 11:01 hamedor

How would I go if I want to add an avatar for example ? Adding relations and strings are easy enough but I can't get files.

Zharkan avatar Apr 16 '23 01:04 Zharkan