Repository: liqd/a4-product

Issue:
Registration: Confirmation email text & language
There are a couple of spelling and language mistakes in the confirmation email:

- parts of the texts are in German (registration happened in Safari (German) others are in english
- wrong support email address
- links to "contact" and "terms of use" working but no respective static pages ye
- space missing before Liquid Democracy e.V.

"Diese E-Mail wurde an r.brues+1@liqd.net gesendet. Wenn Sie sich nicht registriert haben können Sie diese E-Mail ignorieren. Wir werden Ihnen keine weiteren E-Mail senden. Falls Sie weitere Fragen haben, wenden Sie sich bitte an uns unter support-berlin@liqd.de_LIQD_PRODUCT_ is a participation platform operated byLiquid Democracy e.V., Am Sudhaus 2, D-12053 Berlin"





Discussion:
closed with #133 

Resolving patch:
diff --git a/liqd_product/apps/partners/templatetags/partners_tags.py b/liqd_product/apps/partners/templatetags/partner_tags.py
similarity index 100%
rename from liqd_product/apps/partners/templatetags/partners_tags.py
rename to liqd_product/apps/partners/templatetags/partner_tags.py
diff --git a/liqd_product/config/settings/base.py b/liqd_product/config/settings/base.py
--- a/liqd_product/config/settings/base.py
+++ b/liqd_product/config/settings/base.py
@@ -79,6 +79,7 @@
     'meinberlin.apps.contrib.apps.Config',
     'meinberlin.apps.maps.apps.Config',
     'meinberlin.apps.moderatorfeedback.apps.Config',
+    'meinberlin.apps.notifications.apps.Config',
 
     # General apps containing views
     'liqd_product.apps.account.apps.Config',
@@ -332,7 +333,6 @@
     ('meinberlin_mapideas', 'mapidea'),
 )
 
-
 A4_CATEGORIZABLE = (
     ('meinberlin_ideas', 'idea'),
     ('meinberlin_mapideas', 'mapidea'),
diff --git a/liqd_product/config/urls.py b/liqd_product/config/urls.py
--- a/liqd_product/config/urls.py
+++ b/liqd_product/config/urls.py
@@ -73,7 +73,10 @@
     # Urls within the context of a partner
     partner_patterns(
         url(r'^modules/', include('adhocracy4.modules.urls')),
-        url(r'^projects/', include('adhocracy4.projects.urls')),
+        # Temporary include meinberlin projects urls, as they contain
+        # the invite links. This may be removed when invites are refactored
+        # to a separate app.
+        url(r'^projects/', include('meinberlin.apps.projects.urls')),
         url(r'^offlineevents/', include('meinberlin.apps.offlineevents.urls',
                                         namespace='meinberlin_offlineevents')),
         url(r'^ideas/', include(r'meinberlin.apps.ideas.urls',


Test patch:
diff --git a/liqd_product/apps/contrib/management/commands/send_product_test_emails.py b/liqd_product/apps/contrib/management/commands/send_product_test_emails.py
new file mode 100644
--- /dev/null
+++ b/liqd_product/apps/contrib/management/commands/send_product_test_emails.py
@@ -0,0 +1,206 @@
+from django.conf import settings
+from django.contrib.auth import get_user_model
+from django.contrib.contenttypes.models import ContentType
+from django.core.management.base import BaseCommand
+
+from adhocracy4.actions.models import Action
+from adhocracy4.actions.verbs import Verbs
+from adhocracy4.comments.models import Comment
+from adhocracy4.emails.mixins import SyncEmailMixin
+from adhocracy4.projects.models import Project
+from adhocracy4.reports import emails as reports_emails
+from adhocracy4.reports.models import Report
+from meinberlin.apps.contrib.emails import Email
+from meinberlin.apps.ideas.models import Idea
+from meinberlin.apps.notifications import emails as notification_emails
+from meinberlin.apps.projects import models as project_models
+
+User = get_user_model()
+
+
+class TestEmail(SyncEmailMixin, Email):
+    def get_receivers(self):
+        return self.kwargs['receiver']
+
+    def dispatch(self, object, *args, **kwargs):
+        self.template_name = kwargs.pop('template_name')
+        print('Sending template: {} with object "{}"'.format(
+            self.template_name,
+            str(object)))
+        super().dispatch(object, *args, **kwargs)
+
+    def get_context(self):
+        context = super().get_context()
+        context['project'] = getattr(self.object, 'project', None)
+        context['contact_email'] = settings.CONTACT_EMAIL
+        return context
+
+
+class Command(BaseCommand):
+    help = 'Send test emails to a registered user.'
+
+    def add_arguments(self, parser):
+        parser.add_argument('email')
+
+    def handle(self, *args, **options):
+        self.user = User.objects.get(email=options['email'])
+
+        self._send_notifications_create_idea()
+        self._send_notifications_comment_idea()
+        self._send_notification_phase()
+        self._send_notification_project_created()
+
+        self._send_report_mails()
+
+        self._send_allauth_email_confirmation()
+        self._send_allauth_password_reset()
+
+        self._send_invitation_private_project()
+        self._send_invitation_moderator()
+
+    def _send_notifications_create_idea(self):
+        # Send notification for a newly created item
+        action = Action.objects.filter(
+            verb=Verbs.ADD.value,
+            obj_content_type=ContentType.objects.get_for_model(Idea)
+        ).exclude(project=None).first()
+        if not action:
+            self.stderr.write('At least one idea is required')
+            return
+
+        self._send_notify_create_item(action)
+
+    def _send_notifications_comment_idea(self):
+        # Send notifications for a comment on a item
+        action = Action.objects.filter(
+            verb=Verbs.ADD.value,
+            obj_content_type=ContentType.objects.get_for_model(Comment),
+            target_content_type=ContentType.objects.get_for_model(Idea)
+        ).exclude(project=None).first()
+        if not action:
+            self.stderr.write('At least one idea with a comment is required')
+            return
+
+        self._send_notify_create_item(action)
+
+    def _send_notify_create_item(self, action):
+        TestEmail.send(
+            action,
+            receiver=[self.user],
+            template_name=notification_emails.
+            NotifyCreatorEmail.template_name)
+
+        TestEmail.send(
+            action,
+            receiver=[self.user],
+            template_name=notification_emails.
+            NotifyFollowersOnNewItemCreated.template_name)
+
+        TestEmail.send(
+            action,
+            receiver=[self.user],
+            template_name=notification_emails.
+            NotifyModeratorsEmail.template_name)
+
+    def _send_notification_phase(self):
+        action = Action.objects.filter(
+            verb=Verbs.SCHEDULE.value
+        ).first()
+        if not action:
+            self.stderr.write('Schedule action is missing')
+            return
+
+        TestEmail.send(
+            action,
+            receiver=[self.user],
+            template_name=notification_emails.
+            NotifyFollowersOnPhaseIsOverSoonEmail.template_name
+        )
+
+    def _send_notification_project_created(self):
+        project = Project.objects.first()
+        TestEmail.send(
+            project,
+            project=project,
+            creator=self.user,
+            receiver=[self.user],
+            template_name=notification_emails.
+            NotifyInitiatorsOnProjectCreatedEmail.template_name
+        )
+
+    def _send_report_mails(self):
+        report = Report.objects.first()
+        if not report:
+            self.stderr.write('At least on report is required')
+            return
+
+        TestEmail.send(
+            report,
+            receiver=[self.user],
+            template_name=reports_emails.ReportCreatorEmail.template_name
+        )
+
+        TestEmail.send(
+            report,
+            receiver=[self.user],
+            template_name=reports_emails.ReportModeratorEmail.template_name
+        )
+
+    def _send_allauth_password_reset(self):
+        context = {"current_site": 'http://example.com/...',
+                   "user": self.user,
+                   "password_reset_url": 'http://example.com/...',
+                   "request": None,
+                   "username": self.user.username}
+
+        TestEmail.send(self.user,
+                       receiver=[self.user],
+                       template_name='account/email/password_reset_key',
+                       **context
+                       )
+
+    def _send_allauth_email_confirmation(self):
+        context = {
+            "user": self.user,
+            "activate_url": 'http://example.com/...',
+            "current_site": 'http://example.com/...',
+            "key": 'the1454key',
+        }
+
+        TestEmail.send(
+            self.user,
+            receiver=[self.user],
+            template_name='account/email/email_confirmation_signup',
+            **context
+        )
+
+        TestEmail.send(
+            self.user,
+            receiver=[self.user],
+            template_name='account/email/email_confirmation',
+            **context
+        )
+
+    def _send_invitation_private_project(self):
+        invite = project_models.ParticipantInvite.objects.first()
+        if not invite:
+            self.stderr.write('At least one participant request is required')
+            return
+
+        TestEmail.send(
+            invite,
+            receiver=[self.user],
+            template_name='meinberlin_projects/emails/invite_participant'
+        )
+
+    def _send_invitation_moderator(self):
+        invite = project_models.ModeratorInvite.objects.first()
+        if not invite:
+            self.stderr.write('At least one moderator request is required')
+            return
+
+        TestEmail.send(
+            invite,
+            receiver=[self.user],
+            template_name='meinberlin_projects/emails/invite_moderator'
+        )