Merge branch 'master' into member_lists

v1-0-stable
Schlabonski 9 years ago
commit d5d8ae4099

2
.gitignore vendored

@ -93,6 +93,8 @@ jdav_web/db.sqlite3
# test images for file upload # test images for file upload
*.jpeg *.jpeg
*.png *.png
jdav_web/media
jdav_web/*/migrations
*.py.swp *.py.swp
# django database migrations # django database migrations

@ -4,3 +4,15 @@ This repository has the purpose to develop a webapplication that can be used by
JDAV to send newsletters, manage user lists and keep material lists up to date. JDAV to send newsletters, manage user lists and keep material lists up to date.
As this repository is also meant to be a base for exchange during development, feel free As this repository is also meant to be a base for exchange during development, feel free
to contribute ideas in form of edits to this README, issues, landmarks, projects, wiki entries, ... to contribute ideas in form of edits to this README, issues, landmarks, projects, wiki entries, ...
# Useful stuff
## Reset database for certain app
The following can be useful in case that automatic migrations throw errors.
1. delete everything in the migrations folder except for __init__.py.
2. drop into my MySQL console and do: DELETE FROM django_migrations WHERE app='my_app'
3. while at the MySQL console, drop all of the tables associated with my_app.
4. re-run ./manage.py makemigrations my_app - this generates a 0001_initial.py file in my migrations folder.
5. run ./manage migrate my_app - I expect this command to re-build all my tables, but instead it says: "No migrations to apply."

@ -37,6 +37,7 @@ INSTALLED_APPS = [
'startpage.apps.StartpageConfig', 'startpage.apps.StartpageConfig',
'material.apps.MaterialConfig', 'material.apps.MaterialConfig',
'members.apps.MembersConfig', 'members.apps.MembersConfig',
'mailer.apps.MailerConfig',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@ -133,3 +134,12 @@ STATIC_URL = '/static/'
# Locale files (translations) # Locale files (translations)
LOCALE_PATHS = (os.path.join(BASE_DIR, 'locale'),) LOCALE_PATHS = (os.path.join(BASE_DIR, 'locale'),)
# Email setup
EMAIL_HOST = 'localhost'
EMAIL_PORT = 25
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False

@ -23,6 +23,7 @@ urlpatterns = static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),
url(r'^newsletter/', include('mailer.urls', namespace="mailer")),
url(r'^$', include('startpage.urls')), url(r'^$', include('startpage.urls')),
) )

@ -0,0 +1,42 @@
from django.contrib import admin
from django.contrib.admin import helpers
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import render
from .models import Message
class MessageAdmin(admin.ModelAdmin):
"""Message creation view"""
list_display = ('subject', 'from_addr', 'get_groups', 'sent')
change_form_template = "mailer/change_form.html"
actions = ['send_message']
def send_message(self, request, queryset):
print("calling send_message")
if request.POST.get('confirmed'):
for msg in queryset:
msg.submit()
self.message_user(request, _("Message sent"))
else:
context = {
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
'mails': queryset,
'ids': queryset.values_list("id"),
'some_sent': any(m.sent for m in queryset)}
return render(request, 'mailer/confirm_send.html', context)
send_message.short_description = _("Send message")
def response_change(self, request, obj):
if "_send" in request.POST:
obj.submit()
return super(MessageAdmin, self).response_change(request, obj)
def response_add(self, request, obj):
if "_send" in request.POST:
obj.submit()
return super(MessageAdmin, self).response_change(request, obj)
admin.site.register(Message, MessageAdmin)

@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class MailerConfig(AppConfig):
name = 'mailer'
verbose_name = _('mailer')

@ -0,0 +1,121 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-19 16:11+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: admin.py:20
msgid "Message sent"
msgstr "Nachricht gesendet"
#: admin.py:28
msgid "Send message"
msgstr "Nachricht verschicken"
#: apps.py:7
msgid "mailer"
msgstr "Verteiler"
#: models.py:9
msgid "from email"
msgstr "Von Email"
#: models.py:10
msgid "subject"
msgstr "Betreff"
#: models.py:11
msgid "content"
msgstr "Inhalt"
#: models.py:12
msgid "to group"
msgstr "An Gruppe"
#: models.py:13
msgid "sent"
msgstr "Gesendet"
#: models.py:29
msgid "message"
msgstr "Nachricht"
#: models.py:30
msgid "messages"
msgstr "Nachrichten"
#: models.py:32
msgid "Can submit mails"
msgstr "Kann Mails verschicken"
#: templates/admin/change_form.html:11
msgid "Save and send mail"
msgstr "Speichern und Email senden"
#: templates/mailer/confirm_send.html:7
msgid "Do you really want to send these mails?"
msgstr "Möchtest du diese Emails wirklich verschicken?"
#: templates/mailer/confirm_send.html:13
msgid "already sent"
msgstr "schon verschickt"
#: templates/mailer/confirm_send.html:19
msgid ""
"Some messages have already been sent! Do you really want to resend them?"
msgstr ""
"Einige Emails wurden schon versendet! Möchtest du diese wirklich nochmal "
"senden?"
#: templates/mailer/confirm_send.html:30
msgid "Send"
msgstr "Senden"
#: templates/mailer/confirm_send.html:35
msgid "Cancel"
msgstr "Abbruch"
#: templates/mailer/index.html:2
msgid "This is the mailer app!"
msgstr "Das ist die Mailer App!"
#: templates/mailer/send.html:2
msgid "Here you can send new emails!"
msgstr "Hier kannst du neue Emails verschicken!"
#: templates/mailer/send.html:11
msgid "Subject:"
msgstr "Betreff"
#: templates/mailer/send.html:14
msgid "Content:"
msgstr "Inhalt:"
#: templates/mailer/send.html:17
msgid "Receiving group:"
msgstr "Erhaltende Gruppe"
#: templates/mailer/send.html:24
msgid "Send mail"
msgstr "Email senden"
#: views.py:33
msgid "Please fill in every field!"
msgstr "Bitte jedes Feld ausfüllen!"
#~ msgid "History"
#~ msgstr "Geschichte"

@ -0,0 +1,43 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.mail import send_mass_mail
# Create your models here.
class Message(models.Model):
"""Represents a message that can be sent to some members"""
from_addr = models.EmailField(_('from email'))
subject = models.CharField(_('subject'), max_length=50)
content = models.TextField(_('content'))
to_groups = models.ManyToManyField('members.Group',
verbose_name=_('to group'))
sent = models.BooleanField(_('sent'), default=False)
def __str__(self):
return self.subject
def get_groups(self):
return ", ".join([g.name for g in self.to_groups.all()])
get_groups.short_description = _('recipicients')
def submit(self):
"""Sends the mail to the specified group of members"""
members = set()
for group in self.to_groups.all():
group_members = group.member_set.all()
for member in group_members:
members.add(member)
data = [
(self.subject, self.content, self.from_addr, [member.email])
for member in members
]
send_mass_mail(data)
self.sent = True
self.save()
class Meta:
verbose_name = _('message')
verbose_name_plural = _('messages')
permissions = (
("submit_mails", _("Can submit mails")),
)

@ -0,0 +1,15 @@
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block content %}
{{ block.super }}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'mailer/change_style.css' %}" />
<script type="text/javascript">
(function($){
$('<input type="submit" value="{% trans 'Save and send mail' %}" name="_send" class="send_mail"/>')
.prependTo('div.submit-row');
})(django.jQuery);
</script>
{% endblock %}

@ -0,0 +1,38 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load static %}
{% block content %}
<link rel="stylesheet" type="text/css" href="{% static 'admin/style.css' %}" />
<p>{% trans "Do you really want to send these mails?" %}</p>
<ul>
{% for mail in mails %}
<li>
{{mail.subject}}
{% if mail.sent %}
({% trans "already sent" %})
{%endif %}
</li>
{% endfor %}
</ul>
{% if some_sent %}
<p><b>{% trans "Some messages have already been sent! Do you really want to resend them?" %}</b></p>
{% endif %}
<form action="" method="post">
{% csrf_token %}
<input type="hidden" name="confirmed" value="yes">
<input type="hidden" name="action" value="send_message">
{% for id in ids %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ id.0 }}">
{% endfor %}
<input type="submit" value={% trans "Send" %}>
</form>
<form action="" method="post" class="cancel">
{% csrf_token %}
<input type="submit" value={% trans "Cancel" %}>
</form>
{% endblock %}

@ -0,0 +1,3 @@
{% load i18n %}
{% trans "This is the mailer app!" %}
<p><a href={% url 'mailer:send' %}>New Mail</a></p>

@ -0,0 +1,25 @@
{% load i18n %}
{% trans "Here you can send new emails!" %}
{% if error_message %}
<p><b>{{ error_message }}</b></p>
{% endif %}
<form action="{% url 'mailer:send_mail' %}" method="post">
{% csrf_token %}
{% trans "Subject:" %}<br>
<input type="text" name="subject"><br>
{% trans "Content:" %}<br>
<textarea rows="10" cols="80" name="content"></textarea><br>
{% trans "Receiving group:" %}<br>
<select name="to_group">
{% for group in groups %}
<option value="{{ group.id }}">{{ group.name }}</option>
{% endfor %}
</select><br>
<input type="submit" value="{% trans "Send mail" %}">
</form>

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,10 @@
from django.conf.urls import url
from . import views
app_name = "mailer"
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^send_mail', views.send_mail, name='send_mail'),
url(r'^send', views.send, name='send')
]

@ -0,0 +1,40 @@
from django.shortcuts import render
from django.utils.translation import ugettext_lazy as _
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import permission_required
from members.models import Group
from .models import Message
@permission_required('mailer.submit_mails', login_url='/admin/')
def index(request):
"""This is the main newsletter view"""
return render(request, 'mailer/index.html')
@permission_required('mailer.submit_mails', login_url='/admin/')
def send(request):
return render(request, 'mailer/send.html', {
'groups': Group.objects.all()
})
@permission_required('mailer.submit_mails', login_url='/admin/')
def send_mail(request):
try:
subject = request.POST['subject']
content = request.POST['content']
to_group = Group.objects.get(pk=request.POST['to_group'])
except (KeyError, Group.DoesNotExist):
return render(request, 'mailer/send.html', {
'error_message': _("Please fill in every field!"),
'groups': Group.objects.all()
})
else:
msg = Message(subject=subject, content=content, to_group=to_group)
msg.submit()
msg.save()
return HttpResponseRedirect(reverse('mailer:index'))

@ -1,4 +1,6 @@
from django.contrib import admin from django.contrib import admin
from django.utils. translation import ugettext_lazy as translate
from django.contrib.admin import SimpleListFilter
from .models import MaterialPart, Ownership from .models import MaterialPart, Ownership
@ -13,10 +15,30 @@ class OwnershipInline(admin.StackedInline):
extra = 0 extra = 0
class NotTooOldFilter(SimpleListFilter):
title = translate('Age')
parameter_name = 'age'
def lookups(self, request, model_admin):
return (
('too_old', translate('Not Too Old')),
('not_too_old', translate('Too old')),
)
def queryset(self, request, queryset):
if self.value() == 'too_old':
return queryset.filter(pk__in=[x.pk for x in queryset.all() if x.not_too_old()])
if self.value() == 'not_too_old':
return queryset.filter(pk__in=[x.pk for x in queryset.all() if not x.not_too_old()])
class MaterialAdmin(admin.ModelAdmin): class MaterialAdmin(admin.ModelAdmin):
"""Edit view of a MaterialPart""" """Edit view of a MaterialPart"""
list_display = ('name', 'buy_date', 'lifetime', 'not_too_old', 'photo') list_display = ('name', 'buy_date', 'lifetime', 'not_too_old', 'photo')
inlines = [OwnershipInline] inlines = [OwnershipInline]
list_filter = (NotTooOldFilter,)
admin.site.register(MaterialPart, MaterialAdmin) admin.site.register(MaterialPart, MaterialAdmin)

@ -0,0 +1,38 @@
[
{
"model": "material.MaterialPart",
"pk": "1",
"fields": {
"name": "Seil 40m grün",
"buy_date": "2016-01-01",
"lifetime": "3"
}
},
{
"model": "material.MaterialPart",
"pk": "2",
"fields": {
"name": "Seil 40m blau",
"buy_date": "2012-01-01",
"lifetime": "3"
}
},
{
"model": "material.MaterialPart",
"pk": "3",
"fields": {
"name": "Seil 60m gelb",
"buy_date": "2013-01-01",
"lifetime": "3"
}
},
{
"model": "material.MaterialPart",
"pk": "4",
"fields": {
"name": "Seil 60m blau",
"buy_date": "2016-01-01",
"lifetime": "3"
}
}
]

@ -1,3 +1,3 @@
Django==1.10.2 Django==1.10.2
Pillow==3.4.2
mysqlclient==1.3.9 mysqlclient==1.3.9
PyMySQL==0.7.9

Loading…
Cancel
Save