Commit 3cbc55a0 authored by Lysander Trischler's avatar Lysander Trischler

Let user take exercise date times from GPX

parent 56283f7a
......@@ -161,7 +161,7 @@ if __name__ == "__main__":
raise tornado.web.HTTPError(404)
if own and exercise.username != self.current_user.username:
raise tornado.web.HTTPError(403)
return exercise
return Exercise(**exercise)
def get_gpx_file(self, gpx_file_id):
......@@ -239,11 +239,11 @@ if __name__ == "__main__":
class ListExercisesHandler(BaseHandler):
@authenticated
def get(self):
self.render("exercises.html", exercises=self.db.query("""
self.render("exercises.html", exercises=[Exercise(**exercise) for exercise in self.db.query("""
SELECT id, username, discipline, count, start, end
FROM exercises
ORDER BY start DESC, end DESC, count, username
"""))
""")])
@route(r'/exercises/add', aliases=[r'/add'])
class AddExerciseHandler(BaseHandler):
......@@ -629,16 +629,44 @@ if __name__ == "__main__":
self.redirect(self.reverse_url("ViewExerciseHandler", exercise_id))
@route(r'/exercises/(\d+)/update_from_gpx')
class UpdateFromGPXHandler(BaseHandler):
def post(self, exercise_id):
exercise = self.get_exercise(exercise_id)
start = self.get_string_argument("start", None)
end = self.get_string_argument("end", None)
update = []
args = []
if start:
update.append("start = %s")
args.append(datetime.datetime.strptime(start, "%Y-%m-%d %H:%M:%S"))
if end:
update.append("end = %s")
args.append(datetime.datetime.strptime(end, "%Y-%m-%d %H:%M:%S"))
if update:
args.append(exercise_id)
self.db.execute("""
UPDATE exercises
SET """ + ", ".join(update) + """
WHERE id = %s
""", *args)
self.success_messages.append("Übungszeitraum erfolgreich aktualisiert.")
self.redirect(self.reverse_url("ViewExerciseHandler", exercise_id))
@route(r'/users/', aliases=[r'/users'])
class ListUsersHandler(BaseHandler):
@authenticated
def get(self):
self.render("users.html", users=self.db.query("""
self.render("users.html", users=[Exercise(**exercise) for exercise in self.db.query("""
SELECT username, SUM(count) AS count_sum
FROM exercises
GROUP BY username
ORDER BY username ASC, count_sum ASC
"""))
""")])
@route(r'/users/(.+)')
class ViewUserHandler(ListUsersHandler):
......@@ -706,12 +734,12 @@ if __name__ == "__main__":
def get(self):
start = datetime.datetime.combine(self.today, datetime.time(hour=3))
end = start + datetime.timedelta(days=1)
self.render("today.html", exercises=self.db.query("""
self.render("today.html", exercises=[Exercise(**exercise) for exercise in self.db.query("""
SELECT id, username, discipline, count, start, end
FROM exercises
WHERE start >= %s AND start < %s
ORDER BY start DESC, end DESC, count, username
""", start, end))
""", start, end)])
@route(r'/api/')
class APIHandler(BaseHandler):
......@@ -910,8 +938,29 @@ if __name__ == "__main__":
self.user = user
self.discipline = discipline or u"Bauchaufzüge"
self.count = count or (0 if count == 0 else 20)
self.start = start or datetime.datetime.now()
self.end = end or datetime.datetime.now()
self._start = start or datetime.datetime.now()
self._end = end or datetime.datetime.now()
@property
def start(self):
if self._start.tzinfo is None:
self._start = berlin.localize(self._start)
return self._start
@start.setter
def start(self, start):
self._start = start
@property
def end(self):
if self._end.tzinfo is None:
self._end = berlin.localize(self._end)
return self._end
@end.setter
def end(self, end):
self._end = end
def __repr__(self):
return u"<Exercise id=%s username=%s user=%s discipline=%s count=%s start=%s end=%s" % (
self.id, self.username, self.user, self.discipline, self.count, self.start, self.end)
......
......@@ -97,83 +97,6 @@ body {
margin: 0;
padding: 0;
width: 55em;
> fieldset {
margin: 0;
padding: .5em;
> dl {
margin: 0;
padding: 0;
position: relative;
> dt {
clear: left;
float: left;
width: 10em;
text-align: right;
margin: 0;
padding: .2em 0;
font-weight: bold;
&:after { content: ":"; }
&.required:before { content: "* "; }
&.error { color: red; }
}
> dd {
margin: 0 0 0 10.5em;
padding: .2em 0;
width: 44.5em;
> p {
margin: 0;
padding: 0;
&.info {
visibility: hidden;
position: absolute;
width: 13.5em;
top: 0;
right: 0;
text-align: right;
&:before { content: "Ausfüllhinweis: "; }
}
}
> input,
> textarea,
> select,
> p.error {
width: 30em;
font-size: 1em;
font-family: sans-serif;
}
> input:focus + p.info,
> textarea:focus + p.info,
> select:focus + p.info {
visibility: visible;
}
}
}
> p.buttonbox {
text-align: right;
margin: 1em 0 0 0;
width: 40.5em;
> input[type=submit] {
width: 8em;
font-size: 1em;
}
> input[type=submit][name=preview] {
font-weight: bold;
}
}
}
}
> p + table,
......@@ -218,6 +141,84 @@ body {
font-size: .65em;
}
fieldset {
margin: 0;
padding: .5em;
> dl {
margin: 0;
padding: 0;
position: relative;
> dt {
clear: left;
float: left;
width: 10em;
text-align: right;
margin: 0;
padding: .2em 0;
font-weight: bold;
&:after { content: ":"; }
&.required:before { content: "* "; }
&.error { color: red; }
}
> dd {
margin: 0 0 0 10.5em;
padding: .2em 0;
width: 44.5em;
> p {
margin: 0;
padding: 0;
&.info {
visibility: hidden;
position: absolute;
width: 13.5em;
top: 0;
right: 0;
text-align: right;
&:before { content: "Ausfüllhinweis: "; }
}
}
> input,
> textarea,
> select,
> p.error {
width: 30em;
font-size: 1em;
font-family: sans-serif;
}
> input:focus + p.info,
> textarea:focus + p.info,
> select:focus + p.info {
visibility: visible;
}
}
}
> p.buttonbox {
text-align: right;
margin: 1em 0 0 0;
width: 40.5em;
> input[type=submit] {
width: 8em;
font-size: 1em;
}
> input[type=submit][name=preview] {
font-weight: bold;
}
}
}
.error { background: @error-background; color: @error-foreground; }
.warning { background: @warning-background; color: @warning-foreground; }
.information { background: @information-background; color: @information-foreground; }
......
......@@ -8,107 +8,152 @@
{% block content %}
<section>
<h1>Übung {{ exercise.discipline }} betrachten</h1>
<form action="{{ request.uri }}" method=post enctype=multipart/form-data>
<fieldset>
<legend>Übungsdaten</legend>
<dl>
<dt>Disziplin</dt>
<dd>{{ exercise.discipline }}</dd>
<dt>Benutzer</dt>
<dd>{% module user_link(username=exercise.username) %}</dd>
<dt>Anzahl</dt>
<dd>{{ exercise.count }}</dd>
{% set fmt = "%d.%m.%Y %H:%M:%S" %}
<dt>Beginn</dt>
<dd>{{ exercise.start.strftime(fmt) }}</dd>
<dt>Ende</dt>
<dd>{{ exercise.end.strftime(fmt) }}</dd>
<dt>Dauer</dt>
<dd>{{ (exercise.end - exercise.start) }} h</dd>
</dl>
</fieldset>
{% if gpx_files %}
{% if current_user.username == exercise.username %}
{% set starts = any([exercise.start != gpx_file.start for gpx_file in gpx_files]) %}
{% set ends = any([exercise.end != gpx_file.end for gpx_file in gpx_files]) %}
{% if starts or ends %}
<form action={{ reverse_url("UpdateFromGPXHandler", exercise.id) }} method=post enctype=application/x-www-form-urlencoded>
<fieldset>
<legend>Übungsdaten anpassen</legend>
<p>
{% if starts and not ends %}
Es wurde festgestellt, dass der Beginn der Übung mit dem der GPS-Trajektorie nicht übereinstimmt.
{% elif not starts and ends %}
Es wurde festgestellt, dass das Ende der Übung mit dem der GPS-Trajektorie nicht übereinstimmt.
{% elif starts and ends %}
Es wurde festgestellt, dass sowohl der Beginn als auch das Ende der Übung nicht mit denen der GPS-Trajektorie übereinstimmen.
{% else %}
Hmm, es wurde festgestellt, dass sowohl Beginn als auch Ende der Übung mit denen der GPS-Trajektorie tadellos übereinstimmen. Eigentlich sollte diese Meldung gar nicht erscheinen…
{% end %}
Der Zeitraum der Übung kann automatisch korrigiert werden.
</p>
<dl>
{% if starts %}
<dt>Beginn</dt>
<dd><label><input type=radio name=start value="" checked=checked /> <i>Aus Übung behalten</i></label></dd>
{% for gpx_file in gpx_files %}
{% if gpx_file.start != exercise.start %}
<dd><label><input type=radio name=start value="{{ gpx_file.start.strftime("%Y-%m-%d %H:%M:%S") }}" /> aus GPS-Trajektorie übernehmen ({{ gpx_file.start.strftime(fmt) }})</label></dd>
{% end %}
{% end %}
{% end %}
{% if ends %}
<dt>Ende</dt>
<dd><label><input type=radio name=end value="" checked=checked /> <i>Aus Übung behalten</i></label></dd>
{% for gpx_file in gpx_files %}
{% if gpx_file.end != exercise.end %}
<dd><label><input type=radio name=end value="{{ gpx_file.end.strftime("%Y-%m-%d %H:%M:%S") }}" /> Aus GPS-Trajektorie übernehmen ({{ gpx_file.end.strftime(fmt) }})</label></dd>
{% end %}
{% end %}
{% end %}
</dl>
<p class=buttonbox>
<input type=submit name=update value=Aktualisieren />
</p>
</fieldset>
</form>
{% end %}
{% end %}
<fieldset>
<legend>Übungsdaten</legend>
<dl>
<dt>Disziplin</dt>
<dd>{{ exercise.discipline }}</dd>
<dt>Benutzer</dt>
<dd>{% module user_link(username=exercise.username) %}</dd>
<dt>Anzahl</dt>
<dd>{{ exercise.count }}</dd>
<legend>{{ ("%d " % len(gpx_files)) if len(gpx_files) > 1 else "" }}GPS-Trajektorie{{ "" if len(gpx_files) == 1 else "n" }}</legend>
{% set hr = False %}
{% for gpx_file in gpx_files %}
{% if hr %}<hr />{% end %}{% set hr = True %}
<dl>
<dt>Beginn</dt>
<dd>{{ gpx_file.start.strftime(fmt) }}</dd>
{% set fmt = "%d.%m.%Y %H:%M:%S" %}
<dt>Beginn</dt>
<dd>{{ exercise.start.strftime(fmt) }}</dd>
<dt>Ende</dt>
<dd>{{ gpx_file.end.strftime(fmt) }}</dd>
<dt>Ende</dt>
<dd>{{ exercise.end.strftime(fmt) }}</dd>
<dt>Dauer</dt>
<dd>{{ (exercise.end - exercise.start) }} h</dd>
</dl>
</fieldset>
{% if gpx_files %}
<fieldset>
<legend>{{ ("%d " % len(gpx_files)) if len(gpx_files) > 1 else "" }}GPS-Trajektorie{{ "" if len(gpx_files) == 1 else "n" }}</legend>
{% set hr = False %}
{% for gpx_file in gpx_files %}
{% if hr %}<hr />{% end %}{% set hr = True %}
<dl>
<dt>Beginn</dt>
<dd>{{ gpx_file.start.strftime(fmt) }}</dd>
<dt>Dauer</dt>
<dd>{{ gpx_file.end - gpx_file.start }} h</dd>
<dt>Ende</dt>
<dd>{{ gpx_file.end.strftime(fmt) }}</dd>
<dt>Streckenpunkte</dt>
<dd>{{ sum([ track.get_points_no() for track in gpx_file.gpx.tracks ]) }}</dd>
<dt>Dauer</dt>
<dd>{{ gpx_file.end - gpx_file.start }} h</dd>
<dt>Strecke (2D)</dt>
<dd>{{ distance(gpx_file.gpx.length_2d()) }}</dd>
<dt>Streckenpunkte</dt>
<dd>{{ sum([ track.get_points_no() for track in gpx_file.gpx.tracks ]) }}</dd>
<dt>Strecke (3D)</dt>
<dd>{{ distance(gpx_file.gpx.length_3d()) }}</dd>
<dt>Strecke (2D)</dt>
<dd>{{ distance(gpx_file.gpx.length_2d()) }}</dd>
{% set uphill_downhill = gpx_file.gpx.get_uphill_downhill() %}
<dt>Höhengewinn</dt>
<dd>{{ distance(uphill_downhill.uphill) }}</dd>
<dt>Strecke (3D)</dt>
<dd>{{ distance(gpx_file.gpx.length_3d()) }}</dd>
<dt>Höhenverlust</dt>
<dd>{{ distance(uphill_downhill.downhill) }}</dd>
{% set uphill_downhill = gpx_file.gpx.get_uphill_downhill() %}
<dt>Höhengewinn</dt>
<dd>{{ distance(uphill_downhill.uphill) }}</dd>
{% set elevation_extremes = gpx_file.gpx.get_elevation_extremes() %}
<dt>Tiefster Punkt</dt>
<dd>{{ distance(elevation_extremes.minimum) }}</dd>
<dt>henverlust</dt>
<dd>{{ distance(uphill_downhill.downhill) }}</dd>
<dt>chster Punkt</dt>
<dd>{{ distance(elevation_extremes.maximum) }}</dd>
{% set elevation_extremes = gpx_file.gpx.get_elevation_extremes() %}
<dt>Tiefster Punkt</dt>
<dd>{{ distance(elevation_extremes.minimum) }}</dd>
{% set moving_data = gpx_file.gpx.get_moving_data() %}
<dt>Fahrtzeit</dt>
<dd>{{ datetime.timedelta(seconds=moving_data.moving_time) }} h</dd>
<dt>Höchster Punkt</dt>
<dd>{{ distance(elevation_extremes.maximum) }}</dd>
<dt>Haltezeit</dt>
<dd>{{ datetime.timedelta(seconds=moving_data.stopped_time) }} h</dd>
{% set moving_data = gpx_file.gpx.get_moving_data() %}
<dt>Fahrtzeit</dt>
<dd>{{ datetime.timedelta(seconds=moving_data.moving_time) }} h</dd>
<dt>Fahrtentfernung</dt>
<dd>{{ distance(moving_data.moving_distance) }}</dd>
<dt>Haltezeit</dt>
<dd>{{ datetime.timedelta(seconds=moving_data.stopped_time) }} h</dd>
<dt>Halteentfernung</dt>
<dd>{{ distance(moving_data.stopped_distance) }}</dd>
<dt>Fahrtentfernung</dt>
<dd>{{ distance(moving_data.moving_distance) }}</dd>
<dt><abbr title="Höchstgeschwindigkeit">Höchstgeschw.</abbr></dt>
<dd>{{ "%.2f" % (moving_data.max_speed * 60. ** 2 / 1000) }} km/h ({{ "%.2f" % moving_data.max_speed }} m/s)</dd>
</dl>
{% end %}
<noscript><p class=warning>Für die Kartenvisualisierung der GPS-Trajektorie
muss JavaScript aktiviert sein! Dazu bitte die Domain
<code>kraftwerk.lyse.isobeef.org</code> erlauben.</p></noscript>
<div style="width:100%;height:40em" id=map></div>
<script type=text/javascript>
{% set center = gpx_files[0].gpx.tracks[0].get_center() %}
init_map(GET.lon || {{ center.longitude }}, GET.lat || {{ center.latitude }}, GET.zoom || 14);
<dt>Halteentfernung</dt>
<dd>{{ distance(moving_data.stopped_distance) }}</dd>
<dt><abbr title="Höchstgeschwindigkeit">Höchstgeschw.</abbr></dt>
<dd>{{ "%.2f" % (moving_data.max_speed * 60. ** 2 / 1000) }} km/h ({{ "%.2f" % moving_data.max_speed }} m/s)</dd>
</dl>
{% for gpx_file in gpx_files %}
add_gpx_track("Route vom {{ gpx_file.start.strftime("%d.%m.%Y, %H:%M") }}<sup><u>h</u></sup>", "{{ gpx_url(gpx_file.filename) }}", "{{ colors.next() }}");
{% end %}
<noscript><p class=warning>Für die Kartenvisualisierung der GPS-Trajektorie
muss JavaScript aktiviert sein! Dazu bitte die Domain
<code>kraftwerk.lyse.isobeef.org</code> erlauben.</p></noscript>
<div style="width:100%;height:40em" id=map></div>
<script type=text/javascript>
{% set center = gpx_files[0].gpx.tracks[0].get_center() %}
init_map(GET.lon || {{ center.longitude }}, GET.lat || {{ center.latitude }}, GET.zoom || 14);
{% for gpx_file in gpx_files %}
add_gpx_track("Route vom {{ gpx_file.start.strftime("%d.%m.%Y, %H:%M") }}<sup><u>h</u></sup>", "{{ gpx_url(gpx_file.filename) }}", "{{ colors.next() }}");
{% end %}
{% set start = gpx_files[ 0].gpx.tracks[ 0].segments[ 0].points[ 0] %}
add_marker({{ start.longitude }}, {{ start.latitude }}, '{{ static_url("start.png") }}');
{% set end = gpx_files[-1].gpx.tracks[-1].segments[-1].points[-1] %}
add_marker({{ end.longitude }}, {{ end.latitude }}, '{{ static_url("end.png") }}');
</script>
</fieldset>
{% elif current_user.username == exercise.username %}
<p><a href="{{ reverse_url("AddGPXHandler", exercise.id) }}" title="Zu dieser Übung eine GPS-Trajektorie hinzufügen">GPX hinzufügen</a></p>
{% end %}
</form>
{% set start = gpx_files[ 0].gpx.tracks[ 0].segments[ 0].points[ 0] %}
add_marker({{ start.longitude }}, {{ start.latitude }}, '{{ static_url("start.png") }}');
{% set end = gpx_files[-1].gpx.tracks[-1].segments[-1].points[-1] %}
add_marker({{ end.longitude }}, {{ end.latitude }}, '{{ static_url("end.png") }}');
</script>
</fieldset>
{% elif current_user.username == exercise.username %}
<p><a href="{{ reverse_url("AddGPXHandler", exercise.id) }}" title="Zu dieser Übung eine GPS-Trajektorie hinzufügen">GPX hinzufügen</a></p>
{% end %}
</section>
{% end %}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment