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

Extending / customizing a plugin #18

Open
Chmarusso opened this issue Apr 21, 2023 · 13 comments
Open

Extending / customizing a plugin #18

Chmarusso opened this issue Apr 21, 2023 · 13 comments

Comments

@Chmarusso
Copy link

Chmarusso commented Apr 21, 2023

Did anyone try to extend strapi-plugin-passwordless?

I tried methods suggested in official docs and I'm not able to customize createToken service function.

I've tried the extensions folder technique and override it through server-strapi.js. Any advice on what should I try next?

@kucherenko
Copy link
Owner

Hi, thank you for the issue.

To be honest I didn't try to rewrite services, could you please give me the link to the official docs that are you trying to follow?

@kucherenko
Copy link
Owner

@Chmarusso Also, I can try to implement the logic in the public version of the plugin. I had planned to add token patterns - numbers, symbols, etc.

@Chmarusso
Copy link
Author

Chmarusso commented Apr 23, 2023

@kucherenko

That's a tutorial that I tried to follow:
https://docs.strapi.io/dev-docs/plugins-extension#extending-a-plugin-s-interface

I had planned to add token patterns - numbers, symbols, etc.

That is exactly the reason why I'm trying to customize your extension 😃
I would like to use customAlphabet from nanoid and just generate tokens that are only containing 0-9

@Chmarusso
Copy link
Author

In the meantime, I managed to override plugin in the following way:

  • I've copied your package directory to my root dir of strapi
  • changed nanoid call to use customAlphabet
  • installed package from local directory npm install ./path/strapi-plugin-passwordless

Not ideal, but works.

Regarding how your plugin may support custom alphabets in future. Perhaps something like this:

    async createToken(email, context) {
      const settings = await this.settings();
      const {token_length = 20, alphabet = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"} = settings;
      await strapi.query('plugin::passwordless.token').update({where: {email}, data: {is_active: false}});
      const body = customAlphabet(alphabet, token_length);
      const tokenInfo = {
        email,
        body: body(),
        context: JSON.stringify(context)
      };
      return strapi.query('plugin::passwordless.token').create({data: tokenInfo});
    },

@striveShop
Copy link

@kucherenko

Hi,
is there any progress there.

I plan to generate a code that only contains numbers.

Are there already settings for this or do you have to overwrite the code yourself?

@marcosnc08
Copy link

Hi! I could do this, it may help:

  1. Create a folder named passwordless in src/extensions
  2. Create a strapi-server.ts file with the following:
import passwordlessService from "./services/passwordless";

export default (plugin) => {
  plugin.services.passwordless = passwordlessService;

  return plugin;
};

Use this function to replace a controller or service as you wish. In my case replaces the passwordless service with a custom service.

@striveShop
Copy link

striveShop commented Jan 20, 2024

Hi! I could do this, it may help:

  1. Create a folder named passwordless in src/extensions
  2. Create a strapi-server.ts file with the following:
import passwordlessService from "./services/passwordless";

export default (plugin) => {
  plugin.services.passwordless = passwordlessService;

  return plugin;
};

Use this function to replace a controller or service as you wish. In my case replaces the passwordless service with a custom service.

Okay thanks i will try it

@cvolant
Copy link

cvolant commented Feb 1, 2024

Thanks @marcosnc08

Here is a complete working implementation.

// src/extenstions/passwordless/strapi-server.ts
import { Strapi } from '@strapi/strapi'
import passwordlessService from 'strapi-plugin-passwordless/server/services/passwordless'

const extendedPasswordlessService = ({ strapi }: { strapi: Strapi }) => {
  const { sendLoginLink: _extracted, ...otherMethods } = passwordlessService({ strapi })

  return {
    ...otherMethods,
    async sendLoginLink(token) {
      const settings = await this.settings()
      const user = await this.fetchUser({ email: token.email })
      let context = undefined

      try {
        context = JSON.parse(JSON.parse(token.context))
      } catch (_) {
        console.error('passwordless send-link failed to parse context: context should be in JSON format.')
      }

      const params = {
        URL: settings.confirmationUrl,
        CODE: token.body,
        USER: user,
        CONTEXT: context,
      }

      console.log('sendLoginLink params:', params)

      const text = await this.template(settings.message_text, params)
      const html = await this.template(settings.message_html, params)
      const subject = await this.template(settings.object, params)

      const sendData = {
        to: token.email,
        from: settings.from_email && settings.from_name ? `${settings.from_name} <${settings.from_email}>` : undefined,
        replyTo: settings.response_email,
        subject,
        text,
        html,
      }
      // Send an email to the user.
      return await strapi.plugin('email').service('email').send(sendData)
    },
  }
}

export default (plugin) => {
  plugin.services.passwordless = extendedPasswordlessService

  return plugin
}

And here is the log I get:

sendLoginLink params: {
  URL: 'http://localhost:3000/fr/mon-compte',
  CODE: 'k3D2mMGKZqkqv4gCkUmq',
  USER: {
    id: 18,
    username: 'Kim',
    email: '[email protected]',
    provider: null,
    confirmed: false,
    blocked: false,
    createdAt: '2024-02-01T11:20:58.478Z',
    updatedAt: '2024-02-01T11:20:58.478Z',
    role: {
      id: 6,
      name: 'Authenticated',
      description: 'Default role given to authenticated user.',
      type: 'authenticated',
      createdAt: '2023-03-02T18:53:41.863Z',
      updatedAt: '2023-03-02T18:53:41.863Z'
    }
  },
  CONTEXT: { to: 'http://localhost:3000/fr/ici' }
}

And here is how it can be used in the admin "Subject", "Message (text)" and "Message (html)" fields:

Context.to: <%= CONTEXT.to %>
USER.username: <%= USER.username %>

⚠️ With this implementation, the context param of the request should be formatted in json.

Ex: {"to":"http://localhost:3000/fr/ici"}.

@cvolant
Copy link

cvolant commented Feb 3, 2024

I saw in the code that the templates use lodash template, where we can find more details about syntax.

@SetiZ
Copy link

SetiZ commented Jul 5, 2024

thank @cvolant for the code exemple, I was able to change some parts and use an email template from Brevo directly, instead of the standard template of passwordless plugin

@SetiZ
Copy link

SetiZ commented Aug 28, 2024

@cvolant I just realized there's a double parse on your code
context = JSON.parse(JSON.parse(token.context))

@ggggaolf
Copy link

Hi, thank you for the issue.

To be honest I didn't try to rewrite services, could you please give me the link to the official docs that are you trying to follow?

@kucherenko hey~may i ask is there any progress there? still have a plan on this ?

@kucherenko
Copy link
Owner

hey @ggggaolf, I'm sorry I don't have time for implementing the feature right now, will try to do that in few months

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants