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

feat: refactor template preference logic #3596

Merged
merged 12 commits into from
Jun 25, 2023

Conversation

djabarovgeorge
Copy link
Contributor

What change does this PR introduce?

Refactor the template preference usecase.
Add the source to the preference (template/subscriber)

Why was this change needed?

The reason for the refactoring is that the initial logic was not so intuitive, hopefully, the current one is more self-explanatory 😅.

Added the source of the override so we could print it to the execution details so the user could see why the step was filtered.

Other information (Screenshots)

Copy link
Contributor Author

@djabarovgeorge djabarovgeorge Jun 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the deep eql of all the preferences now it checks the preference without the overrides, not sure if to add the override check as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create small unit tests for the main functions of the usecase.

}
}

export function determineOverrides(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the main logic of the template preferences. i centralized the logic to cannon for loop so it will be easier (i hope) to understand.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me it was hard to read, but I think that if you will split it to smaller functions with a good naming and will do the other suggestions it will be much better

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was afraid it became more complicated + the extra override source data added more complexity to it.
At some point, I was not sure if splitting this one into more functions will make it more readable or not, I will try to split it a bit more.

export function determineOverrides(
preferenceSources: Record<'template' | 'subscriber', IPreferenceChannels>
) {
const priorityOrder = ['template', 'subscriber'];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first, we override by template preference and then by the subscriber as the subscriber is on higher priority.

Comment on lines +75 to +81
it('should filter not active channels and sources', async function () {
const response = await getSubscriberPreference(session.subscriberToken);

const data = response.data.data[0];

expect(Object.keys(data.preference.channels).length).to.equal(2);
expect(data.preference.overrides.length).to.equal(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we combine this one with should fetch a default user preference ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could but I wanted a separate test that points to the filtering of the active channels.

).toEqual('subscriber');
});

it('should get preference from template when subscriber preference are empty', async function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're missing the test when the template preferences are empty, shouldn't we have one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add one but I did not, because this state should not exist.

Comment on lines +80 to +86
{
email: true,
sms: true,
in_app: true,
chat: true,
push: true,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a better array of fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it will be better? I am it as an object so it will be the same as the IPreferenceChannels type.

}
}

export function determineOverrides(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me it was hard to read, but I think that if you will split it to smaller functions with a good naming and will do the other suggestions it will be much better

@jainpawan21
Copy link
Member

Hi @djabarovgeorge
Is there any change in this documentation after this PR changes?
https://docs.novu.co/platform/preferences

@djabarovgeorge
Copy link
Contributor Author

Hi @djabarovgeorge Is there any change in this documentation after this PR changes? https://docs.novu.co/platform/preferences

Not yet, basically, the logic remains the same, the only things that change are the following:

  • refactor the code (i tried ti make it a bit more readable/debuggable).
  • I added an additional data object of overrides in order to reflect the user how the preference was calculated. this part maybe could have been added to the bottom of the page under
    Subscriber preference example for three workflows

@LetItRock
Copy link
Contributor

hey @djabarovgeorge, I've added my two cents to the code of this PR, hope it's ok for you :) just removed unnecessary functions and moved code around ;)

@@ -99,7 +113,9 @@ export class GetSubscriberTemplatePreference {
(step) => step.active === true
);

if (activeSteps.some((step) => !step.template)) {
const stepMissingTemplate = activeSteps.some((step) => !step.template);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering do you know how it's possible that the step doesn't have a template?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, one of this usecase clients has a lean template that does not contain the step template. (get-subscriber-preference.usecase)

@djabarovgeorge
Copy link
Contributor Author

hey @djabarovgeorge, I've added my two cents to the code of this PR, hope it's ok for you :) just removed unnecessary functions and moved code around ;)

Shame you needed to, but totally fine by me because in the end, I was not sure if it is more readable or not. and your assistance really helped on getting fresh 👀 on this one 🙏

@djabarovgeorge djabarovgeorge added this pull request to the merge queue Jun 25, 2023
Merged via the queue into next with commit a377b3d Jun 25, 2023
28 checks passed
@djabarovgeorge djabarovgeorge deleted the refactor-template-preference-logic branch June 25, 2023 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants