Added shadow users
This commit is contained in:
parent
c9e76b468a
commit
c2309a4086
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,30 +1,67 @@
|
||||||
{% 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="panel panel-default">
|
<div class="row">
|
||||||
<div class="panel-heading">Contest Stations</div>
|
<div class="col-md-12">
|
||||||
<div class="panel-body">
|
<div class="panel panel-default">
|
||||||
Here is a Table with all OMs/YLs in the contest!
|
<div class="panel-heading">Contest Stations</div>
|
||||||
<table class="table">
|
<div class="panel-body">
|
||||||
<thead>
|
Here is a Table with all OMs/YLs in the contest!
|
||||||
<tr>
|
<table class="table">
|
||||||
<th>Call</th>
|
<thead>
|
||||||
<th>Ref</th>
|
<tr>
|
||||||
<th></th>
|
<th>Call</th>
|
||||||
</tr>
|
<th>Ref</th>
|
||||||
</thead>
|
<th></th>
|
||||||
<tbody>
|
|
||||||
{% for u in alluser %}
|
|
||||||
<tr class="{% if not u.ref %}danger{% endif %}">
|
|
||||||
<td>{{ u.username }}</td>
|
|
||||||
<td>{{ u.ref|default:"unknown / unset" }}</td>
|
|
||||||
<td><a href="{% url "contest:updateRef" u.id %}">Update / Create ref</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{% for u in alluser %}
|
||||||
|
<tr class="{% if not u.ref %}danger{% endif %}">
|
||||||
|
<td>{{ u.username }}</td>
|
||||||
|
<td>{{ u.ref|default:"unknown / unset" }}</td>
|
||||||
|
<td><a href="{% url "contest:updateRef" u.id %}">Update / Create ref</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Loading…
Reference in New Issue