# -*- 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)