Add Bootstrap CSS, management script to load locale data, add new fields to locale models
This commit is contained in:
parent
d70435fdcc
commit
f4cf1c9cda
21 changed files with 335 additions and 19 deletions
|
@ -12,14 +12,21 @@ admin.site.register(Country)
|
|||
|
||||
class SPRAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('country',)
|
||||
list_filter =('country',)
|
||||
search_fields = ('name', 'country__name')
|
||||
admin.site.register(SPR, SPRAdmin)
|
||||
|
||||
class CityAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('spr',)
|
||||
list_filter =('spr__country',)
|
||||
search_fields = ('name', 'spr__name')
|
||||
admin.site.register(City, CityAdmin)
|
||||
|
||||
admin.site.register(UserProfile)
|
||||
admin.site.register(Organization)
|
||||
|
||||
class OrgAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'site')
|
||||
admin.site.register(Organization, OrgAdmin)
|
||||
|
||||
class TeamAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('country', 'spr', 'city', 'owner_profile', 'admin_profiles', 'contact_profiles')
|
||||
|
|
56
events/management/commands/load_cities.py
Normal file
56
events/management/commands/load_cities.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from events.models.locale import Country, SPR, City
|
||||
|
||||
# Fields from geoname table, from http://download.geonames.org/export/dump/readme.txt
|
||||
GEONAMEID=0
|
||||
NAME=1
|
||||
ASCIINAME=2
|
||||
ALTERNATENAMES=3
|
||||
LATITUDE=4
|
||||
LONGITUDE=5
|
||||
FEATURE_CLASS=6
|
||||
FEATURE_CODE=7
|
||||
COUNTRY_CODE=8
|
||||
COUNTRY_CODE_2=9
|
||||
ADMIN1=10
|
||||
ADMIN2=11
|
||||
ADMIN3=12
|
||||
ADMIN4=13
|
||||
POPULATION=14
|
||||
ELEVATION=15
|
||||
DIGITAL_ELEVATION=16
|
||||
TIMEZONE=17
|
||||
MODIFICATION_DATE=18
|
||||
|
||||
COUNTRY_CACHE = dict()
|
||||
SPR_CACHE = dict()
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Loads city data from GeoNames database file'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('file', type=str)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if 'file' in options:
|
||||
# Preload country cache
|
||||
for country in Country.objects.all():
|
||||
COUNTRY_CACHE[country.code] = country
|
||||
for spr in SPR.objects.all():
|
||||
SPR_CACHE["%s.%s"%(spr.country.code, spr.code)] = spr
|
||||
cities_file = open(options['file'], 'r')
|
||||
for city_line in cities_file.readlines():
|
||||
city = city_line.split("\t")
|
||||
if len(city) == 19:
|
||||
if city[FEATURE_CODE] == "PPL" or city[FEATURE_CODE] == "PPLA":
|
||||
country = COUNTRY_CACHE.get(city[COUNTRY_CODE])
|
||||
spr = SPR_CACHE.get("%s.%s"%(city[COUNTRY_CODE], city[ADMIN1]))
|
||||
if country is not None and spr is not None:
|
||||
City.objects.get_or_create(name=city[NAME], spr=spr, tz=city[TIMEZONE])
|
||||
else:
|
||||
print("Short line (%s): %s" % (len(city), city_line))
|
||||
cities_file.close()
|
||||
|
||||
else:
|
||||
print("No File in options!")
|
47
events/management/commands/load_countries.py
Normal file
47
events/management/commands/load_countries.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from events.models.locale import Country
|
||||
|
||||
# Fields from geoname table, from http://download.geonames.org/export/dump/readme.txt
|
||||
ISO=0
|
||||
ISO3=1
|
||||
ISO_NUMERIC=2
|
||||
FIPS=3
|
||||
COUNTRY=4
|
||||
CAPITAL=5
|
||||
AREA=6
|
||||
POPULATION=7
|
||||
CONTINENT=8
|
||||
TLD=9
|
||||
CURRENCYCODE=10
|
||||
CURRENCYNAME=11
|
||||
PHONE=12
|
||||
POSTAL_CODE_FORMAT=13
|
||||
POSTAL_CODE_REGEX=14
|
||||
LANGUAGES=15
|
||||
GEONAMEID=16
|
||||
NEIGHBOURS=17
|
||||
EQUIVALENTFIPSCODE=18
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Loads country data from GeoNames database file'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('file', type=str)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if 'file' in options:
|
||||
countries_file = open(options['file'], 'r')
|
||||
for country_line in countries_file.readlines():
|
||||
if country_line.startswith("#"):
|
||||
continue
|
||||
country = country_line.split("\t")
|
||||
if len(country) == 19:
|
||||
#print("%s - %s" % (country[ISO], country[COUNTRY]))
|
||||
Country.objects.get_or_create(name=country[COUNTRY], code=country[ISO])
|
||||
else:
|
||||
print("Short line (%s): %s" % (len(country), country_line))
|
||||
countries_file.close()
|
||||
|
||||
else:
|
||||
print("No File in options!")
|
41
events/management/commands/load_spr.py
Normal file
41
events/management/commands/load_spr.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from events.models.locale import Country, SPR, City
|
||||
|
||||
# Fields from geoname table, from http://download.geonames.org/export/dump/readme.txt
|
||||
COMBINED_CODE=0
|
||||
NAME=1
|
||||
ASCIINAME=2
|
||||
GEONAMEID=3
|
||||
|
||||
COUNTRY_CACHE = dict()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Loads spr data from GeoNames database file'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('file', type=str)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if 'file' in options:
|
||||
# Preload country cache
|
||||
for country in Country.objects.all():
|
||||
COUNTRY_CACHE[country.code] = country
|
||||
spr_file = open(options['file'], 'r')
|
||||
for spr_line in spr_file.readlines():
|
||||
if spr_line.startswith("#"):
|
||||
continue
|
||||
spr = spr_line.split("\t")
|
||||
if len(spr) ==4:
|
||||
COUNTRY_CODE, SPR_CODE = spr[COMBINED_CODE].split(".")
|
||||
country = COUNTRY_CACHE.get(COUNTRY_CODE)
|
||||
if country is not None:
|
||||
#print("%s - %s, %s" % (SPR_CODE, spr[NAME], country.name))
|
||||
SPR.objects.get_or_create(name=spr[NAME], code=SPR_CODE, country=country)
|
||||
else:
|
||||
print("Short line (%s): %s" % (len(spr), spr_line))
|
||||
spr_file.close()
|
||||
|
||||
else:
|
||||
print("No File in options!")
|
39
events/migrations/0004_auto_20180103_2212.py
Normal file
39
events/migrations/0004_auto_20180103_2212.py
Normal file
File diff suppressed because one or more lines are too long
|
@ -50,7 +50,11 @@ class Event(models.Model):
|
|||
#replies
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('show-event', kwargs={'event_id': self.id, 'event_slug': slugify(self.name)})
|
||||
return reverse('show-event', kwargs={'event_id': self.id, 'event_slug': self.slug})
|
||||
|
||||
@property
|
||||
def slug(self):
|
||||
return slugify(self.name)
|
||||
|
||||
def __str__(self):
|
||||
return u'%s by %s at %s' % (self.name, self.team.name, self.start_time)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import pytz
|
||||
|
||||
class Language(models.Model):
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
|
@ -41,6 +43,7 @@ class Country(models.Model):
|
|||
|
||||
class SPR(models.Model):
|
||||
name = models.CharField(_("Name"), max_length=100)
|
||||
code = models.CharField(_("Admin Code"), max_length=8)
|
||||
country = models.ForeignKey(Country, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
|
@ -63,6 +66,7 @@ class City(models.Model):
|
|||
|
||||
name = models.CharField(_("Name"), max_length=100)
|
||||
spr = models.ForeignKey(SPR, on_delete=models.CASCADE)
|
||||
tz = models.CharField(max_length=32, verbose_name=_('Default Timezone'), default='UTC', choices=[(tz, tz) for tz in pytz.all_timezones], blank=False, null=False, help_text=_('The most commonly used timezone for this Team.'))
|
||||
|
||||
def __str__(self):
|
||||
return u'%s, %s, %s' % (self.name, self.spr.name, self.spr.country.name)
|
||||
|
|
|
@ -45,6 +45,19 @@ class UserProfile(models.Model):
|
|||
local = self.timezone.localize(dt)
|
||||
return local.astimezone(pytz.utc)
|
||||
|
||||
def can_create_event(self, team):
|
||||
if not self.user_id:
|
||||
return False
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
if team.owner_profile == self:
|
||||
return True
|
||||
if self in team.admin_profiles.all():
|
||||
return True
|
||||
if self in team.contact_profiles.all():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_user_timezone(username):
|
||||
# TODO: find a smarter way to get timezone
|
||||
return 'UTC'
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<td><b>Place:</b></td><td>{{ event.place }}</td>
|
||||
{% if event.web_url %}
|
||||
</tr><tr>
|
||||
<td><b>Website:</b></td><td><a href="{{ event.web_url }}">{{ event.web_url }}</a></td>
|
||||
<td><b>Website:</b></td><td><a href="{{ event.web_url }}" target="_blank">{{ event.web_url }}</a></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<table border="0" width="960px">
|
||||
{% for event in events_list %}
|
||||
<tr>
|
||||
<td><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></td>
|
||||
<td>{{ event.team }}</td>
|
||||
<td><a href="{% url 'show-event' event.id event.slug %}">{{ event.name }}</a></td>
|
||||
<td><a href="{% url 'show-team' event.team.id %}">{{ event.team.name }}</a></td>
|
||||
<td>{{ event.start_time }}</td>
|
||||
<td>{{ event.place }}</td>
|
||||
</tr>
|
||||
|
|
18
events/templates/events/team_list.html
Normal file
18
events/templates/events/team_list.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
{% if teams_list %}
|
||||
<table border="0" width="960px">
|
||||
{% for team in teams_list %}
|
||||
<tr>
|
||||
<td><a href="{% url 'show-team' team.id %}">{{ team.name }}</a></td>
|
||||
<td>{{ team.country.name|default:'' }}</td>
|
||||
<td>{{ team.spr.name|default:'' }}</td>
|
||||
<td>{{ team.city.name|default:'' }}</td>
|
||||
<td>{{ team.owner_profile }}</td>
|
||||
<td>{{ team.created_time }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No team available.</p>
|
||||
{% endif %}
|
||||
|
|
@ -1,8 +1,67 @@
|
|||
{% if request.user.is_authenticated %}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
Welcome {{ request.user.username }}
|
||||
<title>Get Together</title>
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous" rel="stylesheet">
|
||||
|
||||
<!-- Bootstrap style overrides -->
|
||||
<style>
|
||||
body {
|
||||
padding-top: 5rem;
|
||||
}
|
||||
.starter-template {
|
||||
padding: 3rem 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<a class="navbar-brand" href="/">GetTogether</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'events' %}">Events <span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'teams' %}">Teams</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" href="#">Places</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="nav-item"><a class="nav-link">Welcome {{ request.user.username }}</a></li>
|
||||
{% else %}
|
||||
<li class="nav-item"><a class="nav-link" href="/">Signup or Login</a></li>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container">
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script>window.jQuery || document.write('<script src="../../../../assets/js/vendor/jquery-slim.min.js"><\/script>')</script>
|
||||
<script src="../../../../assets/js/vendor/popper.min.js"></script>
|
||||
<script src="../../../../dist/js/bootstrap.min.js"></script> </body>
|
||||
</html>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Have a Get Together</h2>
|
||||
<h2>Plan a Get Together</h2>
|
||||
<form action="{% url "create-event" team.id%}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
{% include "events/event_form.html" %}
|
||||
<br />
|
||||
<input type="submit" value="Announce your Get Together!" />
|
||||
<button type="submit" class="btn btn-primary">Announce your Get Together</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% csrf_token %}
|
||||
{% include "events/team_form.html" %}
|
||||
<br />
|
||||
<input type="submit" value="Gather your crew!" />
|
||||
<button type="submit" class="btn btn-primary">Gather your Team</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h4>Upcoming events</h4>
|
||||
{% include "events/event_list.html" %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
<center>
|
||||
<h2>Welcome to Get Together!</h2>
|
||||
|
||||
<h3>Login with:</h3>
|
||||
<a href="{% url 'social:begin' 'google-oauth2' %}">Google</a><br/>
|
||||
<a href="{% url 'social:begin' 'facebook' %}">Facebook</a><br/>
|
||||
<a href="{% url 'social:begin' 'twitter' %}">Twitter</a><br/>
|
||||
<a href="{% url 'social:begin' 'github' %}">GitHub</a><br/>
|
||||
<h3>Login</h3>
|
||||
<a class="btn btn-primary" href="{% url 'social:begin' 'google-oauth2' %}">Google</a>
|
||||
<a class="btn btn-primary" href="{% url 'social:begin' 'facebook' %}">Facebook</a><br/><br/>
|
||||
<a class="btn btn-primary" href="{% url 'social:begin' 'twitter' %}">Twitter</a>
|
||||
<a class="btn btn-primary" href="{% url 'social:begin' 'github' %}">GitHub</a><br/>
|
||||
<br>
|
||||
</center>
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{% block content %}
|
||||
<h2>About {{ event.name }}</h2>
|
||||
|
||||
<h3>Hosted by <a href="{% url "show-team" team.id %}">{{ team.name }}</a></h3>
|
||||
<h4>Hosted by <a href="{% url "show-team" team.id %}">{{ team.name }}</a></h4>
|
||||
{% include "events/event_details.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
{% block content %}
|
||||
<h2>Welcome to {{ team.name }}</h2>
|
||||
|
||||
<h3>Upcoming Events</h3>
|
||||
<h4>Upcoming Events</h4>
|
||||
{% include "events/event_list.html" %}
|
||||
{% if can_create_event %}
|
||||
<br />
|
||||
<form action="{% url 'create-event' team.id %}" method="get">
|
||||
<input type="submit" value="Plan a Get Together!" />
|
||||
<button type="submit" class="btn btn-primary">Plan a Get Together</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
13
get_together/templates/get_together/teams.html
Normal file
13
get_together/templates/get_together/teams.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% include "events/team_list.html" %}
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<br/>
|
||||
<form action="{% url 'create-team' %}" method="get">
|
||||
<button type="submit" class="btn btn-primary">Start a Team</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -25,6 +25,7 @@ urlpatterns = [
|
|||
|
||||
path('events/', views.events_list, name='events'),
|
||||
path('create-team/', views.create_team, name='create-team'),
|
||||
path('teams/', views.teams_list, name='teams'),
|
||||
path('team/<int:team_id>/', views.show_team, name='show-team'),
|
||||
path('team/<int:team_id>/create-event/', views.create_event, name='create-event'),
|
||||
path('events/<int:event_id>/<str:event_slug>/', views.show_event, name='show-event'),
|
||||
|
|
|
@ -22,7 +22,7 @@ def home(request, *args, **kwards):
|
|||
return render(request, 'get_together/index.html')
|
||||
|
||||
def events_list(request, *args, **kwargs):
|
||||
events = Event.objects.all()
|
||||
events = Event.objects.order_by('start_time').all()
|
||||
context = {
|
||||
'events_list': events,
|
||||
}
|
||||
|
@ -51,12 +51,21 @@ def create_team(request, *args, **kwargs):
|
|||
else:
|
||||
return redirect('home')
|
||||
|
||||
def teams_list(request, *args, **kwargs):
|
||||
teams = Team.objects.all()
|
||||
context = {
|
||||
'teams_list': teams,
|
||||
}
|
||||
return render(request, 'get_together/teams.html', context)
|
||||
|
||||
|
||||
def show_team(request, team_id, *args, **kwargs):
|
||||
team = Team.objects.get(id=team_id)
|
||||
team_events = Event.objects.filter(team=team)
|
||||
context = {
|
||||
'team': team,
|
||||
'events_list': team_events,
|
||||
'can_create_event': request.user.profile.can_create_event(team),
|
||||
}
|
||||
return render(request, 'get_together/show_team.html', context)
|
||||
|
||||
|
|
Loading…
Reference in a new issue