From 63b0fc6269b38edf7234b9f151b80d81f614c0a3 Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Tue, 4 Aug 2015 10:11:24 +0300 Subject: Initial commit First public commit --- servo/views/account.py | 450 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 servo/views/account.py (limited to 'servo/views/account.py') diff --git a/servo/views/account.py b/servo/views/account.py new file mode 100644 index 0000000..39193b6 --- /dev/null +++ b/servo/views/account.py @@ -0,0 +1,450 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import csv +import pytz +from datetime import date + +from django.contrib import auth +from django.utils import timezone, translation + +from django.contrib import messages +from django.http import HttpResponse +from django.core.urlresolvers import reverse +from django.shortcuts import redirect, render +from dateutil.relativedelta import relativedelta +from django.utils.translation import ugettext as _ +from django.contrib.auth.decorators import permission_required +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger + +from servo.views.order import prepare_list_view + +from servo.models import Order, User, Calendar, CalendarEvent +from servo.forms.account import ProfileForm, RegistrationForm, LoginForm + + +def settings(request, username): + """ + User editing their profile preferences + """ + title = _("Profile Settings") + form = ProfileForm(instance=request.user) + + if request.method == "POST": + + form = ProfileForm(request.POST, request.FILES, instance=request.user) + + if form.is_valid(): + user = form.save() + messages.success(request, _("Settings saved")) + User.refresh_nomail() + + if form.cleaned_data['password1']: + request.user.set_password(form.cleaned_data['password1']) + request.user.save() + + lang = user.activate_locale() + translation.activate(lang) + request.session[translation.LANGUAGE_SESSION_KEY] = lang + request.session['django_timezone'] = user.timezone + + return redirect(settings, username) + else: + print("Error in user settings: %s" % form.errors) + messages.error(request, _("Error in user details")) + + return render(request, "accounts/settings.html", locals()) + + +def orders(request, username): + """ + This is basically like orders/index, but limited to the user + First, filter by the provided search criteria, + then check if we have a saved search filter + then default to user id + Always update saved search filter + """ + args = request.GET.copy() + + if not args: + args = request.session.get("account_search_filter", args) + + if not args: + args.update({'state': 1}) # default to open cases + + # Filter by the user, no matter what + args.update({'followed_by': request.user.pk}) + request.session['account_search_filter'] = args + + data = prepare_list_view(request, args) + data['title'] = _("My Orders") + + del(data['form'].fields['assigned_to']) + + return render(request, "accounts/orders.html", data) + + +def login(request): + """ + User trying to log in + """ + title = _("Sign In") + form = LoginForm() + + if 'username' in request.POST: + + form = LoginForm(request.POST) + + if form.is_valid(): + user = auth.authenticate( + username=form.cleaned_data['username'], + password=form.cleaned_data['password'] + ) + + if user is None: + messages.error(request, _("Incorrect username or password")) + elif not user.is_active: + messages.error(request, _("Your account has been deactivated")) + else: + auth.login(request, user) + + if user.location: + lang = user.activate_locale() + request.session['django_language'] = lang + request.session['django_timezone'] = user.timezone + + messages.success(request, _(u"%s logged in") % user.get_full_name()) + + if request.GET.get('next'): + return redirect(request.GET['next']) + else: + return redirect(orders, username=user.username) + else: + messages.error(request, _("Invalid input for login")) + + return render(request, "accounts/login.html", locals()) + + +def logout(request): + if request.method == 'POST': + auth.logout(request) + messages.info(request, _("You have logged out")) + + return redirect(login) + + return render(request, "accounts/logout.html") + + +@permission_required("servo.add_calendar") +def calendars(request, username=None): + data = {'title': _('Calendars')} + data['calendars'] = Calendar.objects.filter(user=request.user) + + if data['calendars'].count() > 0: + cal = data['calendars'][0] + return redirect(view_calendar, username, cal.pk) + + return render(request, "accounts/calendars.html", data) + + +@permission_required("servo.add_calendar") +def prepare_calendar_view(request, pk, view, start_date): + """ + Prepares a calendar detail view for other views to use + """ + calendar = Calendar.objects.get(user=request.user, pk=pk) + + if start_date is not None: + year, month, day = start_date.split("-") + start_date = date(int(year), int(month), int(day)) + else: + start_date = timezone.now().date() + + start = start_date + finish = start_date + relativedelta(days=+1) + + if view == "week": + start = start_date + relativedelta(day=1) + finish = start_date + relativedelta(weeks=+1) + + if view == "month": + start = start_date + relativedelta(day=1) + finish = start_date + relativedelta(day=1, months=+1, days=-1) + + data = {'title': "%s %s - %s" % (calendar.title, start.strftime("%x"), + finish.strftime("%x"))} + + data['view'] = view + data['start'] = start + data['finish'] = finish + + data['next'] = finish + relativedelta(days=+1) + data['previous'] = start + relativedelta(days=-1) + + data['calendars'] = Calendar.objects.filter(user=request.user) + data['events'] = calendar.calendarevent_set.filter( + started_at__range=(start, finish) + ) + + data['calendar'] = calendar + data['subtitle'] = calendar.subtitle(start, finish) + + return data + + +@permission_required("servo.add_calendar") +def download_calendar(request, username, pk, view): + calendar = Calendar.objects.get(pk=pk) + + response = HttpResponse(content_type="text/csv") + response['Content-Disposition'] = 'attachment; filename="%s.csv"' % calendar.title + writer = csv.writer(response) + writer.writerow(['START', 'FINISH', 'HOURS', 'NOTES']) + + for e in calendar.calendarevent_set.all(): + writer.writerow([e.started_at, e.finished_at, e.get_hours(), e.notes]) + + return response + + +@permission_required("servo.add_calendar") +def print_calendar(request, username, pk, view, start_date): + data = prepare_calendar_view(request, pk, view, start_date) + calendar = data['calendar'] + + data['location'] = request.user.location + # Don't show unfinished events in the report + data['events'] = data['events'].exclude(finished_at=None) + data['subtitle'] = calendar.subtitle(data['start'], data['finish']) + return render(request, "accounts/print_calendar.html", data) + + +@permission_required("servo.add_calendar") +def view_calendar(request, username, pk, view, start_date=None): + data = prepare_calendar_view(request, pk, view, start_date) + data['base_url'] = reverse(view_calendar, args=[username, pk, view]) + + return render(request, "accounts/view_calendar.html", data) + + +@permission_required("servo.delete_calendar") +def delete_calendar(request, username, pk): + calendar = Calendar.objects.get(pk=pk) + + if calendar.user != request.user: + messages.error(request, _("Users can only delete their own calendars!")) + + return redirect(calendars, username=username) + + if request.method == "POST": + calendar.delete() + messages.success(request, _('Calendar deleted')) + return redirect(calendars, username=request.user.username) + + data = {'title': _("Really delete this calendar?")} + data['action'] = request.path + + return render(request, "accounts/delete_calendar.html", data) + + +@permission_required("servo.change_calendar") +def edit_calendar(request, username, pk=None, view="week"): + from servo.models.calendar import CalendarForm + calendar = Calendar(user=request.user) + + if pk is not None: + calendar = Calendar.objects.get(pk=pk) + + if request.method == "POST": + form = CalendarForm(request.POST, instance=calendar) + + if form.is_valid(): + calendar = form.save() + messages.success(request, _("Calendar saved")) + return redirect(view_calendar, username, calendar.pk, 'week') + + form = CalendarForm(instance=calendar) + + data = {'title': calendar.title} + data['form'] = form + data['action'] = request.path + + return render(request, "accounts/calendar_form.html", data) + + +@permission_required('servo.change_calendar') +def edit_calendar_event(request, username, cal_pk, pk=None): + from servo.models.calendar import CalendarEventForm + + calendar = Calendar.objects.get(pk=cal_pk) + event = CalendarEvent(calendar=calendar) + + if pk: + event = CalendarEvent.objects.get(pk=pk) + else: + event.save() + messages.success(request, _(u'Calendar event created')) + return redirect(event.calendar) + + form = CalendarEventForm(instance=event) + + if request.method == 'POST': + form = CalendarEventForm(request.POST, instance=event) + + if form.is_valid(): + event = form.save() + messages.success(request, _(u'Event saved')) + return redirect(event.calendar) + + data = {'title': _(u'Edit Event')} + data['form'] = form + data['calendars'] = Calendar.objects.filter(user=request.user) + + return render(request, 'accounts/edit_calendar_event.html', data) + + +@permission_required("servo.change_calendar") +def finish_calendar_event(request, username, cal_pk, pk): + event = CalendarEvent.objects.get(pk=pk) + event.set_finished() + messages.success(request, _(u'Calendar event updated')) + + return redirect(view_calendar, username, cal_pk, 'week') + + +def delete_calendar_event(request, username, cal_pk, pk): + if username != request.user.username: + messages.error(request, _(u'Users can only delete their own events!')) + + return redirect(calendars, username=request.user.username) + + event = CalendarEvent.objects.get(pk=pk) + + if request.method == 'POST': + event.delete() + messages.success(request, _('Calendar event deleted')) + return redirect(event.calendar) + + data = {'title': _(u'Really delete this event?')} + data['action'] = request.path + return render(request, 'accounts/delete_calendar_event.html', data) + + +def register(request): + """ + New user applying for access + """ + form = RegistrationForm() + data = {'title': _("Register")} + + if request.method == 'POST': + + form = RegistrationForm(request.POST) + + if form.is_valid(): + user = User(is_active=False) + user.email = form.cleaned_data['email'] + user.last_name = form.cleaned_data['last_name'] + user.first_name = form.cleaned_data['first_name'] + user.set_password(form.cleaned_data['password']) + user.save() + + messages.success(request, _(u'Your registration is now pending approval.')) + + return redirect(login) + + data['form'] = form + return render(request, 'accounts/register.html', data) + + +def clear_notifications(request, username): + from datetime import datetime + ts = [int(x) for x in request.GET.get('t').split('/')] + ts = datetime(*ts, tzinfo=timezone.get_current_timezone()) + notif = request.user.notifications.filter(handled_at=None) + notif.filter(triggered_at__lt=ts).update(handled_at=timezone.now()) + messages.success(request, _('All notifications cleared')) + return redirect(request.META['HTTP_REFERER']) + + +def search(request, username): + """ + User searching for something from their homepage + """ + query = request.GET.get("q") + + if not query or len(query) < 3: + messages.error(request, _('Search query is too short')) + return redirect('accounts-list_orders', username) + + request.session['search_query'] = query + + # Redirect Order ID:s to the order + try: + order = Order.objects.get(code__iexact=query) + return redirect(order) + except Order.DoesNotExist: + pass + + kwargs = request.GET.copy() + kwargs.update({'followed_by': request.user.pk}) + data = prepare_list_view(request, kwargs) + + data['title'] = _("Search results") + orders = data['queryset'] + data['orders'] = orders.filter(customer__fullname__icontains=query) + + return render(request, "accounts/orders.html", data) + + +def stats(request, username): + from servo.views.stats import prep_view, BasicStatsForm + data = prep_view(request) + form = BasicStatsForm(initial=data['initial']) + if request.method == 'POST': + form = BasicStatsForm(request.POST, initial=data['initial']) + if form.is_valid(): + request.session['stats_filter'] = form.cleaned_data + data['form'] = form + return render(request, "accounts/stats.html", data) + + +def updates(request, username): + title = _('Updates') + kind = request.GET.get('kind', 'note_added') + events = request.user.notifications.filter(action=kind) + + page = request.GET.get("page") + paginator = Paginator(events, 100) + + try: + events = paginator.page(page) + except PageNotAnInteger: + events = paginator.page(1) + except EmptyPage: + events = paginator.page(paginator.num_pages) + + return render(request, "accounts/updates.html", locals()) -- cgit v1.2.3