PK r+Jv plugs_newsletter/views.py""" Newsletter views """ from django.utils.translation import ugettext_lazy as _ from django.shortcuts import get_object_or_404 from rest_framework import viewsets from rest_framework import status from rest_framework.response import Response from rest_framework import permissions from rest_framework.decorators import api_view, permission_classes from plugs_newsletter import models from plugs_newsletter import serializers from plugs_newsletter import signals @api_view(['POST']) @permission_classes([permissions.AllowAny]) def subscribe(request): """ Subscribe newsletter """ serializer = serializers.SubscriptionSerializer(data=request.data) serializer.is_valid(raise_exception=True) subscription = serializer.save() subscription.send_subscribed_email() signals.email_added_to_newsletter.send(sender=subscription) data = {"message": _("Subscribed successfuly.")} return Response(data=data, status=status.HTTP_201_CREATED) @api_view(['POST']) @permission_classes([permissions.AllowAny]) def unsubscribe(request): """ Unsubscribe from the newsletter """ kwargs = {'email': request.data.get('email')} subscription = get_object_or_404(models.Subscription, **kwargs) signals.email_removed_from_newsletter.send(sender=subscription) subscription.delete() subscription.send_unsubscribed_email() data = {"message": _("Unsubscribed successfuly from the newsletter")} return Response(data=data, status=status.HTTP_200_OK) PK z+J6 plugs_newsletter/serializers.py""" Newsletter Serializers """ from rest_framework import serializers from plugs_newsletter import models class SubscriptionSerializer(serializers.ModelSerializer): """ Subscription Serializer """ # pylint: disable=R0903 class Meta: """ Metaclass definition """ model = models.Subscription fields = ('id', 'email', 'first_name', 'last_name', 'created', 'updated') PK r+Ja plugs_newsletter/signals.py""" Plugs Newsletter Signals """ from django.dispatch import Signal # sent when an email was added to the newsletter email_added_to_newsletter = Signal() # sent when an email was removed from the newsletter email_removed_from_newsletter = Signal() PK +J" plugs_newsletter/models.py""" Plugs Newsletter Models """ from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from django.conf import settings from django.db import models from django.utils.translation import ugettext_lazy as _ from django.contrib.auth import get_user_model from django.db import IntegrityError, transaction from plugs_newsletter.settings import plugs_newsletter_settings from plugs_core import mixins from plugs_mail.utils import to_email from plugs_newsletter import emails class Subscription(mixins.Timestampable, models.Model): """ Newsletter subscription """ error_msgs = {'unique': _('This email is already registered.')} email = models.EmailField(unique=True, error_messages=error_msgs) first_name = models.CharField(max_length=35, null=True) last_name = models.CharField(max_length=35, null=True) def __str__(self): return self.email def send_subscribed_email(self): """ Send newsletter subscribed successfuly to subscriber """ to_email(emails.NewsletterSubscribed, self.email) def send_unsubscribed_email(self): """ Send newsletter unsubscribed successfuly to subscriber """ to_email(emails.NewsletterUnsubscribed, self.email) # pylint: disable=R0903 class Meta: """ Providing verbose names is recommended if we want to use i18n in admin site """ verbose_name = _('subscription') verbose_name_plural = _('subscriptions') @receiver(post_save, sender=settings.AUTH_USER_MODEL) def update_newsletter_settings(instance, created, **kwargs): """ Every time the user is saved we need to check the newsletter flag and update it accordingly """ send_newsletter = getattr(instance, plugs_newsletter_settings['NEWSLETTER_ENDPOINT']) if send_newsletter: kwargs = { 'email': instance.email, 'first_name': instance.first_name, 'last_name': instance.last_name } try: with transaction.atomic(): subscription = Subscription.objects.create(**kwargs) except IntegrityError: pass else: try: subscription = Subscription.objects.get(email=instance.email) subscription.delete() except Subscription.DoesNotExist: pass @receiver(post_save, sender=Subscription) def update_user_settings_start(instance, **kwargs): """ Every time a newsletter subscription occurs update user settings if the subscriber is a user """ try: user = get_user_model().objects.get(email=instance.email) setattr(user, plugs_newsletter_settings['AUTH_MODEL_NEWSLETTER_FIELD'], True) user.save() except get_user_model().DoesNotExist: pass @receiver(post_delete, sender=Subscription) def update_user_settings_stop(instance, **kwargs): """ Every time a newsletter unsubscription occurs update user settings if the subscriber is a user """ try: user = get_user_model().objects.get(email=instance.email) setattr(user, plugs_newsletter_settings['AUTH_MODEL_NEWSLETTER_FIELD'], False) user.save() except get_user_model().DoesNotExist: pass PK HJ^x plugs_newsletter/__init__.py__version__ = '0.1.4' PK z+JAA plugs_newsletter/admin.pyfrom django.contrib import admin from plugs_newsletter.models import Subscription class SubscriptionAdmin(admin.ModelAdmin): """ Subscription Model Admin """ fields = ('email', 'first_name', 'last_name', 'created', 'updated') readonly_fields = ('id', 'created', 'updated') list_display = ('email', 'first_name', 'last_name') search_fields = ('email', 'first_name', 'last_name') admin.site.register(Subscription, SubscriptionAdmin) PK z+JP plugs_newsletter/emails.py""" Plugs Newsletter Emails """ from plugs_mail.mail import PlugsMail class NewsletterSubscribed(PlugsMail): """ Email sent to subscriber after newsletter subscription """ template = 'NEWSLETTER_SUBSCRIBED' description = 'Email sent to subscriber after newsletter subscription' class NewsletterUnsubscribed(PlugsMail): """ Email sent to subscriber after newsletter unsubscription """ template = 'NEWSLETTER_UNSUBSCRIBED' description = 'Email sent to subscriber after newsletter unsubscription' PK z+J$co o plugs_newsletter/urls.py""" Newsletter APP urls """ from django.conf.urls import url from plugs_newsletter import views from plugs_newsletter.settings import plugs_newsletter_settings endpoint = plugs_newsletter_settings['NEWSLETTER_ENDPOINT'] urlpatterns = [ url(r'^' + endpoint + r'/subscribe/$', views.subscribe), url(r'^' + endpoint + r'/unsubscribe/$', views.unsubscribe) ] PK +J^16 6 plugs_newsletter/settings.py""" Newsletter APP Settings """ from django.conf import settings PROJECT_SETTINGS = getattr(settings, 'PLUGS_NEWSLETTER', {}) DEFAULTS = { 'NEWSLETTER_ENDPOINT': 'newsletter', 'AUTH_MODEL_NEWSLETTER_FIELD': 'newsletter' } if not PROJECT_SETTINGS.get('NEWSLETTER_ENDPOINT'): PROJECT_SETTINGS['NEWSLETTER_ENDPOINT'] = DEFAULTS['NEWSLETTER_ENDPOINT'] if not PROJECT_SETTINGS.get('AUTH_MODEL_NEWSLETTER_FIELD'): PROJECT_SETTINGS['AUTH_MODEL_NEWSLETTER_FIELD'] = DEFAULTS['AUTH_MODEL_NEWSLETTER_FIELD'] plugs_newsletter_settings = PROJECT_SETTINGS PK z+Ji; plugs_newsletter/runtests.py#!/usr/bin/env python import os import sys import django from django.conf import settings from django.test.utils import get_runner if __name__ == "__main__": os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_settings' django.setup() TestRunner = get_runner(settings) test_runner = TestRunner() failures = test_runner.run_tests(["tests"]) sys.exit(bool(failures)) PK z+J$!H H ' plugs_newsletter/tests/test_settings.pySECRET_KEY = 'afakesecret' INSTALLED_APPS = [ "plugs_newsletter", ] PK z+JqK32 * plugs_newsletter/tests/test_serializers.py""" Tests Serializers """ from django.test import TestCase from plugs_newsletter import serializers class TestSerializers(TestCase): """ Tests Serializers """ def test_email_is_required_to_subscribe(self): """ Ensures email is required in subscription serializer """ serializer = serializers.SubscriptionSerializer(data={}) self.assertFalse(serializer.is_valid()) self.assertIn('email', serializer.errors.keys()) def test_subscription_serializer(self): """ Ensures subscription serializer """ data = {'email': 'janedoe@example.com', 'first_name': 'Jane', 'last_name': 'Doe'} serializer = serializers.SubscriptionSerializer(data=data) self.assertTrue(serializer.is_valid()) self.assertEqual(serializer.validated_data, data) self.assertEqual(serializer.errors, {}) PK z+Ju%= $ plugs_newsletter/tests/test_views.py""" Testing Views """ from rest_framework.test import APIRequestFactory from plugs_core.testcases import PlugsAPITestCase from plugs_newsletter import views factory = APIRequestFactory() class TestsViews(PlugsAPITestCase): """ Testing Views """ def test_subscribe_using_valid_email(self): """ Ensures guest can subscribe with valid email """ request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.subscribe(request) self.assert201(response) def test_subscribe_using_valid_email(self): """ Ensures guest can subscribe with valid email """ request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.subscribe(request) self.assert201(response) def test_cannot_subscribe_twice_with_same_email(self): """ Ensures cannot subscribe twice with same email """ request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.subscribe(request) self.assert201(response) request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.subscribe(request) self.assert400(response) def test_can_unsubscribe(self): """ Ensures guest can unsubscribe """ request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.subscribe(request) self.assert201(response) request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.unsubscribe(request) self.assert200(response) def test_cannot_unsubscribe(self): """ Ensures guest cannot unsubscribe """ request = factory.post('', data={'email': 'janedoe@example.com'}) response = views.unsubscribe(request) self.assert404(response) PK z+J " plugs_newsletter/tests/__init__.pyPK z+J ' plugs_newsletter/migrations/__init__.pyPK z+J̷r' ' + plugs_newsletter/migrations/0001_initial.py# -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-12-22 17:59 from __future__ import unicode_literals from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Subscription', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateTimeField(auto_now_add=True)), ('updated', models.DateTimeField(auto_now=True)), ('email', models.EmailField(error_messages={'unique': 'This email is already registered.'}, max_length=254, unique=True)), ('first_name', models.CharField(max_length=35, null=True)), ('last_name', models.CharField(max_length=35, null=True)), ], options={ 'verbose_name': 'subscription', 'verbose_name_plural': 'subscriptions', }, ), ] PK z+J0t ? plugs_newsletter/templates/emails/newsletter_subscribed_en.htmlEmail successfully added to the newsletter {% extends "base.html" %} {% block content %}
Email successfully added to the newsletter.
{% endblock %} PK z+Jm m A plugs_newsletter/templates/emails/newsletter_unsubscribed_pt.htmlEmail removido da newsletter {% extends "base.html" %} {% block content %}Removido
{% endblock %} PK z+J헐 A plugs_newsletter/templates/emails/newsletter_unsubscribed_en.htmlEmail successfully removed from the newsletter {% extends "base.html" %} {% block content %}Email successfully removed from the newsletter
{% endblock %} PK z+J= ? plugs_newsletter/templates/emails/newsletter_subscribed_pt.htmlEmail adicionado à newsletter {% extends "base.html" %} {% block content %}Email adicionado com sucesso à nossa newsletter.
{% endblock %} PK 'HJq{# 0 plugs_newsletter-0.1.4.dist-info/DESCRIPTION.rst============================= Plugs Newsletter ============================= .. image:: https://badge.fury.io/py/plugs-newsletter.png :target: https://badge.fury.io/py/plugs-newsletter .. image:: https://travis-ci.org/ricardolobo/plugs-newsletter.png?branch=master :target: https://travis-ci.org/ricardolobo/plugs-newsletter n Documentation ------------- The full documentation is at https://plugs-newsletter.readthedocs.io. Quickstart ---------- Install Plugs Newsletter:: pip install plugs-newsletter Add it to your `INSTALLED_APPS`: .. code-block:: python INSTALLED_APPS = ( ... 'plugs_newsletter.apps.PlugsNewsletterConfig', ... ) Add Plugs Newsletter's URL patterns: .. code-block:: python from plugs_newsletter import urls as plugs_newsletter_urls urlpatterns = [ ... url(r'^', include(plugs_newsletter_urls)), ... ] Features -------- * TODO Running Tests ------------- Does the code actually work? :: source