1
0
Fork 0

First iteration on suggestions forms

merge-requests/8/head
Nikos Roussos 2015-04-25 19:47:22 +03:00
parent 1befe28bb1
commit 2134f44b49
11 changed files with 331 additions and 26 deletions

View File

@ -1,18 +1,27 @@
from django.contrib import admin
from db.base.models import Satellite, Transponder
from db.base.models import Satellite, Transponder, Suggestion
@admin.register(Satellite)
class SatelliteAdmin(admin.ModelAdmin):
list_display = ('name', 'norad_cat_id')
@admin.register(Transponder)
class TransponderAdmin(admin.ModelAdmin):
list_display = ('description', 'satellite', 'uplink_low',
'uplink_high', 'downlink_low', 'downlink_high')
search_fields = ('satellite', )
list_filter = ('mode', 'invert', 'approved')
list_filter = ('mode', 'invert')
admin.site.register(Satellite, SatelliteAdmin)
admin.site.register(Transponder, TransponderAdmin)
@admin.register(Suggestion)
class SuggestionAdmin(admin.ModelAdmin):
list_display = ('description', 'suggestion', 'user', 'satellite', 'uplink_low',
'uplink_high', 'downlink_low', 'downlink_high', 'approved')
search_fields = ('satellite', 'approved')
list_filter = ('mode', 'invert')
def get_queryset(self, request):
return Transponder.objects_all.filter(approved=False)

14
db/base/forms.py 100644
View File

@ -0,0 +1,14 @@
from django import forms
from django.forms import ModelForm
from db.base.models import Transponder
class SatelliteSearchForm(forms.Form):
term = forms.CharField()
class TransponderSuggestionForm(forms.ModelForm):
class Meta:
model = Transponder
exclude = ['approved']

View File

@ -10,7 +10,7 @@ class Command(BaseCommand):
help = 'Create initial fixtures'
def handle(self, *args, **options):
TransponderFactory.create_batch(20, suggestion=None)
TransponderFactory.create_batch(20, suggestion=None, approved=True, user=None)
satellites = Satellite.objects.all()

View File

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('base', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Suggestion',
fields=[
],
options={
'proxy': True,
},
bases=('base.transponder',),
),
migrations.AddField(
model_name='transponder',
name='citation',
field=models.URLField(max_length=255, blank=True),
),
migrations.AddField(
model_name='transponder',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AlterField(
model_name='transponder',
name='satellite',
field=models.ForeignKey(related_name='transponders', to='base.Satellite', null=True),
),
]

View File

@ -1,17 +1,23 @@
from django.core.validators import MinValueValidator
from django.db import models
from django.contrib.auth.models import User
MODE_CHOICES = ['FM', 'AFSK', 'BFSK', 'APRS', 'SSTV', 'CW', 'FMN']
class TransponderApprovedManager(models.Manager):
def get_queryset(self):
return super(TransponderApprovedManager, self).get_queryset().filter(approved=True)
class Satellite(models.Model):
"""Model for SatNOGS satellites."""
norad_cat_id = models.PositiveIntegerField()
name = models.CharField(max_length=45)
def __unicode__(self):
return self.name
return '{0} - {1}'.format(self.norad_cat_id, self.name)
class Transponder(models.Model):
@ -26,12 +32,23 @@ class Transponder(models.Model):
max_length=10)
invert = models.BooleanField(default=False)
baud = models.FloatField(validators=[MinValueValidator(0)])
satellite = models.ForeignKey(Satellite, related_name='transponder',
satellite = models.ForeignKey(Satellite, related_name='transponders',
null=True)
approved = models.BooleanField(default=False)
suggestion = models.ForeignKey('self', blank=True, null=True,
on_delete=models.SET_NULL,
related_name="suggestions")
citation = models.URLField(max_length=255, blank=True)
user = models.ForeignKey(User, blank=True, null=True,
on_delete=models.SET_NULL)
objects = TransponderApprovedManager()
objects_all = models.Manager()
def __unicode__(self):
return self.description
class Suggestion(Transponder):
class Meta:
proxy = True

View File

@ -1,9 +1,19 @@
from django.contrib.auth.models import User
import factory
from factory import fuzzy
from db.base.models import MODE_CHOICES, Satellite, Transponder
class UserFactory(factory.django.DjangoModelFactory):
"""User model factory"""
username = factory.Sequence(lambda n: "user_%d" % n)
class Meta:
model = User
class SatelliteFactory(factory.django.DjangoModelFactory):
"""Sattelite model factory."""
norad_cat_id = fuzzy.FuzzyInteger(2000, 4000)
@ -26,6 +36,8 @@ class TransponderFactory(factory.django.DjangoModelFactory):
satellite = factory.SubFactory(SatelliteFactory)
approved = fuzzy.FuzzyChoice(choices=[True, False])
suggestion = factory.SubFactory('db.base.tests.TransponderFactory')
citation = fuzzy.FuzzyText()
user = factory.SubFactory('db.base.tests.UserFactory')
class Meta:
model = Transponder

View File

@ -3,4 +3,5 @@ from django.conf.urls import patterns, url
urlpatterns = patterns(
'db.base.views',
url(r'^$', 'home', name='home'),
url(r'^suggestion/$', 'suggestion', name='suggestion'),
)

View File

@ -1,15 +1,54 @@
from django.shortcuts import render
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.core.urlresolvers import reverse
from db.base.models import Transponder, Satellite
from db.base.models import Transponder, Satellite, MODE_CHOICES
from db.base.forms import SatelliteSearchForm, TransponderSuggestionForm
def home(request):
"""View to render index page."""
satellites = Satellite.objects.all()
transponders = Transponder.objects.all()
contributors = User.objects.filter(is_active=1)
if request.method == 'POST':
satellite_form = SatelliteSearchForm(request.POST)
if satellite_form.is_valid():
term = satellite_form.cleaned_data['term']
norad_cat_id = term.split()[0]
try:
satellite = Satellite.objects.get(norad_cat_id=norad_cat_id)
except:
messages.error(request, 'Please select one of the available Satellites')
return redirect(reverse('home'))
return render(request, 'base/home.html', {'satellites': satellites,
'transponders': transponders,
'satellite': satellite,
'contributors': contributors,
'satellite_form': satellite_form,
'modes': MODE_CHOICES})
return render(request, 'base/home.html', {'satellites': satellites,
'transponders': transponders,
'contributors': contributors})
@login_required
@require_POST
def suggestion(request):
suggestion_form = TransponderSuggestionForm(request.POST)
if suggestion_form.is_valid():
suggestion = suggestion_form.save(commit=False)
suggestion.user = request.user
suggestion.save()
messages.success(request, 'Your suggestion was stored successfully. Thanks for contibuting!')
return redirect(reverse('home'))
messages.error(request, 'We are sorry, but some error occured :(')
return redirect(reverse('home'))

View File

@ -1,4 +1,17 @@
$(document).ready(function() {
'use strict';
$('#search-input').focus();
$('#search-input').keypress(function (e) {
if (e.which == 13) {
$('#search-form').submit();
return false;
}
});
$('#search-button').click(function (e) {
$('#search-form').submit();
return false;
});
});

View File

@ -20,34 +20,42 @@
<div class="row" id="search">
<div class="col-md-12">
<form method="post" action="">
<input type="text" list="satellites-list"
<form method="post" action="{% url 'home' %}" id="search-form">{% csrf_token %}
<div class="input-group">
<input type="text" name="term" list="satellites-list" id="search-input"
class="form-control input-lg satellite-search"
placeholder="Search for satellite (NORAD Cat ID or Name)">
placeholder="Select Satellite (Type NORAD Cat ID or Name)" autocomplete="off">
<div class="input-group-addon">
<a href="#" id="search-button">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</a>
</div>
</div>
<datalist id="satellites-list">
{% for sat in satellites %}
<option value="{{ sat.name }}">
<option value="{{ sat }}">
{% endfor %}
</datalist>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12 satellite-panels">
{% for sat in satellites %}
{% if satellite %}
<div class="row">
<div class="col-md-12 satellite-panels">
<div class="panel panel-default panel-satellite">
<div class="panel-heading">
<h3 class="panel-title">
<span class="satellite-title">{{ sat.norad_cat_id }} {{ sat.name }}</span>
<span class="satellite-title">{{ satellite }}</span>
<button type="button"
class="btn btn-default btn-sm pull-right add-transponder">
class="btn btn-default btn-sm pull-right add-transponder"
data-toggle="modal" data-target="#NewSuggestionModal">
<span class="glyphicon glyphicon-plus" title="Suggest new transponder"></span>
</button>
</h3>
</div>
{% for transponder in sat.transponder.all %}
{% for transponder in satellite.transponders.all %}
<div class="row panel-body">
<div class="col-md-12">
<div class="panel panel-default panel-transponder">
@ -57,7 +65,7 @@
<button type="button"
class="btn btn-default btn-sm pull-right suggest-transponder"
data-toggle="modal"
data-target="#editModal">
data-target="#EditSuggestionModal">
<span class="glyphicon glyphicon-edit" title="Suggest edits"></span>
</button>
</h3>
@ -65,19 +73,170 @@
<div class="panel-body">
<div class="container transponder-element">
<div class="col-md-3">
<span class="label label-default">{{ transponder.key }}</span>
<span class="pull-right">{{ transponder.value }}</span>
<span class="label label-default">Uplink Low</span>
<span class="pull-right">{{ transponder.uplink_low }} - {{ transponder.approved }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Edit Suggestion Modal -->
<div class="modal fade" id="EditSuggestionModal" tabindex="-1" role="dialog" aria-labelledby="EditSuggestionModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="EditSuggestionModalLabel">Suggest an edit to this Transponder</h4>
</div>
{% if request.user.is_authenticated %}
<form action="{% url 'suggestion' %}" method="post" id="editsuggestion-form">{% csrf_token %}
<div class="modal-body">
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Description</div>
<input type="text" class="form-control" name="description" value="{{ transponder.description }}">
</div>
<div class="input-group transponder-element-suggest">
<input type="checkbox" value="1" name="alive" {% if transponder.alive %}checked{% endif %}> Alive
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Uplink Low</div>
<input type="text" class="form-control" name="uplink_low" value="{{ transponder.uplink_low }}">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Uplink High</div>
<input type="text" class="form-control" name="uplink_high" value="{{ transponder.uplink_high }}">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Downlink Low</div>
<input type="text" class="form-control" name="downlink_low" value="{{ transponder.downlink_low }}">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Downlink High</div>
<input type="text" class="form-control" name="downlink_high" value="{{ transponder.downlink_high }}">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Mode</div>
<select class="form-control" name="mode">
{% for mode in modes %}
<option value="{{ mode }}" {% ifequal transponder.mode mode %}selected{% endifequal %}>
{{ mode }}
</option>
{% endfor %}
</select>
</div>
<div class="input-group transponder-element-suggest">
<input type="checkbox" value="1" name="invert" {% if transponder.invert %}checked{% endif %}> Invert
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Baud Rate</div>
<input type="text" class="form-control" name="baud" value="{{ transponder.baud }}">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Citation URL</div>
<input type="url" class="form-control" name="citation" value="{{ transponder.citation }}">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Send</button>
</div>
<input type="hidden" name="suggestion" value="{{ transponder.pk }}">
<input type="hidden" name="satellite" value="{{ satellite.pk }}">
</form>
{% else %}
<div class="modal-body">
<div class="text-danger">You need to login first to add a new suggestion.</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal">Close</button>
<a href="{% url 'account_login' %}" class="btn btn-primary">Log In</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Suggestion Modal -->
<div class="modal fade" id="NewSuggestionModal" tabindex="-1" role="dialog" aria-labelledby="NewSuggestionModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="NewSuggestionModalLabel">Suggest a new Transponder</h4>
</div>
{% if request.user.is_authenticated %}
<form action="{% url 'suggestion' %}" method="post" id="newsuggestion-form">{% csrf_token %}
<div class="modal-body">
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Description</div>
<input type="text" class="form-control" name="description">
</div>
<div class="input-group transponder-element-suggest">
<input type="checkbox" value="1" name="alive"> Alive
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Uplink_Low</div>
<input type="text" class="form-control" name="uplink_low">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Uplink High</div>
<input type="text" class="form-control" name="uplink_high">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Downlink Low</div>
<input type="text" class="form-control" name="downlink_low">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Downlink High</div>
<input type="text" class="form-control" name="downlink_high">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Mode</div>
<select class="form-control" name="mode">
{% for mode in modes %}
<option value="{{ mode }}">
{{ mode }}
</option>
{% endfor %}
</select>
</div>
<div class="input-group transponder-element-suggest">
<input type="checkbox" value="1" name="invert"> Invert
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Baud Rate</div>
<input type="text" class="form-control" name="baud">
</div>
<div class="input-group transponder-element-suggest">
<div class="input-group-addon">Citation URL</div>
<input type="url" class="form-control" name="citation">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Send</button>
</div>
<input type="hidden" name="satellite" value="{{ satellite.pk }}">
</form>
{% else %}
<div class="modal-body">
<div class="text-danger">You need to login first to add a new suggestion.</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal">Close</button>
<a href="{% url 'account_login' %}" class="btn btn-primary">Log In</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="info row">
<div class="col-md-4">

View File

@ -9,7 +9,7 @@ urlpatterns = patterns(
'',
# Base
url(r'^$', include('db.base.urls')),
url(r'^', include('db.base.urls')),
# Accounts
url(r'^accounts/', include('allauth.urls')),