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

11.0 mig mass_mailing_unique #276

Merged
merged 7 commits into from
Jun 29, 2018

Conversation

ernestotejeda
Copy link
Member

@ernestotejeda ernestotejeda commented May 19, 2018

@rafaelbn
Copy link
Member

rafaelbn commented Jun 5, 2018

cc @Tecnativa

@rafaelbn rafaelbn added this to the 11.0 milestone Jun 5, 2018
Copy link
Member

@chienandalu chienandalu left a comment

Choose a reason for hiding this comment

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

Here there's a problem with the new Odoo mailing lists implementation as well. Here's the thing (ping @yajo ):

  • Two contacts with the same email address will receive just one email, so one of them is just ignored.
  • Maybe we should just add a _sql_constraints by email.

"summary": "Avoids duplicate mailing lists and contacts",
"version": "11.0.1.0.0",
"category": "Marketing",
"website": "https://tecnativa.com",
Copy link
Member

Choose a reason for hiding this comment

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

_inherit = "mail.mass_mailing.contact"

@api.constrains('partner_id', 'list_ids')
def _check_partner_id_lists_ids(self):
Copy link
Member

Choose a reason for hiding this comment

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

Just add a unique constraint per email and remove this method.

class MailMassMailingContact(models.Model):
_inherit = "mail.mass_mailing.contact"

@api.constrains('partner_id', 'list_ids')
Copy link
Member

Choose a reason for hiding this comment

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

If I'm not wrong, partner_id field doesn't exist.

cr.execute("""SELECT c.email, l.name, COUNT(c.id)
FROM
mail_mass_mailing_contact AS c
INNER JOIN mail_mass_mailing_contact_list_rel AS cl
Copy link
Member

Choose a reason for hiding this comment

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

All you need to check, if you follow my suggestion below, is to check there are no duplicate emails in mail_mass_mailing_contact. No joins needed.

@rafaelbn
Copy link
Member

This PR depends on @chienandalu approval.

@yajo
Copy link
Member

yajo commented Jun 13, 2018

Maybe we should just add a _sql_constraints by email.

This can't be possible, because it would break mass_mailing_custom_unsubscribe, which is currently much more needed.

Two contacts with the same email address will receive just one email, so one of them is just ignored.

We just checked with @rafaelbn that it sends duplicated emails, just the 2nd (and next ones) are set in exception state. Not sure why that happens, but it can be confusing.

At the end, seeing current v11 implementation, all we need here is a python constraint that avoids 2 contacts to exist for 1 list.

@ernestotejeda
Copy link
Member Author

the situation here is similar to 11.0 mig mass_mailing_partner #277 , i had comment about that

@@ -0,0 +1,6 @@
* `Tecnativa <https://www.tecnativa.com>`_:

* Jairo Llopis <jairo.llopis@tecnativa.com>
Copy link
Member

Choose a reason for hiding this comment

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

Remove emails

Copy link
Member

@chienandalu chienandalu left a comment

Choose a reason for hiding this comment

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

I think case variations should be consider to avoid duplicates due to user errors. For instance, these two email:

Are going to be sent to the same recipient, but is going to pass over the duplicates filter this module tries to avoid.

def _check_email_list_ids(self):
for contact in self:
other_contact = self.search([
('email', '=', contact.email),
Copy link
Member

Choose a reason for hiding this comment

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

To avoid duplucates due to case variations:

('email', '=', contact.email.lower()),

class MailMassMailingList(models.Model):
_inherit = "mail.mass_mailing.list"
_sql_constraints = [
("unique_name", "UNIQUE(name)",
Copy link
Member

Choose a reason for hiding this comment

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

Same problem is going to happen here with case variations. For instance:

- My list of contacts
- my list of contacts
- My List Of Contacts
- MY LIST OF CONTACTS
...

They all are going to pass over the constrain.

Copy link
Member Author

Choose a reason for hiding this comment

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

With postgre, i think you can not make an insensitive unique constraint to not distinguish between uppercase and lowercase. To solve that, we can make an UNIQUE INDEX, for example:
CREATE UNIQUE INDEX "name_unique_idx" ON "mail_mass_mailing_list" (LOWER ('name'))
But then we must catch an IntegrityError exception in the create and write method or in another place. Actually, I do not know if it's worth doing all of this for this specific case

Copy link
Member

Choose a reason for hiding this comment

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

Fortunately it's possible to add a constraint case insensitive. Just put UNIQUE (LOWER(email)). See for example: http://shuber.io/case-insensitive-unique-constraints-in-postgres/

Copy link
Member Author

Choose a reason for hiding this comment

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

In this page it says that Unfortunately, Postgres does now allow us to define unique constraint using LOWER and according to this page one of the solutions is to make a 'UNIQUE INDEX'. That's what I said above and then it can be more work

Copy link
Member

Choose a reason for hiding this comment

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

Right, I read it bad :(

OK, let's keep it that way. @chienandalu please give your final review

_("{0} appears {2} times in list {1}.").format(*result))

# Search for duplicates in list's name
cr.execute("""SELECT name, COUNT(id)
Copy link
Member

Choose a reason for hiding this comment

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

If we want to avoid case duplicates:

SELECT LOWER(name) AS n, COUNT(id)
[...]
GROUP BY n

errors = list()

# Search for duplicates in emails
cr.execute("""SELECT c.email, l.name, COUNT(c.id)
Copy link
Member

Choose a reason for hiding this comment

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

We should check avoid email case variations. Something like:

SELECT LOWER(c.email) AS e, l.name, COUNT(c.id)
[...]
GROUP BY l.name, e, c.id

@pedrobaeza
Copy link
Member

@ernestotejeda please rebase and attend latest comments

Jairo Llopis and others added 7 commits June 20, 2018 16:23
This new module avoids duplicates in mass mailing lists.

Now you cannot have 2 lists with the same name, and you cannot have the same
email repeated in a list.

This will avoid sending the same mail to a contact repeated times, which will
disturb him and most probably cause you to be blocked as spam.
@pedrobaeza pedrobaeza mentioned this pull request Jun 20, 2018
26 tasks
@pedrobaeza
Copy link
Member

@ernestotejeda next time please drop a comment when you make the rebase, because no notification gets to our inboxes if not.

Copy link
Member

@pedrobaeza pedrobaeza left a comment

Choose a reason for hiding this comment

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

@yajo please finish your review with latest changes

@yajo yajo merged commit 1274d12 into OCA:11.0 Jun 29, 2018
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

Successfully merging this pull request may close these issues.

None yet

7 participants