711 lines
26 KiB
Python
711 lines
26 KiB
Python
import smtplib
|
|
from itertools import count, chain
|
|
import socket
|
|
import os.path
|
|
import collections
|
|
import operator
|
|
import datetime
|
|
|
|
|
|
from django.contrib.auth.decorators import login_required
|
|
import django.contrib.auth as auth
|
|
from django.shortcuts import render, redirect, get_object_or_404
|
|
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
|
|
from django.conf import settings
|
|
from django.core.urlresolvers import reverse
|
|
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
|
from django.db.models.query import Q
|
|
from django.contrib.auth.models import User
|
|
from django.contrib import messages
|
|
from django.core.mail import EmailMessage
|
|
from django.utils.translation import ugettext as _, ugettext_noop as N_, ungettext
|
|
from django.forms.forms import NON_FIELD_ERRORS
|
|
from django.views.generic.list import MultipleObjectMixin, ListView
|
|
from django.views.generic.base import View
|
|
from django.views.decorators.debug import sensitive_post_parameters
|
|
from django.views.decorators.cache import never_cache
|
|
from django.utils import timezone
|
|
|
|
|
|
from BeautifulSoup import BeautifulSoup
|
|
import django_tables2.views as tables_views
|
|
|
|
|
|
from .forms import (FileForm, AnonymousContactForm, ContactForm,
|
|
ForwardingForm, FilterForm)
|
|
from .models import (Mailbox, username, AttachedFile, SendingLimitation,
|
|
MailingList, DeletedMailbox, is_guest, Document, FileType)
|
|
from .decorators import no_delegate, never_cache, as_delegate
|
|
from .logger_adapter import get_logger
|
|
from . import tables
|
|
from . import app_settings
|
|
from . import unicodecsv
|
|
from . import profile_views
|
|
from .utils import date_to_aware_datetime
|
|
|
|
|
|
gettext_noop = lambda x: x
|
|
|
|
@login_required
|
|
def homepage(request):
|
|
return redirect('inbox')
|
|
|
|
class Row(object):
|
|
def __init__(self, **kwargs):
|
|
self.__dict__.update(kwargs)
|
|
|
|
|
|
def mailboxes(request):
|
|
return Mailbox.objects.filter(Q(owner=request.user)
|
|
|Q(owner__delegations_to__to=request.user)).distinct()
|
|
|
|
|
|
def get_mailbox(request, mailbox_id, back='inbox'):
|
|
owners = list(request.user.delegations_by \
|
|
.values_list('by__id', flat=True))
|
|
owners.append(request.user.id)
|
|
try:
|
|
return Mailbox.objects.get(pk=mailbox_id,
|
|
owner__in=owners, outbox=back!='inbox')
|
|
except Mailbox.DoesNotExist:
|
|
return None
|
|
|
|
def user_mailing_list_names(user):
|
|
return user.mailing_lists.values_list('name', flat=True)
|
|
|
|
def recursive_lists(lists):
|
|
lists = set(lists)
|
|
count = len(lists)
|
|
while True:
|
|
lists |= set(MailingList.objects.filter(members_lists__in=lists))
|
|
if len(lists) == count:
|
|
break
|
|
count = len(lists)
|
|
return lists
|
|
|
|
def get_file_form_kwargs(request):
|
|
user = request.user
|
|
if is_guest(user):
|
|
user = user.delegations_by.get().by
|
|
delegators = []
|
|
else:
|
|
delegators = User.objects.filter(
|
|
Q(id=user.id) |
|
|
Q(delegations_to__to=user)).distinct()
|
|
user_lists = MailingList.objects.is_member_of(user)
|
|
own_limitations = MailingList.objects \
|
|
.filter(lists_limitation__mailing_list__in=user_lists) \
|
|
.distinct() \
|
|
.order_by('name')
|
|
if not own_limitations:
|
|
return {}
|
|
kwargs = {}
|
|
user_lists = MailingList.objects.are_member_of([user] + list(delegators))
|
|
if SendingLimitation.objects.filter(mailing_list__in=user_lists):
|
|
lists = MailingList.objects \
|
|
.filter(lists_limitation__mailing_list__in=user_lists) \
|
|
.distinct() \
|
|
.order_by('name')
|
|
lists = recursive_lists(lists)
|
|
users = User.objects.filter(mailing_lists__in=lists, is_active=True) \
|
|
.distinct()
|
|
if lists:
|
|
kwargs['list_qs'] = lists
|
|
kwargs['user_qs'] = users
|
|
return kwargs
|
|
|
|
|
|
def get_filetype_limitation(user):
|
|
# find delegation relations
|
|
if is_guest(user):
|
|
user = user.delegations_by.get().by
|
|
delegators = []
|
|
else:
|
|
delegators = User.objects.filter(
|
|
Q(id=user.id) |
|
|
Q(delegations_to__to=user)).distinct()
|
|
# if user has basically no limitation, do not limit him
|
|
user_lists = MailingList.objects.is_member_of(user)
|
|
own_limitations = FileType.objects \
|
|
.filter(filetype_limitation__mailing_list__in=user_lists) \
|
|
.distinct() \
|
|
.order_by('name')
|
|
if not own_limitations.exists():
|
|
return FileType.objects.none()
|
|
if delegators:
|
|
user_lists = MailingList.objects.are_member_of([user] + list(delegators))
|
|
return FileType.objects \
|
|
.filter(filetype_limitation__mailing_list__in=user_lists) \
|
|
.distinct() \
|
|
.order_by('name')
|
|
else:
|
|
return own_limitations
|
|
|
|
|
|
@login_required
|
|
@never_cache
|
|
def send_file(request, file_type_id):
|
|
file_type = get_object_or_404(FileType, id=file_type_id)
|
|
reply_to = None
|
|
if 'reply_to' in request.GET:
|
|
reply_to = get_mailbox(request, request.GET['reply_to'])
|
|
if hasattr(request.user, 'delegate'):
|
|
delegators = []
|
|
else:
|
|
delegators = User.objects.filter(
|
|
Q(id=request.user.id) |
|
|
Q(delegations_to__to=request.user)).distinct()
|
|
real_user = getattr(request.user, 'delegate', request.user)
|
|
limitations = get_filetype_limitation(request.user)
|
|
if limitations:
|
|
if not limitations.filter(id=file_type.id).exists():
|
|
return redirect('send-file-selector')
|
|
if request.method == 'POST':
|
|
if 'send' not in request.POST:
|
|
return redirect('outbox')
|
|
form = FileForm(request.POST, request.FILES,
|
|
default_sender=request.user, user=real_user,
|
|
delegations=delegators, reply_to=reply_to,
|
|
file_type=file_type,
|
|
**get_file_form_kwargs(request))
|
|
try:
|
|
if form.is_valid():
|
|
new_send = form.save(commit=False)
|
|
to_user = []
|
|
to_list = []
|
|
for recipient in form.cleaned_data['recipients']:
|
|
if recipient.startswith('list-'):
|
|
i = recipient.split('-')[1]
|
|
to_list.append(int(i))
|
|
elif recipient.startswith('user-'):
|
|
i = recipient.split('-')[1]
|
|
to_user.append(int(i))
|
|
new_send.save()
|
|
form.save_attachments()
|
|
new_send.to_user = to_user
|
|
new_send.to_list = to_list
|
|
recipients_count = new_send.post()
|
|
request.record('create-document', 'sent document {document} '
|
|
'delivered to {recipients_count}', document=new_send,
|
|
recipients_count=recipients_count)
|
|
return redirect('outbox')
|
|
except Exception:
|
|
logger = get_logger(request)
|
|
logger.exception('unable to create a new document')
|
|
form._errors.setdefault(NON_FIELD_ERRORS, form.error_class()) \
|
|
.append(_('An internal error occured, administrators '
|
|
'have been notified; sending seems blocked at the moment. You should '
|
|
'try agrain later. If it still does not work then, contact '
|
|
'your administrator.'))
|
|
else:
|
|
form = FileForm(default_sender=request.user, user=real_user,
|
|
delegations=delegators, reply_to=reply_to,
|
|
file_type=file_type,
|
|
**get_file_form_kwargs(request))
|
|
if reply_to:
|
|
form.helper.form_action = '?reply_to=%s' % reply_to.id
|
|
return render(request, 'docbow/send_file.html',
|
|
{'form': form, 'view_name': 'send-file', 'reply_to': reply_to})
|
|
|
|
@never_cache
|
|
def upload(request, attached_file):
|
|
response = HttpResponse(attached_file.content.chunks(), mimetype='application/octet-stream')
|
|
response['Content-disposition'] = 'attachment'
|
|
return response
|
|
|
|
@login_required
|
|
@never_cache
|
|
def message_attached_file(request, mailbox_id, attached_file, back='inbox'):
|
|
'''
|
|
Download attached files, verify that the user has access to the document
|
|
before, otherwise return 404.
|
|
'''
|
|
mailbox = get_mailbox(request, mailbox_id, back=back)
|
|
if not mailbox:
|
|
raise Http404
|
|
attached_file = get_object_or_404(AttachedFile,
|
|
document__mailboxes__id=mailbox_id, pk=attached_file)
|
|
Mailbox.objects.filter(pk=mailbox_id).update(seen=True)
|
|
delegate = mailbox.owner if mailbox.owner != request.user else None
|
|
request.record('download', 'download attached file {attached_file} of document {document}',
|
|
attached_file=attached_file, document=attached_file.document,
|
|
user=mailbox.owner,
|
|
delegate=delegate)
|
|
return upload(request, attached_file)
|
|
|
|
def form_to_user_and_list(form):
|
|
to_user = []
|
|
to_list = []
|
|
for recipient in form.cleaned_data['recipients']:
|
|
if recipient.startswith('list-'):
|
|
i = recipient.split('-')[1]
|
|
to_list.append(int(i))
|
|
elif recipient.startswith('user-'):
|
|
i = recipient.split('-')[1]
|
|
to_user.append(int(i))
|
|
return to_user, to_list
|
|
|
|
|
|
@login_required
|
|
@never_cache
|
|
def message(request, mailbox_id, back='inbox'):
|
|
mailbox = get_mailbox(request, mailbox_id, back)
|
|
if not mailbox:
|
|
raise Http404
|
|
document = mailbox.document
|
|
if back == 'inbox':
|
|
back_pair = (reverse('inbox'), gettext_noop('back to inbox'))
|
|
else:
|
|
back_pair = (reverse('outbox'), gettext_noop('back to outbox'))
|
|
ctx = { 'document': document,
|
|
'view_name': back, 'back': back_pair, 'mailbox': mailbox }
|
|
if back == 'inbox':
|
|
limitations = get_filetype_limitation(request.user)
|
|
if not limitations or limitations.filter(id=mailbox.document.filetype.id).exists():
|
|
if request.method == 'POST':
|
|
form = ForwardingForm(request.POST, user=request.user,
|
|
**get_file_form_kwargs(request))
|
|
if form.is_valid():
|
|
users, lists = form_to_user_and_list(form)
|
|
recipients_count, forwarded_document = document.forward(
|
|
form.cleaned_data['sender'], lists, users)
|
|
request.record('forward-document', 'forwarded document '
|
|
'{document} as new document {new_document}',
|
|
document=forwarded_document.from_document,
|
|
new_document=forwarded_document.to_document)
|
|
msg = ungettext('Document forwarded to {recipients_count} '
|
|
'recipient.', 'Document forwarded to {recipients_count} '
|
|
'recipients.', recipients_count) \
|
|
.format(recipients_count=recipients_count)
|
|
messages.info(request, msg)
|
|
return HttpResponseRedirect('')
|
|
else:
|
|
form = ForwardingForm(user=request.user,
|
|
**get_file_form_kwargs(request))
|
|
ctx['form'] = form
|
|
ctx['delegated'] = mailbox.owner != request.user
|
|
delegate = mailbox.owner if ctx['delegated'] else None
|
|
ctx['attached_files'] = attached_files = []
|
|
for attached_file in document.attached_files.order_by('kind__position', 'kind__name', 'id'):
|
|
if attached_files and attached_files[-1][0] == attached_file.kind:
|
|
attached_files[-1][1].append(attached_file)
|
|
else:
|
|
attached_files.append((attached_file.kind, [attached_file]))
|
|
request.record('message-view', 'looked at document {document}',
|
|
document=document, user=mailbox.owner, delegate=delegate)
|
|
return render(request, 'docbow/message.html', ctx)
|
|
|
|
def get_help_content(pagename):
|
|
filepath = os.path.join(settings.STATIC_ROOT, 'help', pagename)
|
|
parsed_doc = BeautifulSoup(file(filepath).read())
|
|
page = parsed_doc.findAll(True, role='main')[0]
|
|
for t in page.findAll('h4'):
|
|
t.name = 'h6'
|
|
for t in page.findAll('h3'):
|
|
t.name = 'h5'
|
|
for t in page.findAll('h2'):
|
|
t.name = 'h4'
|
|
for t in page.findAll('h1'):
|
|
t.name = 'h3'
|
|
return unicode(page)
|
|
|
|
@login_required
|
|
def help(request, pagename='index.html'):
|
|
if pagename.endswith('.html'):
|
|
return render(request, 'docbow/help.html', {
|
|
'view_name': 'help',
|
|
'content': get_help_content(pagename) })
|
|
else:
|
|
filepath = os.path.join(settings.STATIC_ROOT, 'help', pagename)
|
|
response = HttpResponse(content=file(filepath))
|
|
response['Content-Type'] = 'image/png'
|
|
return response
|
|
|
|
def contact(request, template='docbow/contact.html',
|
|
form_class=AnonymousContactForm):
|
|
logger = get_logger(request)
|
|
user = request.user
|
|
if user.is_authenticated():
|
|
template = 'docbow/contact_user.html'
|
|
form_class = ContactForm
|
|
contacts = User.objects.filter(groups__name__in=settings.CONTACT_GROUPS)
|
|
if not bool(contacts):
|
|
msg = N_('unable to send the contact mail because there is no '
|
|
'administrator group to receive them')
|
|
request.error_record('error', msg)
|
|
messages.error(request, _(msg))
|
|
return redirect('inbox')
|
|
if request.method == 'POST':
|
|
form = form_class(request.POST)
|
|
if form.is_valid():
|
|
cleaned_data = form.cleaned_data
|
|
to = [ contact.email for contact in contacts ]
|
|
subject = settings.CONTACT_SUBJECT_PREFIX + cleaned_data['subject']
|
|
message = cleaned_data['message']
|
|
if user.is_authenticated():
|
|
reply_to = user.email
|
|
body = _('Message from %(name)s <%(email)s>') % { 'name':
|
|
user.get_full_name(), 'email': reply_to } + '\n\n%s' % message
|
|
else:
|
|
reply_to = cleaned_data['email']
|
|
body = _('Message from %(name)s <%(email)s>') % cleaned_data
|
|
if cleaned_data.get('phone_number'):
|
|
body += _('\nPhone number: %s') % cleaned_data['phone_number']
|
|
body += '\n\n%s' % message
|
|
try:
|
|
EmailMessage(to=to, subject=subject, body=body,
|
|
headers={'Reply-To': reply_to}).send()
|
|
messages.info(request, _('Your message was sent to %d administrators') % len(to))
|
|
request.record('contact', 'sent mail to administrators with '
|
|
'subject "{subject}" and message "{message}", reply should be sent to email '
|
|
'{reply_to} or phone number "{phone}"',
|
|
subject=subject,
|
|
message=message,
|
|
reply_to=reply_to,
|
|
phone=cleaned_data.get('phone_number'))
|
|
except smtplib.SMTPException, socket.error:
|
|
logger.exception('unable to send mail to administrators')
|
|
request.error_record('error', 'unable to send mail to administrators with '
|
|
'subject "{subject}" and message "{message}", reply should be sent to email '
|
|
'{reply_to} or phone number "{phone}"',
|
|
subject=subject,
|
|
message=message,
|
|
reply_to=reply_to,
|
|
phone=cleaned_data.get('phone_number'))
|
|
return redirect('inbox')
|
|
else:
|
|
form = form_class()
|
|
return render(request, template, { 'form': form, 'view_name': 'contact' })
|
|
|
|
def logout(request):
|
|
auth.logout(request)
|
|
return redirect('inbox')
|
|
|
|
@login_required
|
|
@never_cache
|
|
def delete(request, mailbox_id, back='inbox'):
|
|
'''Remove a document from the inbox'''
|
|
if is_guest(request.user):
|
|
raise Http404
|
|
page = request.GET.get('page', 1)
|
|
viewname = back + '-message-delete'
|
|
back_pair = ('%s?page=%s' % (reverse(back), page),
|
|
gettext_noop('back to %s' % back))
|
|
owners = list(request.user.delegations_by \
|
|
.values_list('by__id', flat=True))
|
|
owners.append(request.user.id)
|
|
m = get_object_or_404(Mailbox, owner__id__in=owners, pk=mailbox_id)
|
|
if request.method == 'GET':
|
|
return render(request, 'docbow/delete.html', { 'document': m.document, 'back': back_pair, 'view_name': viewname })
|
|
else:
|
|
if m.owner == request.user:
|
|
m.deleted = True
|
|
m.save()
|
|
DeletedMailbox.objects.filter(mailbox=m).delete()
|
|
request.record('delete-document', 'marked mailbox entry {mailbox} / document {document} as deleted',
|
|
mailbox=m, document=m.document)
|
|
else:
|
|
DeletedMailbox.objects.create(mailbox=m, delegate=request.user)
|
|
request.record('delete-document', 'marked mailbox entry {mailbox} / document {document} as deleted',
|
|
mailbox=m, user=m.owner, delegate=request.user, document=m.document)
|
|
return redirect(back_pair[0])
|
|
|
|
def get_free_delegation_number(user):
|
|
'''Allocate a new delegation username'''
|
|
for i in count(1):
|
|
delegate_username = user.username + '-%d' % i
|
|
try:
|
|
User.objects.get(username=delegate_username)
|
|
except User.DoesNotExist:
|
|
return delegate_username
|
|
|
|
|
|
@login_required
|
|
@never_cache
|
|
def inbox_by_document(request, document_id):
|
|
mailbox = get_object_or_404(mailboxes(request), document=document_id,
|
|
outbox=False)
|
|
return redirect('inbox-message', mailbox.id, permanent=True)
|
|
|
|
|
|
|
|
@login_required
|
|
@never_cache
|
|
def outbox_by_document(request, document_id):
|
|
mailbox = get_object_or_404(mailboxes(request), document=document_id,
|
|
outbox=True)
|
|
return redirect('outbox-message', mailbox.id, permanent=True)
|
|
|
|
|
|
from django.contrib.auth import SESSION_KEY, BACKEND_SESSION_KEY
|
|
from django import http
|
|
|
|
def su(request, username, redirect_url='/'):
|
|
'''Allows changing user for super-users. Super-user status is kept using a
|
|
flag on the session.
|
|
'''
|
|
if request.user.is_superuser or request.session.get('has_superuser_power'):
|
|
su_user = get_object_or_404(User, username=username)
|
|
if su_user.is_active:
|
|
if is_guest(su_user):
|
|
real_username = su_user.username.rsplit('-', 1)[0]
|
|
real_user = User.objects.get(username=real_username)
|
|
pair_id = '%s,%s' % (real_user.id, su_user.id)
|
|
request.session[SESSION_KEY] = pair_id
|
|
request.session[BACKEND_SESSION_KEY] = 'docbow_project.docbow.auth_backend.DelegationAuthBackend'
|
|
request.session['has_superuser_power'] = True
|
|
else:
|
|
request.session[SESSION_KEY] = su_user.id
|
|
request.session['has_superuser_power'] = True
|
|
request.session[BACKEND_SESSION_KEY] = 'django.contrib.auth.backends.ModelBackend'
|
|
return http.HttpResponseRedirect(redirect_url)
|
|
else:
|
|
return http.HttpResponseRedirect('/')
|
|
|
|
@never_cache
|
|
def mailing_lists(request, template='docbow/mailing-lists.html'):
|
|
mailing_lists = MailingList.objects.active().filter(Q(members__isnull=False) |
|
|
Q(mailing_list_members__isnull=False)).distinct().order_by('name')
|
|
return render(request, template, { 'mailing_lists': mailing_lists })
|
|
|
|
|
|
def robots(request):
|
|
output = '''User-Agent: *
|
|
Disallow: /
|
|
'''
|
|
return HttpResponse(output, mimetype='text/plain')
|
|
|
|
|
|
def password_reset_done(request):
|
|
messages.info(request, _('Email with password reset instruction has been sent.'))
|
|
return redirect('auth_login')
|
|
|
|
|
|
class DateFilterMixinView(object):
|
|
def get_filter_form(self):
|
|
if not hasattr(self, '_form'):
|
|
if 'clear' in self.request.GET:
|
|
form = FilterForm(request=self.request)
|
|
else:
|
|
form = FilterForm(data=self.request.GET,
|
|
request=self.request)
|
|
self._form = form
|
|
return self._form
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(DateFilterMixinView, self).get_context_data(**kwargs)
|
|
context['filter_form'] = self.get_filter_form()
|
|
return context
|
|
|
|
def get_queryset(self):
|
|
qs = super(DateFilterMixinView, self).get_queryset()
|
|
filter_form = self.get_filter_form()
|
|
if filter_form.is_valid():
|
|
not_before = filter_form.cleaned_data.get('not_before')
|
|
not_after = filter_form.cleaned_data.get('not_after')
|
|
if not_before is not None:
|
|
not_before = date_to_aware_datetime(not_before)
|
|
qs = qs.filter(document__date__gte=not_before)
|
|
if not_after is not None:
|
|
not_after += datetime.timedelta(days=1)
|
|
not_after = date_to_aware_datetime(not_after)
|
|
qs = qs.filter(document__date__lt=not_after)
|
|
return qs
|
|
|
|
|
|
class ExtraContextMixin(object):
|
|
extra_ctx = {}
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ExtraContextMixin, self).get_context_data(**kwargs)
|
|
context.update(self.extra_ctx)
|
|
return context
|
|
|
|
class MailboxQuerysetMixin(object):
|
|
def get_queryset(self):
|
|
qs = super(MailboxQuerysetMixin, self).get_queryset()
|
|
user = self.request.user
|
|
delegations = user.delegations_by.select_related('by')
|
|
if delegations:
|
|
delegators = [delegation.by for delegation in delegations]
|
|
delegators.append(user)
|
|
deleted_ids = DeletedMailbox.objects.all()
|
|
deleted_ids = deleted_ids.filter(delegate=user)
|
|
deleted_ids = deleted_ids.values_list('mailbox_id', flat=True)
|
|
qs = qs.filter(deleted=False, owner__in=delegators, outbox=self.outbox) \
|
|
.exclude(id__in=deleted_ids)
|
|
else:
|
|
qs = qs.filter(deleted=False, owner=user, outbox=self.outbox)
|
|
return qs
|
|
|
|
|
|
class MailboxView(ExtraContextMixin, MailboxQuerysetMixin, tables_views.SingleTableView):
|
|
model = Mailbox
|
|
table_class = tables.MailboxTable
|
|
table_pagination = {
|
|
'per_page': app_settings.DOCBOW_MAILBOX_PER_PAGE,
|
|
}
|
|
|
|
|
|
class CSVMultipleObjectMixin(object):
|
|
mapping = ()
|
|
filename = ''
|
|
|
|
def get_header(self):
|
|
return [ column['caption'] for column in self.mapping ]
|
|
|
|
def get_cell(self, mailbox, attribute):
|
|
value = operator.attrgetter(attribute)(mailbox)
|
|
if callable(value):
|
|
value = value()
|
|
return unicode(value)
|
|
|
|
def get_row(self, mailbox):
|
|
for column in self.mapping:
|
|
yield self.get_cell(mailbox, column['attribute'])
|
|
|
|
def get_rows(self):
|
|
qs = self.get_queryset()
|
|
for mailbox in qs:
|
|
yield list(self.get_row(mailbox))
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
response = HttpResponse(mimetype='text/csv')
|
|
response['Content-Disposition'] = 'attachment; filename="%s"' % self.filename
|
|
writer = unicodecsv.UnicodeWriter(response, encoding='utf-8')
|
|
writer.writerow(self.get_header())
|
|
writer.writerows(self.get_rows())
|
|
return response
|
|
|
|
|
|
class ODSMultipleObjectMixin(CSVMultipleObjectMixin):
|
|
worksheet_name = '1'
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
from . import ods
|
|
import cStringIO as StringIO
|
|
response = HttpResponse(mimetype='application/vnd.oasis.opendocument.spreadsheet')
|
|
response['Content-Disposition'] = 'attachment; filename="%s"' % self.filename
|
|
workbook = ods.Workbook(encoding='utf-8')
|
|
sheet = workbook.add_sheet(self.worksheet_name.encode('utf-8'))
|
|
rows = chain(((0, self.get_header()),), enumerate(self.get_rows(), 1))
|
|
for i, row in rows:
|
|
for j, cell in enumerate(row):
|
|
sheet.write(i, j, unicode(cell).encode('utf-8'))
|
|
workbook.save(response)
|
|
return response
|
|
|
|
|
|
class CSVMailboxView(CSVMultipleObjectMixin, ExtraContextMixin,
|
|
MailboxQuerysetMixin, MultipleObjectMixin,
|
|
tables_views.SingleTableMixin, View):
|
|
model = Mailbox
|
|
|
|
|
|
@property
|
|
def filename(self):
|
|
return '{prefix}-{user}-{date}.csv'.format(
|
|
prefix=self.filename_prefix,
|
|
user=self.request.user,
|
|
date=datetime.date.today())
|
|
|
|
def get_header(self):
|
|
table = self.get_table()
|
|
for column in table.columns:
|
|
yield column.header
|
|
|
|
def get_row(self, row):
|
|
for column, cell in row.items():
|
|
yield cell
|
|
|
|
def get_rows(self):
|
|
table = self.get_table()
|
|
for table_row in table.rows:
|
|
yield self.get_row(table_row)
|
|
|
|
|
|
class ODSMailboxView(ODSMultipleObjectMixin, CSVMailboxView):
|
|
@property
|
|
def filename(self):
|
|
return '{prefix}-{user}-{date}.ods'.format(
|
|
prefix=self.filename_prefix,
|
|
user=self.request.user,
|
|
date=datetime.date.today())
|
|
|
|
|
|
class CSVInboxView(CSVMailboxView):
|
|
outbox = False
|
|
table_class = tables.InboxCsvTable
|
|
filename_prefix = 'inbox'
|
|
|
|
|
|
inbox_csv = CSVInboxView.as_view()
|
|
|
|
|
|
class CSVOutboxView(CSVMailboxView):
|
|
outbox = True
|
|
table_class = tables.OutboxCsvTable
|
|
filename_prefix = 'outbox'
|
|
|
|
|
|
outbox_csv = CSVOutboxView.as_view()
|
|
|
|
|
|
class ODSInboxView(ODSMailboxView, CSVInboxView):
|
|
pass
|
|
|
|
|
|
inbox_ods = ODSInboxView.as_view()
|
|
|
|
|
|
class ODSOutboxView(ODSMailboxView, CSVOutboxView):
|
|
pass
|
|
|
|
|
|
outbox_ods = ODSOutboxView.as_view()
|
|
|
|
|
|
class InboxView(DateFilterMixinView, MailboxView):
|
|
outbox = False
|
|
table_class = tables.InboxTable
|
|
template_name = 'docbow/inbox_list.html'
|
|
extra_ctx = {
|
|
'view_name': 'inbox',
|
|
}
|
|
|
|
inbox_view = login_required(InboxView.as_view())
|
|
|
|
class OutboxView(DateFilterMixinView, MailboxView):
|
|
outbox = True
|
|
table_class = tables.OutboxTable
|
|
template_name = 'docbow/outbox_list.html'
|
|
extra_ctx = {
|
|
'view_name': 'outbox',
|
|
}
|
|
|
|
outbox_view = login_required(OutboxView.as_view())
|
|
|
|
|
|
class SendFileSelectorView(ListView):
|
|
template_name = 'docbow/send_file_selector.html'
|
|
model = FileType
|
|
|
|
def get_queryset(self):
|
|
qs = super(SendFileSelectorView, self).get_queryset()
|
|
limitations = get_filetype_limitation(self.request.user)
|
|
if limitations:
|
|
return limitations
|
|
return qs
|
|
|
|
|
|
send_file_selector = login_required(SendFileSelectorView.as_view())
|
|
|
|
|
|
delegate = login_required(no_delegate(never_cache(profile_views.DelegateView.as_view())))
|
|
|
|
|
|
password_change = sensitive_post_parameters()(never_cache(login_required(as_delegate(profile_views.PasswordChangeView.as_view()))))
|
|
|
|
|
|
profile = login_required(as_delegate(profile_views.FullProfileView.as_view()))
|