624 lines
19 KiB
Python
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)
|
|
|
|
|