From 9927310f6e2600056634c7b5261504eca98b0842 Mon Sep 17 00:00:00 2001 From: Skia Date: Fri, 26 Aug 2016 20:56:16 +0200 Subject: [PATCH] Update login system to support the multiple threads of UWSGI --- core/static/core/style.css | 6 +++ counter/migrations/0002_auto_20160826_1342.py | 54 +++++++++++++++++++ .../migrations/0003_permanency_activity.py | 22 ++++++++ counter/migrations/0004_auto_20160826_1907.py | 19 +++++++ counter/models.py | 54 +++++++------------ counter/views.py | 23 ++++---- 6 files changed, 134 insertions(+), 44 deletions(-) create mode 100644 counter/migrations/0002_auto_20160826_1342.py create mode 100644 counter/migrations/0003_permanency_activity.py create mode 100644 counter/migrations/0004_auto_20160826_1907.py diff --git a/core/static/core/style.css b/core/static/core/style.css index b8adccc6..3e8f8e00 100644 --- a/core/static/core/style.css +++ b/core/static/core/style.css @@ -291,6 +291,12 @@ label { #user_edit img { width: 100px; } +#cash_summary_form label { + display: inline; +} +.inline { + display: inline; +} .form_button { width: 150px; height: 120px; diff --git a/counter/migrations/0002_auto_20160826_1342.py b/counter/migrations/0002_auto_20160826_1342.py new file mode 100644 index 00000000..9bcd4906 --- /dev/null +++ b/counter/migrations/0002_auto_20160826_1342.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings +import accounting.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('counter', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='CashRegisterSummary', + fields=[ + ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), + ('date', models.DateTimeField(verbose_name='date')), + ('comment', models.TextField(null=True, verbose_name='comment', blank=True)), + ('emptied', models.BooleanField(default=False, verbose_name='emptied')), + ('counter', models.ForeignKey(to='counter.Counter', related_name='cash_summaries', verbose_name='counter')), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='cash_summaries', verbose_name='user')), + ], + options={ + 'verbose_name': 'cash register summary', + }, + ), + migrations.CreateModel( + name='CashRegisterSummaryItem', + fields=[ + ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), + ('value', accounting.models.CurrencyField(max_digits=12, verbose_name='value', decimal_places=2)), + ('quantity', models.IntegerField(default=0, verbose_name='quantity')), + ('check', models.BooleanField(default=False, verbose_name='check')), + ('cash_summary', models.ForeignKey(to='counter.CashRegisterSummary', related_name='items', verbose_name='cash summary')), + ], + options={ + 'verbose_name': 'cash register summary item', + }, + ), + migrations.AlterField( + model_name='permanency', + name='counter', + field=models.ForeignKey(to='counter.Counter', related_name='permanencies', verbose_name='counter'), + ), + migrations.AlterField( + model_name='permanency', + name='user', + field=models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='permanencies', verbose_name='user'), + ), + ] diff --git a/counter/migrations/0003_permanency_activity.py b/counter/migrations/0003_permanency_activity.py new file mode 100644 index 00000000..21a14717 --- /dev/null +++ b/counter/migrations/0003_permanency_activity.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import datetime +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('counter', '0002_auto_20160826_1342'), + ] + + operations = [ + migrations.AddField( + model_name='permanency', + name='activity', + field=models.DateTimeField(verbose_name='activity time', auto_now=True, default=datetime.datetime(2016, 8, 26, 17, 5, 31, 202824, tzinfo=utc)), + preserve_default=False, + ), + ] diff --git a/counter/migrations/0004_auto_20160826_1907.py b/counter/migrations/0004_auto_20160826_1907.py new file mode 100644 index 00000000..94cc1e1a --- /dev/null +++ b/counter/migrations/0004_auto_20160826_1907.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('counter', '0003_permanency_activity'), + ] + + operations = [ + migrations.AlterField( + model_name='permanency', + name='end', + field=models.DateTimeField(verbose_name='end date', null=True), + ), + ] diff --git a/counter/models.py b/counter/models.py index 0600193f..f8248a44 100644 --- a/counter/models.py +++ b/counter/models.py @@ -109,15 +109,14 @@ class Product(models.Model): class Counter(models.Model): name = models.CharField(_('name'), max_length=30) - club = models.ForeignKey(Club, related_name="counters") - products = models.ManyToManyField(Product, related_name="counters", blank=True) + club = models.ForeignKey(Club, related_name="counters", verbose_name=_("club")) + products = models.ManyToManyField(Product, related_name="counters", verbose_name=_("products"), blank=True) type = models.CharField(_('counter type'), max_length=255, choices=[('BAR',_('Bar')), ('OFFICE',_('Office')), ('EBOUTIC',_('Eboutic'))]) sellers = models.ManyToManyField(Subscriber, verbose_name=_('sellers'), related_name='counters', blank=True) edit_groups = models.ManyToManyField(Group, related_name="editable_counters", blank=True) view_groups = models.ManyToManyField(Group, related_name="viewable_counters", blank=True) - barmen_session = {} class Meta: verbose_name = _('counter') @@ -144,31 +143,21 @@ class Counter(models.Model): sub = get_subscriber(request.user) return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or sub in self.sellers - def add_barman(counter_id, user_id): + def add_barman(self, user): """ Logs a barman in to the given counter A user is stored as a tuple with its login time """ - counter_id = int(counter_id) - user_id = int(user_id) - if counter_id not in Counter.barmen_session.keys(): - Counter.barmen_session[counter_id] = {'users': {(user_id, timezone.now())}, 'time': timezone.now()} - else: - Counter.barmen_session[counter_id]['users'].add((user_id, timezone.now())) + Permanency(user=user, counter=self, start=timezone.now(), end=None).save() - def del_barman(counter_id, user_id): + def del_barman(self, user): """ Logs a barman out and store its permanency """ - counter_id = int(counter_id) - user_id = int(user_id) - user_tuple = None - for t in Counter.barmen_session[counter_id]['users']: - if t[0] == user_id: user_tuple = t - Counter.barmen_session[counter_id]['users'].remove(user_tuple) - u = User.objects.filter(id=user_id).first() - c = Counter.objects.filter(id=counter_id).first() - Permanency(user=u, counter=c, start=user_tuple[1], end=Counter.barmen_session[counter_id]['time']).save() + perm = Permanency.objects.filter(counter=self, user=user, end=None).all() + for p in perm: + p.end = p.activity + p.save() def get_barmen_list(self): """ @@ -176,19 +165,15 @@ class Counter(models.Model): Also handle the timeout of the barmen """ + pl = Permanency.objects.filter(counter=self, end=None).all() bl = [] - counter_id = self.id - if counter_id in list(Counter.barmen_session.keys()): - for b in Counter.barmen_session[counter_id]['users']: - # Reminder: user is stored as a tuple with its login time - bl.append(User.objects.filter(id=b[0]).first()) - if (timezone.now() - Counter.barmen_session[counter_id]['time']) < timedelta(minutes=settings.SITH_BARMAN_TIMEOUT): - Counter.barmen_session[counter_id]['time'] = timezone.now() + for p in pl: + if timezone.now() - p.activity < timedelta(minutes=settings.SITH_BARMAN_TIMEOUT): + p.save() # Update activity + bl.append(p.user) else: - for b in bl: - Counter.del_barman(counter_id, b.id) - bl = [] - Counter.barmen_session[counter_id]['users'] = set() + p.end = p.activity + p.save() return bl def get_random_barman(self): @@ -292,10 +277,11 @@ class Permanency(models.Model): """ This class aims at storing a traceability of who was barman where and when """ - user = models.ForeignKey(User, related_name="permanencies") - counter = models.ForeignKey(Counter, related_name="permanencies") + user = models.ForeignKey(User, related_name="permanencies", verbose_name=_("user")) + counter = models.ForeignKey(Counter, related_name="permanencies", verbose_name=_("counter")) start = models.DateTimeField(_('start date')) - end = models.DateTimeField(_('end date')) + end = models.DateTimeField(_('end date'), null=True) + activity = models.DateTimeField(_('last activity date'), auto_now=True) class Meta: verbose_name = _("permanency") diff --git a/counter/views.py b/counter/views.py index 63864684..49087b49 100644 --- a/counter/views.py +++ b/counter/views.py @@ -19,9 +19,10 @@ from ajax_select import make_ajax_form, make_ajax_field from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin from core.views.forms import SelectUser +from core.models import User from subscription.models import Subscriber from subscription.views import get_subscriber -from counter.models import Counter, Customer, Product, Selling, Refilling, ProductType +from counter.models import Counter, Customer, Product, Selling, Refilling, ProductType, CashRegisterSummary, CashRegisterSummaryItem class GetUserForm(forms.Form): """ @@ -212,7 +213,7 @@ class CounterClick(DetailView): product = self.get_product(pid) can_buy = False for g in product.buying_groups.all(): - if request.user.is_in_group(g.name): + if self.customer.user.is_in_group(g.name): can_buy = True if not can_buy: request.session['not_allowed'] = True @@ -343,12 +344,13 @@ class CounterLogin(RedirectView): Register the logged user as barman for this counter """ self.counter_id = kwargs['counter_id'] + self.counter = Counter.objects.filter(id=kwargs['counter_id']).first() form = AuthenticationForm(request, data=request.POST) self.errors = [] if form.is_valid(): - user = Subscriber.objects.filter(username=form.cleaned_data['username']).first() - if user.is_subscribed(): - Counter.add_barman(self.counter_id, user.id) + user = User.objects.filter(username=form.cleaned_data['username']).first() + if user.is_in_group(settings.SITH_MAIN_MEMBERS_GROUP) and not user in self.counter.get_barmen_list(): + self.counter.add_barman(user) else: self.errors += ["subscription"] else: @@ -364,8 +366,9 @@ class CounterLogout(RedirectView): """ Unregister the user from the barman """ - self.counter_id = kwargs['counter_id'] - Counter.del_barman(self.counter_id, request.POST['user_id']) + self.counter = Counter.objects.filter(id=kwargs['counter_id']).first() + user = User.objects.filter(id=request.POST['user_id']).first() + self.counter.del_barman(user) return super(CounterLogout, self).post(request, *args, **kwargs) def get_redirect_url(self, *args, **kwargs): @@ -384,8 +387,8 @@ class CounterEditForm(forms.ModelForm): class Meta: model = Counter fields = ['sellers', 'products'] - sellers = make_ajax_field(Counter, 'sellers', 'users', show_help_text=False) - products = make_ajax_field(Counter, 'products', 'products') + sellers = make_ajax_field(Counter, 'sellers', 'users', help_text="") + products = make_ajax_field(Counter, 'products', 'products', help_text="") class CounterEditView(CanEditMixin, UpdateView): """ @@ -394,7 +397,7 @@ class CounterEditView(CanEditMixin, UpdateView): model = Counter form_class = CounterEditForm pk_url_kwarg = "counter_id" - template_name = 'counter/counter_edit.jinja' + template_name = 'core/edit.jinja' def get_success_url(self): return reverse_lazy('counter:admin', kwargs={'counter_id': self.object.id})