diff --git a/contest/admin.py b/contest/admin.py index b821db4..77465c2 100644 --- a/contest/admin.py +++ b/contest/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Frequency, Band, Reference, QSO, User, Contest +from .models import Frequency, Band, Reference, QSO, User, Contest, ShadowCall admin.site.register(User) admin.site.register(QSO) @@ -7,3 +7,4 @@ admin.site.register(Band) admin.site.register(Frequency) admin.site.register(Reference) admin.site.register(Contest) +admin.site.register(ShadowCall) diff --git a/contest/forms.py b/contest/forms.py index b87f7c1..96d7dfa 100644 --- a/contest/forms.py +++ b/contest/forms.py @@ -2,10 +2,10 @@ from django import forms from django.contrib.auth.forms import UserCreationForm from crispy_forms.helper import FormHelper -from crispy_forms.layout import Submit +from crispy_forms.layout import Submit, Layout from django.urls import reverse -from .models import User, Reference, QSO +from .models import User, Reference, QSO, ShadowCall from .validators import CallUsernameValidator, CallLogValidator class CustomUserCreationForm(UserCreationForm): @@ -102,3 +102,26 @@ class QSOFormWithTime(QSOForm): model = QSO fields = ["time", "ownNo", "band", "call", "reportTX", "reportRX", "otherNo", "refStr", "remarks"] +class ShadowCallAddForm(forms.ModelForm): + + class Meta: + model = ShadowCall + fields = ['username'] + + def __init__(self, *args, **kwargs): + super(ShadowCallAddForm, self).__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.form_class = "form-inline " + self.helper.form_style = 'inline' + self.helper.field_template = "bootstrap3/layout/inline_field.html" + self.helper.action = reverse("contest:registerRefs") + self.helper.add_input(Submit('submit', 'Add shadow')) + self.helper.layout = Layout(['username']) + + def clean_username(self): + data = self.cleaned_data["username"] + if User.objects.filter(username=data).count() > 0: + raise forms.ValidationError("A user with this call already exists, this is not a shadow!") + + return data diff --git a/contest/migrations/0010_shadowcall.py b/contest/migrations/0010_shadowcall.py new file mode 100644 index 0000000..8ec4803 --- /dev/null +++ b/contest/migrations/0010_shadowcall.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-01-24 23:28 +from __future__ import unicode_literals + +import contest.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0009_auto_20170123_0139'), + ] + + operations = [ + migrations.CreateModel( + name='ShadowCall', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('username', models.CharField(db_index=True, max_length=20, unique=True, validators=[contest.validators.CallUsernameValidator()])), + ('ref', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contest.Reference')), + ], + ), + ] diff --git a/contest/models.py b/contest/models.py index 75c40ca..0036988 100644 --- a/contest/models.py +++ b/contest/models.py @@ -21,6 +21,13 @@ class Reference(models.Model): def __str__(self): return self.name +class ShadowCall(models.Model): + username = models.CharField(max_length=20, unique=True, db_index=True, validators=[CallUsernameValidator()]) + ref = models.ForeignKey(Reference, models.SET_NULL,null=True, blank=True) + + def __str__(self): + return self.username + class User(AbstractUser): ref = models.ForeignKey(Reference, models.SET_NULL,null=True, blank=True) diff --git a/contest/urls.py b/contest/urls.py index e587faf..48c1103 100644 --- a/contest/urls.py +++ b/contest/urls.py @@ -21,7 +21,8 @@ import contest.views as contest_views urlpatterns = [ url(r'^$', contest_views.contestIndex, name='index'), url(r'^regref/$', contest_views.registerRefs, name='registerRefs'), - url(r'^regref/edit/(?P\d+)/$', contest_views.updateRef, name='updateRef'), + url(r'^regref/edit/(?P\d+)/$', contest_views.updateRef, {"shadow": False}, name='updateRef'), + url(r'^regref/shadow/edit/(?P\d+)/$', contest_views.updateRef, {"shadow": True}, name='updateShadowRef'), url(r'^overview/$', contest_views.overview, name='overview'), url(r'^log/$', contest_views.log, name='log'), url(r'^log/edit/(?P\d+)/$', contest_views.logEdit, name='logEdit'), diff --git a/contest/views.py b/contest/views.py index f226b95..6612f65 100644 --- a/contest/views.py +++ b/contest/views.py @@ -1,8 +1,8 @@ -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib.admin.views.decorators import staff_member_required -from django.db.models import Q +#from django.db.models import Q from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm from django.http import HttpResponseRedirect from django.contrib import messages @@ -11,8 +11,8 @@ from django.contrib.auth import login as auth_login import datetime -from .models import User, Contest, Frequency, Reference, QSO -from .forms import UpdateRefForm, QSOForm, QSOFormWithTime, CustomUserCreationForm +from .models import User, Contest, Frequency, Reference, QSO, ShadowCall +from .forms import UpdateRefForm, QSOForm, QSOFormWithTime, CustomUserCreationForm, ShadowCallAddForm def index(request): if request.user.is_authenticated(): @@ -106,24 +106,37 @@ def logDelete(request, qsoid): @staff_member_required def registerRefs(request): allUser = User.objects.all() - refsMissingUser = User.objects.filter(ref=None).order_by("username") - refsNotMissingUser = User.objects.filter(~Q(ref=None)).order_by("username") + shadows = ShadowCall.objects.all() qsos = QSO.objects.all().order_by("-time") - return render(request, 'contest/registerRefs.html', {'alluser': allUser, 'refsMissingUser': refsMissingUser, "refsNotMissinguser": refsNotMissingUser, "qsos": qsos}) + shadowForm = None + if request.method == 'POST': + shadowForm = ShadowCallAddForm(data=request.POST) + if shadowForm.is_valid(): + shadowForm.instance.save() + messages.success(request, "Successfully added shadow user %s" % (shadowForm.instance.username,)) + return HttpResponseRedirect(reverse("contest:registerRefs")) + else: + shadowForm = ShadowCallAddForm() + + return render(request, 'contest/registerRefs.html', {'alluser': allUser, "qsos": qsos, "shadowForm": shadowForm, "shadows": shadows}) @staff_member_required -def updateRef(request, uid): - user = User.objects.get(id=uid) +def updateRef(request, shadow, uid): + user = None form = None + if shadow: + user = get_object_or_404(ShadowCall, id=uid) + else: + user = get_object_or_404(User, id=uid) + if request.method == 'POST': form = UpdateRefForm(data=request.POST) if form.is_valid(): ref = None if form.cleaned_data["existingRef"]: - print("Got an existing Ref") ref = form.cleaned_data["existingRef"] else: ref = Reference(name=form.cleaned_data["newRefName"]) @@ -132,12 +145,12 @@ def updateRef(request, uid): user.ref = ref user.save() - messages.success(request, "%s ref set to %s" % (user, ref)) + messages.success(request, "%s%s ref set to %s" % ("(shadow) " if shadow else "", user, ref)) return HttpResponseRedirect(reverse("contest:registerRefs")) else: form = UpdateRefForm() - return render(request, 'contest/updateRef.html', {'user': user, 'form': form}) + return render(request, 'contest/updateRef.html', {'userobj': user, 'form': form, "shadow": shadow}) def overview(request): # FIXME: Hardcoded for cqtu... everywhere diff --git a/templates/contest/registerRefs.html b/templates/contest/registerRefs.html index 5ab0866..8c92236 100644 --- a/templates/contest/registerRefs.html +++ b/templates/contest/registerRefs.html @@ -1,30 +1,67 @@ {% extends "base.html" %} +{% load crispy_forms_tags %} + {% block content %}
-
-
Contest Stations
-
- Here is a Table with all OMs/YLs in the contest! - - - - - - - - - - {% for u in alluser %} - - - - +
+
+
+
Contest Stations
+
+ Here is a Table with all OMs/YLs in the contest! +
CallRef
{{ u.username }}{{ u.ref|default:"unknown / unset" }}Update / Create ref
+ + + + + - {% endfor %} - -
CallRef
+ + + {% for u in alluser %} + + {{ u.username }} + {{ u.ref|default:"unknown / unset" }} + Update / Create ref + + {% endfor %} + + +
+
+
+
+
+
Shadow Stations (unregistered, but active)
+
+ {% if shadowForm.errors %} +
+ {{ shadowForm.errors }} +
+ {% endif %} + {% crispy shadowForm %} + + + + + + + + + + {% for shadow in shadows %} + + + + + {% endfor %} + +
CallRef
{{ shadow.username }}{{ shadow.ref|default:"unknown / unset" }}Update / create ref +
+
+
diff --git a/templates/contest/updateRef.html b/templates/contest/updateRef.html index 8dc0859..401e53b 100644 --- a/templates/contest/updateRef.html +++ b/templates/contest/updateRef.html @@ -9,14 +9,14 @@
Edit Exchange for User

- Create a ref for user {{ user }} or choose an existing ref! + Create a ref for {% if shadow %}shadow call{% else %}user{% endif %} {{ userobj }} or choose an existing ref!

-
+ {% csrf_token %}
- -
{{ user }}
+ +
{{ userobj }}
{{ form|crispy }}