Added shadow users

This commit is contained in:
Sebastian Lohff 2017-01-25 01:53:22 +01:00
parent c9e76b468a
commit c2309a4086
8 changed files with 148 additions and 41 deletions

View File

@ -1,5 +1,5 @@
from django.contrib import admin 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(User)
admin.site.register(QSO) admin.site.register(QSO)
@ -7,3 +7,4 @@ admin.site.register(Band)
admin.site.register(Frequency) admin.site.register(Frequency)
admin.site.register(Reference) admin.site.register(Reference)
admin.site.register(Contest) admin.site.register(Contest)
admin.site.register(ShadowCall)

View File

@ -2,10 +2,10 @@ from django import forms
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from crispy_forms.helper import FormHelper 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 django.urls import reverse
from .models import User, Reference, QSO from .models import User, Reference, QSO, ShadowCall
from .validators import CallUsernameValidator, CallLogValidator from .validators import CallUsernameValidator, CallLogValidator
class CustomUserCreationForm(UserCreationForm): class CustomUserCreationForm(UserCreationForm):
@ -102,3 +102,26 @@ class QSOFormWithTime(QSOForm):
model = QSO model = QSO
fields = ["time", "ownNo", "band", "call", "reportTX", "reportRX", "otherNo", "refStr", "remarks"] 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

View File

@ -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')),
],
),
]

View File

@ -21,6 +21,13 @@ class Reference(models.Model):
def __str__(self): def __str__(self):
return self.name 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): class User(AbstractUser):
ref = models.ForeignKey(Reference, models.SET_NULL,null=True, blank=True) ref = models.ForeignKey(Reference, models.SET_NULL,null=True, blank=True)

View File

@ -21,7 +21,8 @@ import contest.views as contest_views
urlpatterns = [ urlpatterns = [
url(r'^$', contest_views.contestIndex, name='index'), url(r'^$', contest_views.contestIndex, name='index'),
url(r'^regref/$', contest_views.registerRefs, name='registerRefs'), url(r'^regref/$', contest_views.registerRefs, name='registerRefs'),
url(r'^regref/edit/(?P<uid>\d+)/$', contest_views.updateRef, name='updateRef'), url(r'^regref/edit/(?P<uid>\d+)/$', contest_views.updateRef, {"shadow": False}, name='updateRef'),
url(r'^regref/shadow/edit/(?P<uid>\d+)/$', contest_views.updateRef, {"shadow": True}, name='updateShadowRef'),
url(r'^overview/$', contest_views.overview, name='overview'), url(r'^overview/$', contest_views.overview, name='overview'),
url(r'^log/$', contest_views.log, name='log'), url(r'^log/$', contest_views.log, name='log'),
url(r'^log/edit/(?P<qsoid>\d+)/$', contest_views.logEdit, name='logEdit'), url(r'^log/edit/(?P<qsoid>\d+)/$', contest_views.logEdit, name='logEdit'),

View File

@ -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.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_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.contrib.auth.forms import AuthenticationForm, PasswordChangeForm
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.contrib import messages from django.contrib import messages
@ -11,8 +11,8 @@ from django.contrib.auth import login as auth_login
import datetime import datetime
from .models import User, Contest, Frequency, Reference, QSO from .models import User, Contest, Frequency, Reference, QSO, ShadowCall
from .forms import UpdateRefForm, QSOForm, QSOFormWithTime, CustomUserCreationForm from .forms import UpdateRefForm, QSOForm, QSOFormWithTime, CustomUserCreationForm, ShadowCallAddForm
def index(request): def index(request):
if request.user.is_authenticated(): if request.user.is_authenticated():
@ -106,24 +106,37 @@ def logDelete(request, qsoid):
@staff_member_required @staff_member_required
def registerRefs(request): def registerRefs(request):
allUser = User.objects.all() allUser = User.objects.all()
refsMissingUser = User.objects.filter(ref=None).order_by("username") shadows = ShadowCall.objects.all()
refsNotMissingUser = User.objects.filter(~Q(ref=None)).order_by("username")
qsos = QSO.objects.all().order_by("-time") 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 @staff_member_required
def updateRef(request, uid): def updateRef(request, shadow, uid):
user = User.objects.get(id=uid) user = None
form = 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': if request.method == 'POST':
form = UpdateRefForm(data=request.POST) form = UpdateRefForm(data=request.POST)
if form.is_valid(): if form.is_valid():
ref = None ref = None
if form.cleaned_data["existingRef"]: if form.cleaned_data["existingRef"]:
print("Got an existing Ref")
ref = form.cleaned_data["existingRef"] ref = form.cleaned_data["existingRef"]
else: else:
ref = Reference(name=form.cleaned_data["newRefName"]) ref = Reference(name=form.cleaned_data["newRefName"])
@ -132,12 +145,12 @@ def updateRef(request, uid):
user.ref = ref user.ref = ref
user.save() 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")) return HttpResponseRedirect(reverse("contest:registerRefs"))
else: else:
form = UpdateRefForm() 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): def overview(request):
# FIXME: Hardcoded for cqtu... everywhere # FIXME: Hardcoded for cqtu... everywhere

View File

@ -1,8 +1,12 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Contest Stations</div> <div class="panel-heading">Contest Stations</div>
<div class="panel-body"> <div class="panel-body">
@ -28,6 +32,39 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">Shadow Stations <small>(unregistered, but active)</small></div>
<div class="panel-body">
{% if shadowForm.errors %}
<div class="alert alert-danger">
{{ shadowForm.errors }}
</div>
{% endif %}
{% crispy shadowForm %}
<table class="table">
<thead>
<tr>
<th>Call</th>
<th>Ref</th>
<th></th>
</tr>
</thead>
<tbody>
{% for shadow in shadows %}
<tr>
<td>{{ shadow.username }}</td>
<td>{{ shadow.ref|default:"unknown / unset" }}</td>
<td><a href="{% url "contest:updateShadowRef" shadow.id %}">Update / create ref</a>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6"> <div class="col-md-6">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Current QSOs</div> <div class="panel-heading">Current QSOs</div>

View File

@ -9,14 +9,14 @@
<div class="panel-heading">Edit Exchange for User</div> <div class="panel-heading">Edit Exchange for User</div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
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!
</p> </p>
<form method="post" action="{% url "contest:updateRef" user.id %}"> <form method="post" action="{% if shadow %}{% url "contest:updateShadowRef" userobj.id %}{% else %}{% url "contest:updateRef" userobj.id %}{% endif %}">
{% csrf_token %} {% csrf_token %}
<div class="form-group"> <div class="form-group">
<label class="control-label" for="id_div_user">User</label> <label class="control-label" for="id_div_user">Call</label>
<div id="id_div_user" class="controls readonly">{{ user }}</div> <div id="id_div_user" class="controls readonly">{{ userobj }}</div>
</div> </div>
{{ form|crispy }} {{ form|crispy }}
<input type="submit" value="Save"> <input type="submit" value="Save">