VirtusLab-Open-Source / strapi-plugin-comments

A plugin for Strapi Headless CMS that provides end to end comments feature with their moderation panel, bad words filtering, abuse reporting and more.
MIT License
409 stars 64 forks source link

Proper way to update author info #210

Open jnovak-SM2Dev opened 1 year ago

jnovak-SM2Dev commented 1 year ago

I'm a bit confused about how the author is handled. I have to pass in the author's email, avatar, etc. What happens if that info changes (ie the user updates their profile)? Do I need to get all comments by the user and update each instance?

jnovak-SM2Dev commented 1 year ago

Looks like this was somewhat answered here, but how can I add additional fields/extend calls for this plugin for GraphQL?

cyp3rius commented 1 year ago

If you base on Strapi Users simply add fields to them and populate proper ones in your query.

For more detailed suggestion please provide idea you've got.

jnovak-SM2Dev commented 1 year ago

I guess the larger question would be, what is the proper way to use extensionService with this plugin? I'm not sure how to override the findAllFlat and findAllInHierarchy GraphQL methods to be able to adjust what is returned.

cyp3rius commented 1 year ago

About extensions you can read here but I guess you want to add more fields to User Collection to which we have got relation in the comment schema. After adding fields you should follow the "Populating" chapter in the Strapi Doc.

jnovak-SM2Dev commented 1 year ago

@cyp3rius I understand how to add fields to users and how to populate. My confusion is around extending GraphQL for comments specifically. For example, this is what i'd expect to be able to do, something like below.

 extensionService.use(({ strapi }) => ({
  typeDefs: `
    type CommentSingle {
      authorFull: UsersPermissionsUserEntityResponse
    }
  `,
  resolvers: {
    Query: {
      findAllFlat: {
        resolve: async (parent, args, context) => {
          const { toEntityCollectionResponse } = strapi.service(
            "plugin::graphql.format"
          ).returnTypes;

          const data = await strapi.services["api::comment.comment"].find(
            {}
          );

          const response = toEntityCollectionResponse(data.results);
          return response;
        },
      },
    },
  },
}));

Is there an example on how to do this or does this need to be handled a special way? Sorry, it's very confusing and Strapi 4's docs kind of suck.

cyp3rius commented 1 year ago

Let me check that on weekend and back to you with some advice :)

jnovak-SM2Dev commented 1 year ago

@cyp3rius Thanks! That'd be great. Even you just find a sample somewhere or an article. It's just tough cause Strapi's docs are all over the place with V3 and V4, GraphQL makes it tough, and then you add in the complexity of this plugin having specific calls and types, it's tough to know how to handle things properly.

cyp3rius commented 1 year ago

@SM2DevLLC I did some research and coding. What you expect you should be able to do not as a plugin extension but as part of the register routing of your Strapi project.

File: 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.service("plugin::graphql.extension");

    extensionService.use(({ strapi }) => ({
      typeDefs: `
        type CommentSingle {
          authorFull: UsersPermissionsUserEntityResponse
        }
      `,
      resolvers: {
        Query: {
          findAllFlat: {
            resolve: async (parent, args, context) => {
              const { toEntityCollectionResponse } = strapi.service(
                "plugin::graphql.format"
              ).returnTypes;

              const data = await strapi.services["api::comment.comment"].find(
                {}
              );

              const response = toEntityCollectionResponse(data.results);
              return response;
            },
          },
        },
      },
    }));
  },

  /**
   * 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 }*/) { },
};
Screenshot 2023-05-20 at 00 02 02

Is that what you expect to do?

jnovak-SM2Dev commented 1 year ago

@cyp3rius Yes that's what i'm already doing. That's where the code is. It just doesn't work. I think part of it is the ["api::comment.comment"] portion. I think it may need to be ["plugin::comment.comment"] or something along those lines.

kienbui195 commented 1 year ago

Please add the like feature, manage likes for each comment. I think adding the like feature will make your plugin more perfect

jnovak-SM2Dev commented 1 year ago

@cyp3rius It looks like the authorUser relationship exists, it just isn't being allowed to be selected in GraphQL queries. Can you please enable this? If you do, it'll be easy for people to select that as a return field and even extend it.

cyp3rius commented 1 year ago

Looking into that

CodeVoyager commented 6 months ago

Hi @jnovak-SM2Dev,

I dug a bit deeper. Comment entity connects either to Strapi user or displays details provided at comment creation. Both are displayed as author. If comment is created by strapi user then details of an user are displayed. If relation to user does not exist plugin falls back to reading author details save at comment level.

Long story short you cannot read author as a strapi user or author as static values at comments level. Only one of them at the time. You query both from the same field.

jusiho commented 3 months ago

you just need to extend the response, create a field and resolve, in index.js

const extensionService = strapi.plugin("graphql").service("extension");
    extensionService.use(({ nexus }) => ({
      types: [
        nexus.extendType({
          type: "CommentSingle",
          definition(t) {
            t.string("authorFull", {
              type: "UsersPermissionsUserEntityResponse",
              description: "Author full data",
              resolve: async (parent, root, args) => {
                const { toEntityResponse } = strapi.service(
                  "plugin::graphql.format"
                ).returnTypes;
                console.log("parent", parent.author.id);
                const user = await strapi.db
                  .query("plugin::users-permissions.user")
                  .findOne({
                    where: { id: parent.author.id },
                    populate: { profile_image: true },
                  });
                console.log("user", user);

                return toEntityResponse(user);
              },
            });
          },
        }),
      ],