SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 8505d1b3 authored by George Katsikas's avatar George Katsikas :goat:
Browse files

add common merge object utility

restructure common utilities
parent 53c9edfc
No related branches found
No related tags found
No related merge requests found
from .models import *
from .text import *
from .mail import *
# MARKED FOR DEPRECATION
from django.core.mail import EmailMultiAlternatives
from common.utils.models import get_current_domain
class BaseMailUtil(object):
mail_sender = "no-reply@%s" % get_current_domain()
mail_sender_title = ""
@classmethod
def load(cls, _dict, request=None):
cls._context = _dict
cls._context["request"] = request
cls._context["domain"] = get_current_domain()
for var_name in _dict:
setattr(cls, var_name, _dict[var_name])
def _send_mail(
cls, template_name, recipients, subject, extra_bcc=None, extra_context={}
):
"""
Call this method from a classmethod to send emails.
The template will have context variables defined appended from the `load` method.
Arguments:
template_name -- The .html template to use in the mail. The name be used to get the
following two templates:
`email/<template_name>.txt` (non-HTML)
`email/<template_name>.html`
recipients -- List of mailaddresses to send to mail to.
subject -- The subject of the mail.
"""
template = loader.get_template("email/%s.txt" % template_name)
html_template = loader.get_template("email/%s.html" % template_name)
cls._context.update(extra_context)
message = template.render(cls._context)
html_message = html_template.render(cls._context)
bcc_list = [cls.mail_sender]
if extra_bcc:
bcc_list += extra_bcc
email = EmailMultiAlternatives(
subject,
message,
"%s <%s>" % (cls.mail_sender_title, cls.mail_sender),
recipients,
bcc=bcc_list,
reply_to=[cls.mail_sender],
)
email.attach_alternative(html_message, "text/html")
email.send(fail_silently=False)
from django.contrib.sites.models import Site
from django.db.models import Field, ForeignObjectRel
from django.db.models.fields.related import RelatedField
def get_current_domain():
try:
return Site.objects.get_current().domain
except:
return "fake.domain"
def merge(old, new):
"""
Merge two model instances, `old` and `new`, by:
- copying all the fields from `old` to `new` if they are not already set
- updating all (reverse) relations from `old` to `new`
"""
model = old.__class__
for field in model._meta.get_fields():
accessor = field.name or field.get_accessor_name()
old_value = getattr(old, accessor, None)
if isinstance(field, Field):
# If new object has a value for the field, skip it
# otherwise, set the value from the old object
if getattr(new, accessor, None) is None:
setattr(new, accessor, old_value)
elif isinstance(field, RelatedField) or isinstance(field, ForeignObjectRel):
# Handle object relations
related_object = field
manager = related_object.related_model.objects
# Guard against missing related object field names
if not hasattr(related_object, "field"):
continue
field_name = related_object.field.name
if related_object.one_to_one:
# For one-to-one relations, we get the related objects from the manager
# and anull (let go) the attribute of the new object
# so that it can be attached it to the old object
# =====================
# Equivalent to:
# new.field_name = None
# old.field_name = new
manager.filter(**{field_name: new}).update(**{field_name: None})
manager.filter(**{field_name: old}).update(**{field_name: new})
elif related_object.many_to_many:
# For many-to-many relations, `old_value` is a manager
# and we can add the related objects to the new object
if accessor is not None and old_value is not None:
getattr(new, accessor).add(*old_value.all())
else:
for related_queryset in manager.filter(**{field_name: old}):
getattr(related_queryset, accessor).remove(old)
getattr(related_queryset, accessor).add(new)
elif related_object.one_to_many:
# For one-to-many relations, we get the related objects from the manager
# and update the foreign key to the new object
manager.filter(**{field_name: old}).update(**{field_name: new})
else:
# Handle many-to-one relations by setting the attribute
# of the new object if it is not already set
if getattr(new, accessor) is None:
setattr(new, accessor, old_value)
else:
# Handle fields by setting the attribute of the new object
# if it is not already set
if getattr(new, accessor) is None:
setattr(new, accessor, old_value)
# Save both objects
new.save()
old.save()
......@@ -4,12 +4,9 @@ __license__ = "AGPL v3"
import datetime
from django.contrib.sites.models import Site
from django.core.mail import EmailMultiAlternatives
from django.db.models import Q
from django.template import loader
from .constants import CHARACTER_ALTERNATIVES, CHARACTER_LATINISATIONS
from ..constants import CHARACTER_ALTERNATIVES, CHARACTER_LATINISATIONS
import unicodedata
......@@ -170,63 +167,8 @@ def jatsify_tags(text):
return jatsified
def get_current_domain():
try:
return Site.objects.get_current().domain
except:
return "fake.domain"
def remove_extra_spacing(text):
"""
Remove extra spacing from text in the form of multiple spaces.
"""
return " ".join(text.strip().split())
# MARKED FOR DEPRECATION
class BaseMailUtil(object):
mail_sender = "no-reply@%s" % get_current_domain()
mail_sender_title = ""
@classmethod
def load(cls, _dict, request=None):
cls._context = _dict
cls._context["request"] = request
cls._context["domain"] = get_current_domain()
for var_name in _dict:
setattr(cls, var_name, _dict[var_name])
def _send_mail(
cls, template_name, recipients, subject, extra_bcc=None, extra_context={}
):
"""
Call this method from a classmethod to send emails.
The template will have context variables defined appended from the `load` method.
Arguments:
template_name -- The .html template to use in the mail. The name be used to get the
following two templates:
`email/<template_name>.txt` (non-HTML)
`email/<template_name>.html`
recipients -- List of mailaddresses to send to mail to.
subject -- The subject of the mail.
"""
template = loader.get_template("email/%s.txt" % template_name)
html_template = loader.get_template("email/%s.html" % template_name)
cls._context.update(extra_context)
message = template.render(cls._context)
html_message = html_template.render(cls._context)
bcc_list = [cls.mail_sender]
if extra_bcc:
bcc_list += extra_bcc
email = EmailMultiAlternatives(
subject,
message,
"%s <%s>" % (cls.mail_sender_title, cls.mail_sender),
recipients,
bcc=bcc_list,
reply_to=[cls.mail_sender],
)
email.attach_alternative(html_message, "text/html")
email.send(fail_silently=False)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment