Commit df9a9dcd authored by Lars Kruse's avatar Lars Kruse
Browse files

refactor(settings): provide grouprise settings via an object instead of module attributes

The change allows to apply lazy evaluation to (callable) values.
This is necessary for upcoming optional applications (e.g. the `matrix_chat`
feature), since their full configuration may not be available during the
pre-configure phase (e.g. when "urls.py" is evaluated).

Additionally temporary setting overrides (during tests) are less complicated
with an object instead of a module attribute.
parent fe898447
Pipeline #3115 passed with stages
in 3 minutes and 46 seconds
from django.contrib.sites.models import Site
import grouprise.core.settings as grouprise_settings
from grouprise.core.settings import CORE_SETTINGS
def settings(request):
return {
"GROUPRISE_CLAIMS": grouprise_settings.CLAIMS,
"GROUPRISE_CLAIMS": CORE_SETTINGS.CLAIMS,
"GROUPRISE_SITE_NAME": Site.objects.get_current().name,
"GROUPRISE_THEME_COLOR": grouprise_settings.THEME_COLOR,
"GROUPRISE_LOGO_TEXT": grouprise_settings.LOGO_TEXT,
"GROUPRISE_LOGO_BACKDROP": grouprise_settings.LOGO_BACKDROP,
"GROUPRISE_LOGO_SQUARE": grouprise_settings.LOGO_SQUARE,
"GROUPRISE_LOGO_FAVICON": grouprise_settings.LOGO_FAVICON,
"GROUPRISE_THEME_COLOR": CORE_SETTINGS.THEME_COLOR,
"GROUPRISE_LOGO_TEXT": CORE_SETTINGS.LOGO_TEXT,
"GROUPRISE_LOGO_BACKDROP": CORE_SETTINGS.LOGO_BACKDROP,
"GROUPRISE_LOGO_SQUARE": CORE_SETTINGS.LOGO_SQUARE,
"GROUPRISE_LOGO_FAVICON": CORE_SETTINGS.LOGO_FAVICON,
}
......@@ -6,7 +6,7 @@ import subprocess
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
from grouprise.core.settings import BACKUP_PATH
from grouprise.core.settings import CORE_SETTINGS
def create_filename(directory, prefix, filename=None, suffix=''):
......@@ -51,7 +51,8 @@ class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--prefix', default='', help='prefix for the filename')
parser.add_argument('--output-dir', default=BACKUP_PATH, help='backup storage dir')
parser.add_argument(
'--output-dir', default=CORE_SETTINGS.BACKUP_PATH, help='backup storage dir')
parser.add_argument('--output-file', default=None, help='backup filename')
def handle(self, *args, **options):
......
......@@ -8,20 +8,20 @@ from django.db import models
from django.utils import crypto
import django.utils.timezone
from grouprise.core.settings import UPLOAD_MAX_FILE_SIZE as UPLOAD_MAX_FILE_SIZE_MB
from grouprise.core.settings import CORE_SETTINGS
IMAGE_FIELD_HELP_TEXT = (
'Mögliche Formate sind JPEG, PNG und viele weitere. Nicht unterstützt werden PDF- '
'oder SVG-Dateien. Die maximal erlaubte Dateigröße beträgt {} MB.'.format(
UPLOAD_MAX_FILE_SIZE_MB))
CORE_SETTINGS.UPLOAD_MAX_FILE_SIZE))
PERMISSION_TOKEN_LENGTH = 15
def validate_file_size(f):
try:
if f._size > UPLOAD_MAX_FILE_SIZE_MB * 1024 * 1024:
if f._size > CORE_SETTINGS.UPLOAD_MAX_FILE_SIZE * 1024 * 1024:
raise django.forms.ValidationError('Die Datei ist zu groß.')
except AttributeError:
pass
......
......@@ -11,7 +11,7 @@ from django.core import mail
from django.template import loader
from grouprise.core.models import PermissionToken
import grouprise.core.settings as grouprise_settings
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.templatetags.defaultfilters import full_url as build_absolute_uri
logger = logging.getLogger(__name__)
......@@ -22,7 +22,7 @@ class Notification:
def send_all(cls, instance, force=False, **extra_kwargs):
for recipient, kwargs in cls.get_recipients(instance).items():
if (force or not recipient.is_email_blocker) and (
recipient.id != grouprise_settings.FEED_IMPORTER_GESTALT_ID):
recipient.id != CORE_SETTINGS.FEED_IMPORTER_GESTALT_ID):
kwargs.update(extra_kwargs)
cls(instance).send(recipient, **kwargs)
......@@ -63,14 +63,14 @@ class Notification:
return '{} <{}>'.format(self.recipient, self.recipient.user.email)
def get_formatted_reply_address(self, token):
return '<{}>'.format(grouprise_settings.DEFAULT_REPLY_TO_EMAIL.format(
return '<{}>'.format(CORE_SETTINGS.DEFAULT_REPLY_TO_EMAIL.format(
reply_key=token.secret_key))
def get_formatted_sender(self):
sender = self.get_sender()
name = '{} via '.format(sender) if sender else ''
if sender:
email = grouprise_settings.DEFAULT_DISTINCT_FROM_EMAIL.format(slug=sender.slug)
email = CORE_SETTINGS.DEFAULT_DISTINCT_FROM_EMAIL.format(slug=sender.slug)
else:
email = settings.DEFAULT_FROM_EMAIL
from_email = '{name}{site} <{email}>'.format(
......
import contextlib
import functools
import os
from django.conf import settings
......@@ -7,51 +9,86 @@ from django.templatetags.static import static
_GR = settings.GROUPRISE
# branding
CLAIMS = _GR.get("CLAIMS", [])
LOGO_BACKDROP = _GR.get(
"BRANDING_LOGO_BACKDROP", static("core/logos/logo-backdrop.svg")
)
LOGO_FAVICON = _GR.get("BRANDING_LOGO_FAVICON", static("core/logos/logo-square.png"))
LOGO_SQUARE = _GR.get("BRANDING_LOGO_SQUARE", static("core/logos/logo-square.svg"))
LOGO_TEXT = _GR.get("BRANDING_LOGO_TEXT", static("core/logos/logo-text.svg"))
THEME_COLOR = _GR.get("BRANDING_THEME_COLOR", "#2a62ac")
# mail handling
COLLECTOR_MAILBOX_ADDRESS = _GR.get("COLLECTOR_MAILBOX_ADDRESS", None)
DEFAULT_DISTINCT_FROM_EMAIL = _GR.get(
"DEFAULT_DISTINCT_FROM_EMAIL", "noreply+{slug}@localhost"
)
DEFAULT_REPLY_TO_EMAIL = _GR.get(
"DEFAULT_REPLY_TO_EMAIL", "reply+{reply_key}@localhost"
)
MAILINGLIST_ENABLED = _GR.get("MAILINGLIST_ENABLED", False)
POSTMASTER_EMAIL = _GR.get("POSTMASTER_EMAIL", "postmaster@localhost")
# content import
FEED_IMPORTER_GESTALT_ID = _GR.get("FEED_IMPORTER_GESTALT_ID", None)
OPERATOR_GROUP_ID = _GR.get("OPERATOR_GROUP_ID", 1)
UNKNOWN_GESTALT_ID = _GR.get("UNKNOWN_GESTALT_ID", 1)
# local administration
BACKUP_PATH = _GR.get("BACKUP_PATH", os.getcwd())
HOOK_SCRIPT_PATHS = _GR.get("HOOK_SCRIPT_PATHS", [])
# miscellaneous
ENTITY_SLUG_BLACKLIST = _GR.get(
"ENTITY_SLUG_BLACKLIST",
[
"all",
"grouprise",
"info",
"mail",
"noreply",
"postmaster",
"reply",
"stadt",
"webmaster",
"www",
],
class LazySettingsResolver:
""" storage class for settings
Features:
* optional lazy evaluation
* For example the evaluation of "Site.objects.get_current().domain" can be delayed
until it is really required, since database queries are not available in the
pre-configure phase (e.g. while "urls.py" is parsed).
* allow temporary override of specific settings
"""
def __init__(self, **kwargs):
# determine which resolver is available for lazy evaluation
try:
lazy_resolver = functools.cached_property
except AttributeError:
# "cached_property" was not available before Python 3.8
def lazy_resolver(func):
return property(functools.lru_cache(func))
self._attribute_names = set()
# set the attribute values or (for callables) a lazy evaluator
for key, value in kwargs.items():
setattr(self, key, lazy_resolver(value) if callable(value) else value)
self._attribute_names.add(key)
@contextlib.contextmanager
def temporary_override(self, **kwargs):
""" Allow temporary manipulation of specific settings (e.g. for tests) """
previous_content = {}
for key, value in kwargs.items():
previous_content[key] = getattr(self, key)
setattr(self, key, value)
yield self
for key, value in previous_content.items():
setattr(self, key, value)
CORE_SETTINGS = LazySettingsResolver(
# branding
CLAIMS=_GR.get("CLAIMS", []),
LOGO_BACKDROP=_GR.get(
"BRANDING_LOGO_BACKDROP", static("core/logos/logo-backdrop.svg")
),
LOGO_FAVICON=_GR.get("BRANDING_LOGO_FAVICON", static("core/logos/logo-square.png")),
LOGO_SQUARE=_GR.get("BRANDING_LOGO_SQUARE", static("core/logos/logo-square.svg")),
LOGO_TEXT=_GR.get("BRANDING_LOGO_TEXT", static("core/logos/logo-text.svg")),
THEME_COLOR=_GR.get("BRANDING_THEME_COLOR", "#2a62ac"),
# mail handling
COLLECTOR_MAILBOX_ADDRESS=_GR.get("COLLECTOR_MAILBOX_ADDRESS", None),
DEFAULT_DISTINCT_FROM_EMAIL=_GR.get(
"DEFAULT_DISTINCT_FROM_EMAIL", "noreply+{slug}@localhost"
),
DEFAULT_REPLY_TO_EMAIL=_GR.get(
"DEFAULT_REPLY_TO_EMAIL", "reply+{reply_key}@localhost"
),
MAILINGLIST_ENABLED=_GR.get("MAILINGLIST_ENABLED", False),
POSTMASTER_EMAIL=_GR.get("POSTMASTER_EMAIL", "postmaster@localhost"),
# content import
FEED_IMPORTER_GESTALT_ID=_GR.get("FEED_IMPORTER_GESTALT_ID", None),
OPERATOR_GROUP_ID=_GR.get("OPERATOR_GROUP_ID", 1),
UNKNOWN_GESTALT_ID=_GR.get("UNKNOWN_GESTALT_ID", 1),
# local administration
BACKUP_PATH=_GR.get("BACKUP_PATH", os.getcwd()),
HOOK_SCRIPT_PATHS=_GR.get("HOOK_SCRIPT_PATHS", []),
# miscellaneous
ENTITY_SLUG_BLACKLIST=_GR.get(
"ENTITY_SLUG_BLACKLIST",
[
"all",
"grouprise",
"info",
"mail",
"noreply",
"postmaster",
"reply",
"stadt",
"webmaster",
"www",
],
),
SCORE_CONTENT_AGE=_GR.get("SCORE_CONTENT_AGE", 100),
UPLOAD_MAX_FILE_SIZE=_GR.get("UPLOAD_MAX_FILE_SIZE", 10),
)
SCORE_CONTENT_AGE = _GR.get("SCORE_CONTENT_AGE", 100)
UPLOAD_MAX_FILE_SIZE = _GR.get("UPLOAD_MAX_FILE_SIZE", 10)
import contextlib
import logging
import django.urls
......@@ -8,8 +7,6 @@ from django.contrib.sites import models as sites_models
from django.core import mail
from simplemathcaptcha.utils import hash_answer
import grouprise.core.settings as grouprise_settings
HTTP_GET = 'get'
HTTP_POST = 'post'
......@@ -23,30 +20,6 @@ def get_url(url, *args):
return django.urls.reverse(url, args=args)
@contextlib.contextmanager
def temporary_settings_override(key, value):
""" provide a context for temporarily changing a setting in the GROUPRISE dictionary
This override only works, if the setting is accessed as an attributes of the
grouprise.core.settings module.
Thus direct imports of the values (e.g. "from grouprise.core.settings import FOO") are not
affected by such overrides.
"""
try:
original_value = getattr(grouprise_settings, key)
is_missing = False
except AttributeError:
is_missing = True
setattr(grouprise_settings, key, value)
try:
yield
finally:
if is_missing:
delattr(grouprise_settings, key)
else:
setattr(grouprise_settings, key, original_value)
def with_captcha(data, answer=10, field_name='captcha'):
data.update({
field_name + '_0': answer,
......
......@@ -7,7 +7,7 @@ from django_filters.views import FilterMixin
from rules.contrib.views import PermissionRequiredMixin
import grouprise.core.settings as grouprise_settings
from grouprise.core.settings import CORE_SETTINGS
class PermissionMixin(PermissionRequiredMixin):
......@@ -61,10 +61,10 @@ class Markdown(django.views.generic.TemplateView):
class LogoRedirects(RedirectView):
LOGO_NAME_URL_MAP = {
"backdrop": grouprise_settings.LOGO_BACKDROP,
"favicon": grouprise_settings.LOGO_FAVICON,
"square": grouprise_settings.LOGO_SQUARE,
"text": grouprise_settings.LOGO_TEXT,
"backdrop": CORE_SETTINGS.LOGO_BACKDROP,
"favicon": CORE_SETTINGS.LOGO_FAVICON,
"square": CORE_SETTINGS.LOGO_SQUARE,
"text": CORE_SETTINGS.LOGO_TEXT,
}
def get_redirect_url(self, name):
......
......@@ -2,7 +2,7 @@ import os
from django import forms
from grouprise.core.settings import UPLOAD_MAX_FILE_SIZE
from grouprise.core.settings import CORE_SETTINGS
from grouprise.features.content import forms as content
......@@ -10,7 +10,7 @@ class Create(content.Create):
text = forms.CharField(label='Beschreibung', widget=forms.Textarea({'rows': 2}))
file = forms.FileField(
label='Datei', help_text='Die maximal erlaubte Dateigröße beträgt {} MB.'.format(
UPLOAD_MAX_FILE_SIZE))
CORE_SETTINGS.UPLOAD_MAX_FILE_SIZE))
def save(self, commit=True):
association = super().save(False)
......@@ -27,7 +27,7 @@ class Update(content.Update):
text = forms.CharField(label='Beschreibung', widget=forms.Textarea({'rows': 2}))
file = forms.FileField(
label='Datei', help_text='Die maximal erlaubte Dateigröße beträgt {} MB.'.format(
UPLOAD_MAX_FILE_SIZE))
CORE_SETTINGS.UPLOAD_MAX_FILE_SIZE))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
......
......@@ -2,8 +2,8 @@ import allauth
import django
import grouprise.core
from grouprise.core.settings import CORE_SETTINGS
from grouprise.features.groups import models as groups
from grouprise.features.stadt.forms import ENTITY_SLUG_BLACKLIST
class AccountAdapter(allauth.account.adapter.DefaultAccountAdapter):
......@@ -11,6 +11,6 @@ class AccountAdapter(allauth.account.adapter.DefaultAccountAdapter):
username = super().generate_unique_username(txts, regex)
username = grouprise.core.models.get_unique_slug(
django.contrib.auth.get_user_model(), {'username': username},
reserved_slugs=ENTITY_SLUG_BLACKLIST,
reserved_slugs=CORE_SETTINGS.ENTITY_SLUG_BLACKLIST,
reserved_slug_qs=groups.Group.objects, slug_field_name='username')
return username
......@@ -9,7 +9,7 @@ from imagekit.models import ImageSpecField
from imagekit.processors import SmartResize, Transpose
import grouprise.core
from grouprise.core.settings import UNKNOWN_GESTALT_ID
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.utils import get_random_color
......@@ -82,7 +82,7 @@ class Gestalt(grouprise.core.models.Model):
def delete(self, *args, **kwargs):
data = self.get_data()
unknown_gestalt = Gestalt.objects.get(id=UNKNOWN_GESTALT_ID)
unknown_gestalt = Gestalt.objects.get(id=CORE_SETTINGS.UNKNOWN_GESTALT_ID)
data['associations'].update(entity_id=unknown_gestalt.id)
data['contributions'].update(author=unknown_gestalt)
data['images'].update(creator=unknown_gestalt)
......
......@@ -10,7 +10,7 @@ from imagekit.processors import ResizeToFit, Transpose
from taggit.managers import TaggableManager
import grouprise.core.models
from grouprise.core.settings import OPERATOR_GROUP_ID
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.utils import get_random_color
from grouprise.features.gestalten.models import Gestalt
from grouprise.features.stadt.models import EntitySlugField
......@@ -18,7 +18,7 @@ from grouprise.features.stadt.models import EntitySlugField
class GroupManager(models.Manager):
def operator_group(self):
return self.get_queryset().filter(id=OPERATOR_GROUP_ID).first()
return self.get_queryset().filter(id=CORE_SETTINGS.OPERATOR_GROUP_ID).first()
class Group(grouprise.core.models.Model):
......
......@@ -7,10 +7,9 @@ from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from huey.contrib.djhuey import db_task
from grouprise.core.settings import HOOK_SCRIPT_PATHS
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.utils import slugify
from grouprise.features.gestalten import models as gestalten
from grouprise.features.stadt.forms import ENTITY_SLUG_BLACKLIST
from .models import Group
from ...core.models import get_unique_slug
......@@ -26,7 +25,7 @@ def call_hook_script(event_type: str, group: Group, timeout=300):
"objectData": {"id": group.id, "slug": group.slug},
}
)
for script_name in HOOK_SCRIPT_PATHS:
for script_name in CORE_SETTINGS.HOOK_SCRIPT_PATHS:
try:
subprocess.run(
[script_name, hook_event_info_json],
......@@ -74,7 +73,7 @@ def post_group_save(sender, instance, created, **kwargs):
instance.slug = get_unique_slug(
Group,
{"slug": slugify(instance.name)},
reserved_slugs=ENTITY_SLUG_BLACKLIST,
reserved_slugs=CORE_SETTINGS.ENTITY_SLUG_BLACKLIST,
reserved_slug_qs=gestalten.Gestalt.objects,
reserved_slug_qs_field="user__username",
)
......
......@@ -13,7 +13,7 @@ from django.views.generic.edit import FormView
from django.views.generic.list import MultipleObjectMixin
from django_filters.views import FilterView
from grouprise.core.settings import MAILINGLIST_ENABLED
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.views import PermissionMixin, TemplateFilterMixin
from grouprise.features.associations import models as associations
from grouprise.features.content.filters import ContentFilterSet
......@@ -55,7 +55,7 @@ class Detail(PermissionMixin, TemplateFilterMixin, MultipleObjectMixin, DetailVi
kwargs['feed_url'] = self.request.build_absolute_uri(
reverse('group-feed', args=(self.object.pk,)))
return super().get_context_data(
GROUPRISE_MAILINGLIST_ENABLED=MAILINGLIST_ENABLED,
GROUPRISE_MAILINGLIST_ENABLED=CORE_SETTINGS.MAILINGLIST_ENABLED,
associations=associations,
intro_associations=intro_associations,
intro_gallery=intro_gallery,
......
......@@ -9,7 +9,7 @@ import feedparser
import grouprise.core
from grouprise.core.signals import post_create
from grouprise.core.settings import FEED_IMPORTER_GESTALT_ID
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.templatetags.defaultfilters import html2text
from grouprise.core.utils import slugify
from grouprise.features.associations import models as associations
......@@ -85,8 +85,8 @@ def import_from_feed(feed_url, submitter, target_group):
def run_feed_import_for_groups():
processed_feeds = []
if FEED_IMPORTER_GESTALT_ID is not None:
author = gestalten.Gestalt.objects.get(id=FEED_IMPORTER_GESTALT_ID)
if CORE_SETTINGS.FEED_IMPORTER_GESTALT_ID is not None:
author = gestalten.Gestalt.objects.get(id=CORE_SETTINGS.FEED_IMPORTER_GESTALT_ID)
for group in groups.Group.objects.filter(url_import_feed=True):
if group.url:
request = urllib.request.Request(
......
......@@ -9,7 +9,7 @@ import django.utils.timezone
import html2text
import grouprise.core.models
from grouprise.core.settings import DEFAULT_REPLY_TO_EMAIL
from grouprise.core.settings import CORE_SETTINGS
from grouprise.core.signals import post_create
from grouprise.features.associations import models as associations
from grouprise.features.content.models import Content
......@@ -178,7 +178,7 @@ class ContributionMailProcessor:
def __init__(self, default_reply_to_address=None, response_from_address=None):
if default_reply_to_address is None:
default_reply_to_address = DEFAULT_REPLY_TO_EMAIL
default_reply_to_address = CORE_SETTINGS.DEFAULT_REPLY_TO_EMAIL
if response_from_address is None:
response_from_address = settings.DEFAULT_FROM_EMAIL
self._reply_domain = default_reply_to_address.split("@")[1]
......
......@@ -7,7 +7,7 @@ import sys
from django.core.management.base import BaseCommand
from grouprise.core.settings import COLLECTOR_MAILBOX_ADDRESS
from grouprise.core.settings import CORE_SETTINGS
from grouprise.features.imports.mails import (
ContributionMailProcessor,
MailProcessingFailure,
......@@ -86,9 +86,9 @@ class Command(BaseCommand):
)
)
delivered_to_address = get_normalized_address(match.groups()[0])
if COLLECTOR_MAILBOX_ADDRESS:
if CORE_SETTINGS.COLLECTOR_MAILBOX_ADDRESS:
if (
get_normalized_address(COLLECTOR_MAILBOX_ADDRESS)
get_normalized_address(CORE_SETTINGS.COLLECTOR_MAILBOX_ADDRESS)
== delivered_to_address
):
# The message was delivered to the mailbox configured for collecting all
......@@ -99,7 +99,7 @@ class Command(BaseCommand):
raise ValueError(
"Rejecting the mail, since its envelope address ({}) does not match the "
"expected mailbox address (COLLECTOR_MAILBOX_ADDRESS='{}').".format(
delivered_to_address, COLLECTOR_MAILBOX_ADDRESS
delivered_to_address, CORE_SETTINGS.COLLECTOR_MAILBOX_ADDRESS
)
)
else:
......
......@@ -15,7 +15,7 @@ from aiosmtplib.smtp import SMTP
import django
import django.db
from grouprise.core.settings import POSTMASTER_EMAIL as POSTMASTER_ADDRESS
from grouprise.core.settings import CORE_SETTINGS
from grouprise.features.imports.mails import (
ContributionMailProcessor, MailProcessingFailure, ParsedMailMessage)
......@@ -238,8 +238,8 @@ class ContributionHandler:
err_msg = ''.join(traceback.format_exception(*sys.exc_info()))
self._error_writer('Failed to parse Message:\n{}'.format(err_msg))
django.core.mail.send_mail(
'LMTP Handling Error', err_msg, from_email=POSTMASTER_ADDRESS,
recipient_list=[POSTMASTER_ADDRESS], fail_silently=True)
'LMTP Handling Error', err_msg, from_email=CORE_SETTINGS.POSTMASTER_EMAIL,
recipient_list=[CORE_SETTINGS.POSTMASTER_EMAIL], fail_silently=True)
return '500 Failed to parse incoming message'
success_count = 0
error_messages = []
......@@ -277,7 +277,8 @@ class ContributionHandler:
for recipient, exc in internal_problems)
# inform developers
self._contribution_processor.send_error_mail_response(
parsed_message, problems_text, recipient=POSTMASTER_ADDRESS, fail_silently=True)
parsed_message, problems_text, recipient=CORE_SETTINGS.POSTMASTER_EMAIL,
fail_silently=True)
if success_count > 0:
# Never reject a message that was at least partly processed. Otherwise a
# contribution could be published multiple times - which would be quite annoying
......
......@@ -3,7 +3,7 @@ import datetime
import django.utils.timezone
from grouprise.core import tests
from grouprise.core.tests import temporary_settings_override
from grouprise.core.settings import CORE_SETTINGS
from grouprise.features.associations import models as associations
from grouprise.features.memberships.test_mixins import MemberMixin, OtherMemberMixin
from ..feeds import import_from_feed, parse_feed_url_from_website_content
......@@ -66,7 +66,7 @@ class ImportFeedItems(MemberMixin, OtherMemberMixin, tests.Test):
self.assertEqual(associations.Association.objects.count(), 1)
def test_notifications_all(self):
with temporary_settings_override("FEED_IMPORTER_GESTALT_ID", self.other_gestalt.id):
with CORE_SETTINGS.temporary_override(FEED_IMPORTER_GESTALT_ID=self.other_gestalt.id):
self.assertEqual(associations.Association.objects.count(), 0)
# send a "new" (recent date) feed entry: otherwise its notification is skipped
import_from_feed(self._get_feed_content(date=self._get_now()),
......
......@@ -11,11 +11,10 @@ from django.core import mail
from django.urls import reverse
from grouprise.core import tests
from grouprise.core.settings import DEFAULT_REPLY_TO_EMAIL
from grouprise.core.settings import CORE_SETTINGS
from grouprise.features.associations import models as associations
from grouprise.features.contributions import models
from grouprise.features.imports.management.commands.run_lmtpd import (
ContributionLMTPD, POSTMASTER_ADDRESS)
from grouprise.features.imports.management.commands.run_lmtpd import ContributionLMTPD
from grouprise.features.imports.mails import (
ContributionMailProcessor, ParsedMailMessage, MAGIC_SUBJECT_FOR_INTERNAL_ERROR_TEST)
from grouprise.features.gestalten import tests as gestalten
......@@ -131,9 +130,9 @@ class GroupContentViaLMTP(GroupMailMixin, MailInjectLMTPMixin, tests.Test):
self.assertInvalidRecipient(self.group_address.split('@')[0] + 'example.org')
self.assertValidRecipient(self.group_address)
self.assertValidRecipient(self.group_address.swapcase())
self.assertValidRecipient(DEFAULT_REPLY_TO_EMAIL.format(reply_key='foo'))
self.assertValidRecipient(CORE_SETTINGS.DEFAULT_REPLY_TO_EMAIL.format(reply_key='foo'))
self.assertInvalidRecipient(
DEFAULT_REPLY_TO_EMAIL.replace('+{', '-{').format(reply_key='foo'))
CORE_SETTINGS.DEFAULT_REPLY_TO_EMAIL.replace('+{', '-{').format(reply_key='foo'))
def test_internal_error_mail_handling(self):
with self.fresh_outbox_mails_retriever() as get_new_mails:
......@@ -147,8 +146,8 @@ class GroupContentViaLMTP(GroupMailMixin, MailInjectLMTPMixin, tests.Test):
self.assertEqual(1, len(get_new_mails()))
self.assertIn(MAGIC_SUBJECT_FOR_INTERNAL_ERROR_TEST.swapcase(),
get_new_mails()[0].body)
self.assertListEqual([POSTMASTER_ADDRESS], get_new_mails()[0].recipients(),
get_new_mails()[0])
self.assertListEqual([CORE_SETTINGS.POSTMASTER_EMAIL],
get_new_mails()[0].recipients(), get_new_mails()[0])
def test_reject_initial_contribution_from_non_member(self):
with self.fresh_outbox_mails_retriever() as get_new_mails:
......
from django.core.exceptions import ValidationError