Commits

Alex Padalka committed b68b2fb

- events implemented

Comments (0)

Files changed (10)

avblty/settings.py

-"""
-Django settings for avblty project.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.6/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.6/ref/settings/
-"""
+# -*- coding: utf-8 -*-
 
 try:
     from local_settings import *
     'django.template.loaders.app_directories.Loader',
 )
 
+TEMPLATE_CONTEXT_PROCESSORS = (
+    "django.contrib.auth.context_processors.auth",
+    "django.core.context_processors.debug",
+    "django.core.context_processors.i18n",
+    "django.core.context_processors.media",
+    "django.core.context_processors.static",
+    "django.core.context_processors.tz",
+    "django.contrib.messages.context_processors.messages",
+    "avblty_app.context_processor.context_vars",
+)
+
 ROOT_URLCONF = 'avblty.urls'
 
 WSGI_APPLICATION = 'avblty.wsgi.application'
 
+MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
 
 # Database settings in local_settings
 
 from django.conf.urls import patterns, include, url
 
 from django.contrib import admin
-from avblty_app.views import delete_av_item, create_av_item, update_av_item, availability_view
+from avblty_app.views import delete_av_item, create_av_item, update_av_item, availability_list_view, \
+    create_event, accept_event, reject_event
 
 admin.autodiscover()
 
 urlpatterns = patterns(
     '',
-    url(r'^$', availability_view, name='index'),
+    url(r'^$', availability_list_view, name='index'),
     url(r'^av/delete/(?P<item_id>\d+)$', delete_av_item, name='delete_av_item'),
     url(r'^av/create$', create_av_item, name='create_av_item'),
     url(r'^av/update/(?P<item_id>\d+)$', update_av_item, name='update_av_item'),
+    url(r'^event/create$', create_event, name='create_event'),
+    url(r'^event/accept/(?P<item_id>\d+)$', accept_event, name='accept_event'),
+    url(r'^event/reject/(?P<item_id>\d+)$', reject_event, name='reject_event'),
     url(r'^login$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name='auth_login'),
     url(r'^logout$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='auth_logout'),
 

avblty_app/context_processor.py

+# -*- coding: utf-8 -*-
+from avblty_app import models
+
+
+def context_vars(request):
+    if request.user.is_authenticated():
+        assigned_events = models.Event.objects.filter(user=request.user).order_by('weekday', 'start_time')
+    else:
+        assigned_events = []
+
+    return {
+        'ASSIGNED_EVENTS': assigned_events
+    }

avblty_app/forms.py

 from avblty_app import models
 
 
+class CreateEventForm(forms.ModelForm):
+    def __init__(self, users_queryset, *args, **kwargs):
+        super(CreateEventForm, self).__init__(*args, **kwargs)
+        self.fields['user'] = forms.ModelChoiceField(
+            label=_("User"),
+            help_text=_("Chose user"),
+            empty_label=None,
+            queryset=users_queryset)
+
+        self.fields.keyOrder = ('user', 'weekday', 'start_time', 'end_time')
+
+    def clean(self):
+        cleaned_data = super(CreateEventForm, self).clean()
+        user = cleaned_data.get("user")
+        weekday = cleaned_data.get("weekday")
+        start_time = cleaned_data.get("start_time")
+        end_time = cleaned_data.get("end_time")
+
+        if start_time and end_time:
+            if start_time >= end_time:
+                raise forms.ValidationError(_("End time should be later than start time"))
+
+            if weekday and self.is_available(user, weekday, start_time, end_time):
+                raise forms.ValidationError(_("User already available at this time"))
+
+        return cleaned_data
+
+    def is_available(self, user, weekday, start_time, end_time):
+        return models.UserAvailable.objects.is_available(user, weekday, start_time, end_time)
+
+    class Meta:
+        model = models.Event
+        fields = ('weekday', 'start_time', 'end_time', 'user')
+
+
 class CreateAvailabilityForm(forms.ModelForm):
     def __init__(self, user, *args, **kwargs):
         self.user = user
             if start_time >= end_time:
                 raise forms.ValidationError(_("End time should be later than start time"))
 
-            if weekday and self.has_availability_intersection(weekday, start_time, end_time):
-                raise forms.ValidationError(_("Attempts to add availability time which intersects with existing"))
+            if weekday and self.is_available(weekday, start_time, end_time):
+                raise forms.ValidationError(_("You are already available at this time"))
 
         return cleaned_data
 
-    def has_availability_intersection(self, weekday, start_time, end_time):
-        return models.UserAvailable.objects.has_intersections(self.user, weekday, start_time, end_time)
+    def is_available(self, weekday, start_time, end_time):
+        return models.UserAvailable.objects.is_available(self.user, weekday, start_time, end_time)
 
     class Meta:
         model = models.UserAvailable
         self.pk = pk
         super(UpdateAvailabilityForm, self).__init__(user, *args, **kwargs)
 
-    def has_availability_intersection(self, weekday, start_time, end_time):
-        return models.UserAvailable.objects.has_intersections(self.user, weekday, start_time, end_time,
-                                                              exclude_id=self.pk)
+    def is_available(self, weekday, start_time, end_time):
+        return models.UserAvailable.objects.is_available(self.user, weekday, start_time, end_time, exclude_id=self.pk)

avblty_app/models.py

 # -*- coding: utf-8 -*-
-import re
+from operator import attrgetter
 from django.contrib.auth.models import User
 from django.db.models import Q
 from django.db import models
 from django.utils.dates import WEEKDAYS
-from django.utils.translation import ugettext_lazy as _
-
-from django.core.validators import RegexValidator
-
-TIME24HOURS_PATTERN = re.compile('([01]?[0-9]|2[0-3]):[0-5][0-9]')
 
 
 class UserAvailableModelManager(models.Manager):
 
 
 class UserAvailableQuerySet(models.query.QuerySet):
-    def has_intersections(self, user, weekday, q_start_time, q_end_time, exclude_id=-1):
+    def is_available(self, user, weekday, q_start_time, q_end_time, exclude_id=-1):
         return self.exclude(pk=exclude_id). \
                    filter(user=user, weekday=weekday). \
-                   filter((Q(start_time__lte=q_start_time) & Q(end_time__gte=q_end_time)) |
-                          (Q(start_time__gte=q_start_time) & Q(start_time__lte=q_end_time)) |
-                          (Q(end_time__gte=q_start_time) & Q(end_time__lte=q_end_time))).count() > 0
+                   filter(Q(start_time__lte=q_start_time) & Q(end_time__gte=q_end_time)).count() > 0
+
+    def intersections(self, user, weekday, q_start_time, q_end_time, exclude_id=None):
+        query = self.filter(user=user, weekday=weekday). \
+            filter((Q(start_time__gte=q_start_time) & Q(start_time__lte=q_end_time)) |
+                   (Q(end_time__gte=q_start_time) & Q(end_time__lte=q_end_time))). \
+            order_by('start_time', 'end_time')
+
+        return query.exclude(exclude_id) if exclude_id else query
 
 
 class UserAvailable(models.Model):
 
     objects = UserAvailableModelManager()
 
+    def merge_availability_intersection(self, items):
+        min_start_time = min(items, key=attrgetter('start_time')).start_time
+        max_end_time = max(items, key=attrgetter('end_time')).end_time
+        weekday = items[0].weekday
+        user = items[0].user
+
+        for item in items:
+            if item.id:
+                item.delete()
+
+        UserAvailable(**{
+            'user': user,
+            'weekday': weekday,
+            'start_time': min_start_time,
+            'end_time': max_end_time
+        }).save()
+
+    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
+        intersections = UserAvailable.objects.intersections(self.user, self.weekday, self.start_time, self.end_time)
+        if intersections.count() == 0 or (intersections.count() == 1 and intersections[0] == self):
+            super(UserAvailable, self).save(force_insert, force_update, using, update_fields)
+        else:
+            availability_intersections = list(intersections)
+            availability_intersections.append(self)
+            self.merge_availability_intersection(availability_intersections)
+
     class Meta:
         ordering = ['user', 'weekday', 'start_time']
 

avblty_app/templates/assigned_events.html

+{% load custom_filters %}
+
+{% if ASSIGNED_EVENTS %}
+    <div class="row top5">
+        {% for event in ASSIGNED_EVENTS %}
+            <div class="alert alert-success">
+                <strong>Event:</strong> Do you want to add your availability for:
+                <b>{{ event.weekday|get_weekday }}, {{ event.start_time }} - {{ event.end_time }}</b>
+                <a href="{% url 'accept_event' event.id %}" class="btn btn-default">Accept</a>
+                <a href="{% url 'reject_event' event.id %}" class="btn btn-default">Reject</a>
+            </div>
+        {% endfor %}
+    </div>
+{% endif %}

avblty_app/templates/base_portal.html

             <div class="collapse navbar-collapse">
                 <ul class="nav navbar-nav">
                     <li><a href="{% url 'index' %}">Availability</a></li>
-                    <li><a href="{% url 'index' %}">Add event</a></li>
+                    <li><a href="{% url 'create_event' %}">Add event</a></li>
                     <li><a href="{% url 'auth_logout' %}">Logout</a></li>
                 </ul>
             </div>
     </div>
 
     <div class="container starter-template">
-        {% if messages %}
-            <div>
-                {% include "messages.html" %}
-            </div>
-        {% endif %}
+        {% include "messages.html" %}
+        {% include "assigned_events.html" %}
         {% block content %}
         {% endblock %}
     </div>

avblty_app/templates/create_event_item.html

+{% extends "base_portal.html" %}
+
+{% block content %}
+    <form action="" method="POST" role="form">
+        {% csrf_token %}
+        <h2>Assign event</h2>
+        <table>
+            {{ form.as_table }}
+        </table>
+        <button class="btn btn-primary" type="submit">Assign</button>
+        <a class="btn btn-default" href="{% url 'index' %}">Cancel</a>
+    </form>
+{% endblock %}

avblty_app/templates/messages.html

 {% if messages %}
-    <div class="messages">
+    <div class="row messages top5">
         {% for message in messages %}
             <div class="alert {% if message.tags %} alert-{{ message.tags }}{% endif %}">
                 <button type="button" class="close" data-dismiss="alert">×</button>

avblty_app/views.py

+# -*- coding: utf-8 -*-
+
 from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
 from django.core.urlresolvers import reverse_lazy
 from django.http.response import HttpResponseRedirect
 from django.shortcuts import get_object_or_404
 from django.views.generic.base import TemplateView, View
 from django.views.generic.edit import CreateView, UpdateView
+from django.contrib import messages
 from avblty_app import models, forms
 
 
+class CreateEventView(CreateView):
+    form_class = forms.CreateEventForm
+
+    def get_form_kwargs(self):
+        kwargs = super(CreateEventView, self).get_form_kwargs()
+        kwargs.update({'users_queryset': User.objects.all()}) # exclude(pk=self.request.user.pk)
+        return kwargs
+
+    def get(self, request, *args, **kwargs):
+        # possible no one users (except myself) to assign new event
+        if User.objects.exclude(pk=request.user.pk).count() == 0:
+            messages.warning(request, 'You can\'t create event. No one users in the system except you')
+            return HttpResponseRedirect(reverse_lazy('index'))
+
+        return super(CreateEventView, self).get(request, *args, **kwargs)
+
+    def form_valid(self, form):
+        item = form.save(commit=False)
+        item.requested_by = self.request.user
+        item.save()
+
+        messages.info(self.request, 'Event assigned')
+
+        return HttpResponseRedirect(reverse_lazy('index'))
+
+
+class AcceptEventView(View):
+    def get(self, request, *args, **kwargs):
+        event = get_object_or_404(models.Event, pk=kwargs['item_id'], user=request.user)
+
+        models.UserAvailable(**{
+            'weekday': event.weekday,
+            'start_time': event.start_time,
+            'end_time': event.end_time,
+            'user': event.user
+        }).save(force_insert=True)
+
+        event.delete()
+
+        messages.info(request, 'Availability updated')
+        return HttpResponseRedirect(reverse_lazy('index'))
+
+
+class RejectEventView(View):
+    def get(self, request, *args, **kwargs):
+        get_object_or_404(models.Event, pk=kwargs['item_id'], user=request.user).delete()
+        return HttpResponseRedirect(reverse_lazy('index'))
+
+
 class CreateAvailabilityView(CreateView):
     form_class = forms.CreateAvailabilityForm
 
         item.user = self.request.user
         item.save()
 
+        messages.info(self.request, 'Availability created')
+
         return HttpResponseRedirect(reverse_lazy('index'))
 
 
         })
         return kwargs
 
+    def form_valid(self, form):
+        result = super(UpdateAvailabilityView, self).form_valid(form)
+
+        messages.info(self.request, 'Availability updated')
+
+        return result
+
     def get_object(self, queryset=None):
         return get_object_or_404(models.UserAvailable, pk=self.kwargs['item_id'], user=self.request.user)
 
     def get(self, request, *args, **kwargs):
         get_object_or_404(models.UserAvailable, pk=kwargs['item_id'], user=request.user).delete()
 
+        messages.info(self.request, 'Availability deleted')
+
         return HttpResponseRedirect(reverse_lazy('index'))
 
 
-class AvailabilityView(TemplateView):
+class AvailabilityListView(TemplateView):
     def get_context_data(self, **kwargs):
-        context_data = super(AvailabilityView, self).get_context_data(**kwargs)
+        context_data = super(AvailabilityListView, self).get_context_data(**kwargs)
         context_data.update({
             'user_availability': models.UserAvailable.objects.filter(user=self.request.user)
         })
         return context_data
 
 
-availability_view = login_required(AvailabilityView.as_view(template_name='availability.html'))
+availability_list_view = login_required(AvailabilityListView.as_view(template_name='availability.html'))
 delete_av_item = login_required(DeleteAvailabilityView.as_view())
 create_av_item = login_required(CreateAvailabilityView.as_view(template_name='create_av_item.html'))
-update_av_item = login_required(UpdateAvailabilityView.as_view(template_name='update_av_item.html'))
+update_av_item = login_required(UpdateAvailabilityView.as_view(template_name='update_av_item.html'))
+create_event = login_required(CreateEventView.as_view(template_name='create_event_item.html'))
+accept_event = login_required(AcceptEventView.as_view())
+reject_event = login_required(RejectEventView.as_view())