nalodeni.pirati.cz/nalodeni/news.py

624 lines
19 KiB
Python

# -*- encoding: utf-8 -*-
from datetime import date, datetime, timedelta # timeSlices
from collections import OrderedDict
import django
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect, resolve_url
from django.template import Template, RequestContext, loader
from django.template.loader import render_to_string
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from django.views.decorators.csrf import ensure_csrf_cookie
from django.forms import ModelForm
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import pgettext, pgettext_lazy
from django.db import transaction
from django.db.models import F
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
import logging
import bleach
import html2text
from django.conf import settings as appSettings
from . import models
from . import forms
from . import auth as nalodeni_auth
# Logger instance
logger = logging.getLogger(__name__)
def role_required(roles=[]):
def decorate(func):
def call(request, *args, **kwargs):
for r in roles:
if not r in request.session['site_perms']:
messages.error(request, "Nedostatečné oprávnění pro přístup. Detaily byly zaznamenány.")
return HttpResponseRedirect('/')
result = func(request, *args, **kwargs)
return result
return call
return decorate
@ensure_csrf_cookie
#@login_required(login_url="/prihlaseni")
#@role_required(['sso_news_list'])
def news_all(request):
newsletters = models.Newsletter.objects.filter(is_del=False)
site_perms = request.session.get('site_perms',[])
actions = set()
if 'sso_news_manage' in site_perms:
actions.add('add_news_list')
actions.add('news_list_actions')
actions.add('news_list_details')
if 'sso_kodo' in site_perms:
actions.add('news_list_details')
if len(actions) == 0:
newsletters = newsletters.filter(enabled=True)
template = 'news/list.html'
context = {
'newsletters' : newsletters,
'actions' : actions,
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
@role_required(['sso_news_list'])
def list_edit(request, lid=None):
if lid is not None:
obj = models.Newsletter.objects.filter(pk=lid, is_del=False)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
else:
1/0
else:
obj = None
site_perms = request.session.get('site_perms',[])
passed = False
if (obj is not None and request.user == obj.managed_by) or 'sso_news_manage' in site_perms:
passed = True
if not passed:
messages.error(request, _('Nedostatečné oprávnění.'))
return redirect('nalodeni:news_all')
if request.method == 'GET':
form = forms.NewsletterForm(instance=obj)
elif request.method == 'POST':
form = forms.NewsletterForm(request.POST, instance=obj)
if form.is_valid():
if request.POST.get('del_item', 'ne') == "ano":
form.instance.is_del = True
form.instance.save()
messages.info(request, "Záznam byl smazán.")
return redirect('nalodeni:news_all')
form.save()
messages.info(request, "Údaje byly uloženy.")
return redirect('nalodeni:news_all')
template = 'news/list_edit.html'
context = {
'form' : form,
'regions' : models.InterestRegion.objects.all(),
'topics' : models.UserTopic.objects.all(),
'skills' : models.UserSkill.objects.all(),
}
return render(request, template, context)
@ensure_csrf_cookie
def list_show(request, lid):
"""
Seznam zpráv pro daný newsletter.
"""
obj = models.Newsletter.objects.filter(pk=lid, is_del=False)
if len(obj) == 1:
obj=obj[0]
else:
return redirect('nalodeni:news_all')
site_perms = request.session.get('site_perms',[])
actions = set()
if (request.user == obj.managed_by or 'sso_news_manage' in site_perms):
actions.add('nwsl_edit')
actions.add('nwsl_send_custom')
if (request.user in obj.sent_by.all() or request.user == obj.managed_by
or 'sso_news_manage' in site_perms):
actions.add('nwsl_details')
actions.add('nwsl_actions')
if 'sso_news_list_recipients' in site_perms:
actions.add('show_newsletter_recipients')
msgs = obj.newsmsg_set.filter(is_del=False)
if 'nwsl_actions' not in actions:
msgs = msgs.exclude(sent_ts=None)
template = 'news/list_show.html'
context = {
'obj' : obj,
'msgs' : msgs,
'actions' : actions,
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
@role_required(['sso_news_list_recipients'])
def list_show_recipients(request, lid):
"""
Seznam příjemců pro daný newsletter.
"""
obj = models.Newsletter.objects.filter(pk=lid, is_del=False)
if len(obj) == 1:
obj=obj[0]
else:
return redirect('nalodeni:news_all')
site_perms = request.session.get('site_perms',[])
actions = set()
if not (request.user in obj.sent_by.all() or request.user == obj.managed_by
or 'sso_news_manage' in site_perms):
messages.error(request, _('Nedostatečné oprávnění.'))
return redirect('nalodeni:news_all')
recipients = obj.get_recip_users()
recipients_cnt = len(recipients)
template = 'news/list_show_recipients.html'
context = {
'obj' : obj,
'msgs' : obj.newsmsg_set.filter(is_del=False),
'recipients' : recipients,
'recipients_cnt' : recipients_cnt,
'actions' : actions,
}
return render(request, template, context)
@ensure_csrf_cookie
def msg_show(request, mid):
"""
Detail zpravy newsletteru.
"""
obj = models.NewsMsg.objects.filter(pk=mid,is_del=False)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
messages.error("Objekt nenalezen.")
return redirect('nalodeni:news_all')
else:
1/0
site_perms = request.session.get('site_perms',[])
actions = set()
passed = False
if (request.user in obj.news.sent_by.all()
or request.user == obj.news.managed_by
or 'sso_news_manage' in site_perms):
actions.add('nwsl_actions')
passed = True
# zobrazit jiz odeslanou zpravu
if obj.sent_ts is not None:
passed = True
if not passed:
messages.error(request, _('Zpráva neexistuje, nebo nemáte dostatečné oprávnění k jejímu zobrazení.'))
return redirect('nalodeni:news_all')
template = 'news/msg_show.html'
context = {
'msg' : obj,
'blocks' : obj.newsmsgblock_set.all(),
'actions' : actions,
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
def msg_edit(request, lid, mid=None):
"""
Seznam zpráv pro daný newsletter.
"""
if mid is not None:
obj = models.NewsMsg.objects.filter(pk=mid, is_del=False)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
return redirect('nalodeni:news_msg_create', lid=lid)
else:
1/0
else:
obj = None
if obj is None:
obj = models.NewsMsg(news_id=lid)
site_perms = request.session.get('site_perms',[])
actions = set()
if not (request.user in obj.news.sent_by.all()
or request.user == obj.news.managed_by
or 'sso_news_manage' in site_perms):
messages.error(request, _('Nedostatečné oprávnění pro vytvoření zprávy.'))
return redirect('nalodeni:news_all')
if request.method == 'GET':
form = forms.NewsMsgForm(instance=obj)
elif request.method == 'POST':
form = forms.NewsMsgForm(request.POST, instance=obj)
if form.is_valid():
form.instance.created_by = request.user
form.instance.created_ts = datetime.now()
if request.POST.get('del_item', 'ne') == "ano":
form.instance.is_del = True
form.instance.save()
messages.info(request, "Záznam byl smazán.")
return redirect('nalodeni:news_list_show', lid=lid)
form.instance.headerText = bleach.clean(form.instance.headerText,
tags=['b','ul','ol','li','a','i','hr','br'], strip=True)
form.instance.footerText = bleach.clean(form.instance.footerText,
tags=['b','ul','ol','li','a','i','hr','br'], strip=True)
form.instance.headerText = bleach.linkify(form.instance.headerText)
form.instance.footerText = bleach.linkify(form.instance.footerText)
form.save()
messages.info(request, "Údaje byly uloženy.")
return redirect('nalodeni:news_msg_show', mid=form.instance.id)
template = 'news/msg_edit.html'
context = {
'form' : form,
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
def msg_send_custom(request, id):
custom_recip=set()
if request.method == "POST":
form = forms.CustomRecipientsForm(request.POST)
if form.is_valid():
all_ok = True
for addr in form.cleaned_data['recipients'].replace("\n",",").split(","):
addr = addr.strip()
try:
validate_email(addr)
custom_recip.update([addr,]) # add list, string is also a list !!!
except ValidationError:
messages.error(request, "Email '%s' není ve správném tvaru." % (addr))
all_ok=False
if all_ok:
return msg_send(request, id, True, custom_recip)
else:
messages.error(request, "Je třeba opravit vadné adresy.")
else:
form = forms.CustomRecipientsForm()
template = 'news/msg_send_custom.html'
context = {
'form' : form,
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
def msg_send(request, id, realSend=False, custom_recip=set()):
"""
Odeslani newsletteru.
"""
obj = models.NewsMsg.objects.filter(pk=id,is_del=False)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
messages.error("Objekt nenalezen.")
return redirect('nalodeni:news_all')
else:
1/0
site_perms = request.session.get('site_perms',[])
actions = set()
if not (request.user in obj.news.sent_by.all()
or request.user == obj.news.managed_by
or 'sso_news_manage' in site_perms):
messages.error(request, _('Nedostatečné oprávnění.'))
return redirect('nalodeni:news_all')
if 'sso_news_manage' in site_perms:
recipients_wanted = request.GET.get('recipients','test')
else:
recipients_wanted = "test"
update_sent_ts = False
use_public_to_email = False
recipients_email = []
recip_users = []
if obj.sent_ts is None: # jeste nerozeslano
if recipients_wanted == 'all':
update_sent_ts = True
use_public_to_email = True
recip_users = obj.news.get_recip_users()
elif recipients_wanted == "custom":
update_send_ts = False
use_public_to_email = True
recip_users = [ request.user ]
else:
recip_users = [ request.user ]
else:
if recipients_wanted == "test":
recip_users = [ request.user ]
else:
messages.error(request, "Zpráva již byla rozeslána.")
return redirect('nalodeni:news_list_show', lid=obj.news_id)
if obj.testMailRecipients is not None and recipients_wanted == "test":
for eml in obj.testMailRecipients.split(","):
try:
eml = eml.strip()
validate_email(eml)
recipients_email.append(eml)
except ValidationError:
messages.error(request, "Testovací email %s není ve tvaru emailu." % (eml,) )
for rcp in recip_users:
# pouzivat KONTAKTNI email misto REGISTRACNIHO
eml = rcp.email_contact_active
if eml is None or len(eml.strip()) == 0:
eml = rcp.email
try:
validate_email(eml)
recipients_email.append(eml)
except ValidationError:
messages.error(request, "Email '%s' uživatele %s není ve správném tvaru." % (eml, rcp.username))
# add custom recipients
recipients_email += list(custom_recip)
# do it unique
recipients_email = list(set(recipients_email))
template = 'news/msg_to_email.html'
context = {
'msg' : obj,
'abs_host_url' : '%s://%s' % ( request.scheme, request.get_host()),
'blocks' : obj.newsmsgblock_set.all(),
}
if realSend:
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
from django.core.mail import get_connection, EmailMultiAlternatives
import quopri
for recip_part in chunks(recipients_email, 500):
# process by part, MailGun API has a limit of 1000 messages
mailgun_backend = get_connection('anymail.backends.mailgun.EmailBackend')
header_from = '%s <%s>' % (
appSettings.ANYMAIL['FROM_NAME'],
appSettings.ANYMAIL['FROM_EMAIL'],
)
html_message = render_to_string(template, context)
plain_message = html2text.html2text(html_message)
ema = EmailMultiAlternatives(
"%s - %s" % (obj.news.name, obj.title),
plain_message, header_from )
ema.connection = mailgun_backend
if use_public_to_email:
ema.to = [ appSettings.ANYMAIL['PUBLIC_TO_EMAIL'] ]
else:
# pouzit kontaktni nebo registracni email uzivatele
eml = rcp.email_contact_active
if eml is None or len(eml.strip()) == 0:
eml = rcp.email
ema.to = [ eml ]
ema.bcc = recip_part
if obj.news.replyToEmail is not None:
try:
eml = obj.news.replyToEmail.strip()
validate_email(eml)
ema.extra_headers = {
'Reply-To' : eml,
}
except ValidationError:
messages.error(request, "Odpovědní email '%s' není ve tvaru emailu. Odesílání zrušeno." % (eml,) )
messages.info(request, "Chybu může opravit správce tohoto newsletteru." )
return redirect('nalodeni:news_list_show', lid=obj.news_id)
ema.attach_alternative(html_message, "text/html")
ema.send()
messages.info(request, "Zpráva odeslána %s uživatelům." % len(recip_part) )
# end of partial send
if update_sent_ts:
obj.sent_ts = datetime.now()
obj.save()
messages.info(request, "Zpráva odeslána pomocí MailGun celkem %s uživatelům." % len(recipients_email) )
else:
messages.error(request, "Message delivery disabled.")
return redirect('nalodeni:news_list_show', lid=obj.news_id)
def msg_preview(request, id):
"""
Verejny nahled newsletteru.
"""
obj = models.NewsMsg.objects.filter(pk=id,is_del=False)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
messages.error("Objekt nenalezen.")
return redirect('nalodeni:news_all')
else:
1/0
site_perms = request.session.get('site_perms',[])
actions = set()
passed = False
if (request.user in obj.news.sent_by.all()
or request.user == obj.news.managed_by
or 'sso_news_manage' in site_perms):
passed = True
if obj.sent_ts is not None:
passed = True
if not passed:
return redirect('nalodeni:news_all')
template = 'news/msg_to_email.html'
context = {
'msg' : obj,
'abs_host_url' : '%s://%s' % ( request.scheme, request.get_host()),
'blocks' : obj.newsmsgblock_set.all(),
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
def block_edit(request, mid, bid=None):
"""
Seznam zpráv pro daný newsletter.
"""
if bid is not None:
obj = models.NewsMsgBlock.objects.filter(pk=bid, newsmsg_id=mid)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
return redirect('nalodeni:news_block_create', mid=mid)
else:
1/0
else:
obj = None
if obj is None:
obj = models.NewsMsgBlock(newsmsg_id=mid)
site_perms = request.session.get('site_perms',[])
actions = set()
if not (request.user in obj.newsmsg.news.sent_by.all()
or request.user == obj.newsmsg.news.managed_by
or 'sso_news_manage' in site_perms):
messages.error(request, _('Nedostatečné oprávnění pro editaci bloku zprávy.'))
return redirect('nalodeni:news_all')
if request.method == 'GET':
form = forms.NewsMsgBlockForm(instance=obj)
elif request.method == 'POST':
form = forms.NewsMsgBlockForm(request.POST, instance=obj)
if form.is_valid():
form.instance.content = bleach.clean(form.instance.content,
tags=['b','ul','ol','li','a','i','hr'], strip=True)
form.instance.content = bleach.linkify(form.instance.content)
form.save()
messages.info(request, "Údaje byly uloženy.")
return redirect('nalodeni:news_msg_show', mid=mid)
template = 'news/block_edit.html'
context = {
'form' : form,
}
return render(request, template, context)
@ensure_csrf_cookie
@login_required(login_url="/prihlaseni")
def block_delete(request, bid):
"""
Seznam zpráv pro daný newsletter.
"""
obj = models.NewsMsgBlock.objects.filter(pk=bid)
if len(obj) == 1:
obj = obj[0]
elif len(obj) == 0:
obj = None
return redirect('nalodeni:news_all')
else:
1/0
site_perms = request.session.get('site_perms',[])
actions = set()
if not (request.user in obj.newsmsg.news.sent_by.all()
or request.user == obj.newsmsg.news.managed_by
or 'sso_news_manage' in site_perms):
messages.error(request, _('Nedostatečné oprávnění pro smazání bloku zprávy.'))
return redirect('nalodeni:news_all')
mid = obj.newsmsg_id
obj.delete()
messages.info(request, "Záznam byl smazán.")
return redirect('nalodeni:news_msg_show', mid=mid)