geo-activity-playground 0.38.2__py3-none-any.whl → 0.39.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geo_activity_playground/__main__.py +5 -47
- geo_activity_playground/alembic/README +1 -0
- geo_activity_playground/alembic/env.py +76 -0
- geo_activity_playground/alembic/script.py.mako +26 -0
- geo_activity_playground/alembic/versions/451e7836b53d_add_square_planner_bookmark.py +33 -0
- geo_activity_playground/alembic/versions/63d3b7f6f93c_initial_version.py +73 -0
- geo_activity_playground/alembic/versions/ab83b9d23127_add_upstream_id.py +28 -0
- geo_activity_playground/alembic/versions/b03491c593f6_add_crop_indices.py +30 -0
- geo_activity_playground/alembic/versions/e02e27876deb_add_square_planner_bookmark_name.py +28 -0
- geo_activity_playground/alembic/versions/script.py.mako +28 -0
- geo_activity_playground/core/activities.py +53 -136
- geo_activity_playground/core/config.py +3 -3
- geo_activity_playground/core/datamodel.py +257 -0
- geo_activity_playground/core/enrichment.py +90 -92
- geo_activity_playground/core/heart_rate.py +1 -2
- geo_activity_playground/core/parametric_plot.py +101 -0
- geo_activity_playground/core/paths.py +6 -7
- geo_activity_playground/core/raster_map.py +43 -4
- geo_activity_playground/core/similarity.py +1 -2
- geo_activity_playground/core/tasks.py +2 -2
- geo_activity_playground/core/test_meta_search.py +3 -3
- geo_activity_playground/core/test_summary_stats.py +1 -1
- geo_activity_playground/explorer/grid_file.py +2 -2
- geo_activity_playground/explorer/tile_visits.py +8 -10
- geo_activity_playground/heatmap_video.py +7 -8
- geo_activity_playground/importers/activity_parsers.py +2 -2
- geo_activity_playground/importers/directory.py +9 -10
- geo_activity_playground/importers/strava_api.py +9 -9
- geo_activity_playground/importers/strava_checkout.py +12 -13
- geo_activity_playground/importers/test_csv_parser.py +3 -3
- geo_activity_playground/importers/test_directory.py +1 -1
- geo_activity_playground/importers/test_strava_api.py +1 -1
- geo_activity_playground/webui/app.py +96 -86
- geo_activity_playground/webui/authenticator.py +1 -1
- geo_activity_playground/webui/{activity/controller.py → blueprints/activity_blueprint.py} +246 -108
- geo_activity_playground/webui/{auth_blueprint.py → blueprints/auth_blueprint.py} +1 -1
- geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +61 -0
- geo_activity_playground/webui/{calendar/controller.py → blueprints/calendar_blueprint.py} +19 -19
- geo_activity_playground/webui/{eddington_blueprint.py → blueprints/eddington_blueprint.py} +5 -5
- geo_activity_playground/webui/blueprints/entry_views.py +68 -0
- geo_activity_playground/webui/{equipment_blueprint.py → blueprints/equipment_blueprint.py} +37 -4
- geo_activity_playground/webui/{explorer/controller.py → blueprints/explorer_blueprint.py} +88 -54
- geo_activity_playground/webui/blueprints/heatmap_blueprint.py +233 -0
- geo_activity_playground/webui/blueprints/plot_builder_blueprint.py +43 -0
- geo_activity_playground/webui/{search_blueprint.py → blueprints/search_blueprint.py} +7 -11
- geo_activity_playground/webui/blueprints/settings_blueprint.py +446 -0
- geo_activity_playground/webui/{square_planner_blueprint.py → blueprints/square_planner_blueprint.py} +31 -6
- geo_activity_playground/webui/{summary_blueprint.py → blueprints/summary_blueprint.py} +11 -23
- geo_activity_playground/webui/blueprints/tile_blueprint.py +27 -0
- geo_activity_playground/webui/{upload_blueprint.py → blueprints/upload_blueprint.py} +13 -18
- geo_activity_playground/webui/flasher.py +26 -0
- geo_activity_playground/webui/plot_util.py +1 -1
- geo_activity_playground/webui/search_util.py +4 -6
- geo_activity_playground/webui/static/images/layers-2x.png +0 -0
- geo_activity_playground/webui/static/images/layers.png +0 -0
- geo_activity_playground/webui/static/images/marker-icon-2x.png +0 -0
- geo_activity_playground/webui/static/images/marker-icon.png +0 -0
- geo_activity_playground/webui/static/images/marker-shadow.png +0 -0
- geo_activity_playground/webui/templates/activity/day.html.j2 +81 -0
- geo_activity_playground/webui/templates/activity/edit.html.j2 +38 -0
- geo_activity_playground/webui/{activity/templates → templates}/activity/name.html.j2 +29 -27
- geo_activity_playground/webui/{activity/templates → templates}/activity/show.html.j2 +57 -33
- geo_activity_playground/webui/templates/activity/trim.html.j2 +68 -0
- geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +26 -0
- geo_activity_playground/webui/templates/calendar/index.html.j2 +48 -0
- geo_activity_playground/webui/templates/calendar/month.html.j2 +57 -0
- geo_activity_playground/webui/templates/equipment/index.html.j2 +7 -0
- geo_activity_playground/webui/templates/home.html.j2 +6 -6
- geo_activity_playground/webui/templates/page.html.j2 +2 -1
- geo_activity_playground/webui/templates/plot_builder/index.html.j2 +44 -0
- geo_activity_playground/webui/{settings/templates → templates}/settings/index.html.j2 +9 -20
- geo_activity_playground/webui/templates/settings/manage-equipments.html.j2 +49 -0
- geo_activity_playground/webui/templates/settings/manage-kinds.html.j2 +48 -0
- geo_activity_playground/webui/{settings/templates → templates}/settings/privacy-zones.html.j2 +2 -0
- geo_activity_playground/webui/{settings/templates → templates}/settings/strava.html.j2 +2 -0
- geo_activity_playground/webui/templates/square_planner/index.html.j2 +63 -13
- {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/METADATA +5 -1
- geo_activity_playground-0.39.1.dist-info/RECORD +136 -0
- geo_activity_playground/__init__.py +0 -0
- geo_activity_playground/core/__init__.py +0 -0
- geo_activity_playground/explorer/__init__.py +0 -0
- geo_activity_playground/importers/__init__.py +0 -0
- geo_activity_playground/webui/__init__.py +0 -0
- geo_activity_playground/webui/activity/__init__.py +0 -0
- geo_activity_playground/webui/activity/blueprint.py +0 -109
- geo_activity_playground/webui/activity/templates/activity/day.html.j2 +0 -80
- geo_activity_playground/webui/activity/templates/activity/edit.html.j2 +0 -42
- geo_activity_playground/webui/calendar/__init__.py +0 -0
- geo_activity_playground/webui/calendar/blueprint.py +0 -23
- geo_activity_playground/webui/calendar/templates/calendar/index.html.j2 +0 -46
- geo_activity_playground/webui/calendar/templates/calendar/month.html.j2 +0 -55
- geo_activity_playground/webui/entry_controller.py +0 -63
- geo_activity_playground/webui/explorer/__init__.py +0 -0
- geo_activity_playground/webui/explorer/blueprint.py +0 -62
- geo_activity_playground/webui/heatmap/__init__.py +0 -0
- geo_activity_playground/webui/heatmap/blueprint.py +0 -51
- geo_activity_playground/webui/heatmap/heatmap_controller.py +0 -216
- geo_activity_playground/webui/settings/blueprint.py +0 -262
- geo_activity_playground/webui/settings/controller.py +0 -272
- geo_activity_playground/webui/settings/templates/settings/equipment-offsets.html.j2 +0 -44
- geo_activity_playground/webui/settings/templates/settings/kind-renames.html.j2 +0 -25
- geo_activity_playground/webui/settings/templates/settings/kinds-without-achievements.html.j2 +0 -30
- geo_activity_playground/webui/tile_blueprint.py +0 -42
- geo_activity_playground-0.38.2.dist-info/RECORD +0 -129
- /geo_activity_playground/webui/{activity/templates → templates}/activity/lines.html.j2 +0 -0
- /geo_activity_playground/webui/{explorer/templates → templates}/explorer/index.html.j2 +0 -0
- /geo_activity_playground/webui/{heatmap/templates → templates}/heatmap/index.html.j2 +0 -0
- /geo_activity_playground/webui/{settings/templates → templates}/settings/admin-password.html.j2 +0 -0
- /geo_activity_playground/webui/{settings/templates → templates}/settings/color-schemes.html.j2 +0 -0
- /geo_activity_playground/webui/{settings/templates → templates}/settings/heart-rate.html.j2 +0 -0
- /geo_activity_playground/webui/{settings/templates → templates}/settings/metadata-extraction.html.j2 +0 -0
- /geo_activity_playground/webui/{settings/templates → templates}/settings/segmentation.html.j2 +0 -0
- /geo_activity_playground/webui/{settings/templates → templates}/settings/sharepic.html.j2 +0 -0
- {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/LICENSE +0 -0
- {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/WHEEL +0 -0
- {geo_activity_playground-0.38.2.dist-info → geo_activity_playground-0.39.1.dist-info}/entry_points.txt +0 -0
@@ -1,109 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
import urllib.parse
|
3
|
-
|
4
|
-
from flask import Blueprint
|
5
|
-
from flask import redirect
|
6
|
-
from flask import render_template
|
7
|
-
from flask import request
|
8
|
-
from flask import Response
|
9
|
-
from flask import url_for
|
10
|
-
|
11
|
-
from geo_activity_playground.core.activities import ActivityRepository
|
12
|
-
from geo_activity_playground.core.paths import activity_meta_override_dir
|
13
|
-
from geo_activity_playground.webui.activity.controller import ActivityController
|
14
|
-
from geo_activity_playground.webui.authenticator import Authenticator
|
15
|
-
from geo_activity_playground.webui.authenticator import needs_authentication
|
16
|
-
|
17
|
-
|
18
|
-
def make_activity_blueprint(
|
19
|
-
activity_controller: ActivityController,
|
20
|
-
repository: ActivityRepository,
|
21
|
-
authenticator: Authenticator,
|
22
|
-
) -> Blueprint:
|
23
|
-
blueprint = Blueprint("activity", __name__, template_folder="templates")
|
24
|
-
|
25
|
-
@blueprint.route("/all")
|
26
|
-
def all():
|
27
|
-
return render_template(
|
28
|
-
"activity/lines.html.j2", **activity_controller.render_all()
|
29
|
-
)
|
30
|
-
|
31
|
-
@blueprint.route("/<id>")
|
32
|
-
def show(id: str):
|
33
|
-
return render_template(
|
34
|
-
"activity/show.html.j2", **activity_controller.render_activity(int(id))
|
35
|
-
)
|
36
|
-
|
37
|
-
@blueprint.route("/<id>/sharepic.png")
|
38
|
-
def sharepic(id: str):
|
39
|
-
return Response(
|
40
|
-
activity_controller.render_sharepic(int(id)),
|
41
|
-
mimetype="image/png",
|
42
|
-
)
|
43
|
-
|
44
|
-
@blueprint.route("/day/<year>/<month>/<day>")
|
45
|
-
def day(year: str, month: str, day: str):
|
46
|
-
return render_template(
|
47
|
-
"activity/day.html.j2",
|
48
|
-
**activity_controller.render_day(int(year), int(month), int(day)),
|
49
|
-
)
|
50
|
-
|
51
|
-
@blueprint.route("/day-sharepic/<year>/<month>/<day>/sharepic.png")
|
52
|
-
def day_sharepic(year: str, month: str, day: str):
|
53
|
-
return Response(
|
54
|
-
activity_controller.render_day_sharepic(int(year), int(month), int(day)),
|
55
|
-
mimetype="image/png",
|
56
|
-
)
|
57
|
-
|
58
|
-
@blueprint.route("/name/<name>")
|
59
|
-
def name(name: str):
|
60
|
-
return render_template(
|
61
|
-
"activity/name.html.j2",
|
62
|
-
**activity_controller.render_name(urllib.parse.unquote(name)),
|
63
|
-
)
|
64
|
-
|
65
|
-
@blueprint.route("/edit/<id>", methods=["GET", "POST"])
|
66
|
-
@needs_authentication(authenticator)
|
67
|
-
def edit(id: str):
|
68
|
-
activity_id = int(id)
|
69
|
-
activity = repository.get_activity_by_id(activity_id)
|
70
|
-
override_file = activity_meta_override_dir() / f"{activity_id}.json"
|
71
|
-
if override_file.exists():
|
72
|
-
with open(override_file) as f:
|
73
|
-
override = json.load(f)
|
74
|
-
else:
|
75
|
-
override = {}
|
76
|
-
|
77
|
-
if request.method == "POST":
|
78
|
-
override = {}
|
79
|
-
if value := request.form.get("name"):
|
80
|
-
override["name"] = value
|
81
|
-
repository.meta.loc[activity_id, "name"] = value
|
82
|
-
if value := request.form.get("kind"):
|
83
|
-
override["kind"] = value
|
84
|
-
repository.meta.loc[activity_id, "kind"] = value
|
85
|
-
if value := request.form.get("equipment"):
|
86
|
-
override["equipment"] = value
|
87
|
-
repository.meta.loc[activity_id, "equipment"] = value
|
88
|
-
if value := request.form.get("commute"):
|
89
|
-
override["commute"] = True
|
90
|
-
repository.meta.loc[activity_id, "commute"] = True
|
91
|
-
if value := request.form.get("consider_for_achievements"):
|
92
|
-
override["consider_for_achievements"] = True
|
93
|
-
repository.meta.loc[activity_id, "consider_for_achievements"] = True
|
94
|
-
|
95
|
-
with open(override_file, "w") as f:
|
96
|
-
json.dump(override, f, ensure_ascii=False, indent=4, sort_keys=True)
|
97
|
-
|
98
|
-
repository.save()
|
99
|
-
|
100
|
-
return redirect(url_for(".show", id=activity_id))
|
101
|
-
|
102
|
-
return render_template(
|
103
|
-
"activity/edit.html.j2",
|
104
|
-
activity_id=activity_id,
|
105
|
-
activity=activity,
|
106
|
-
override=override,
|
107
|
-
)
|
108
|
-
|
109
|
-
return blueprint
|
@@ -1,80 +0,0 @@
|
|
1
|
-
{% extends "page.html.j2" %}
|
2
|
-
|
3
|
-
{% block container %}
|
4
|
-
<div class="row mb-3">
|
5
|
-
<div class="col">
|
6
|
-
<h1>{{ date }}</h1>
|
7
|
-
</div>
|
8
|
-
</div>
|
9
|
-
|
10
|
-
|
11
|
-
<div class="row mb-3">
|
12
|
-
<div class="col-12">
|
13
|
-
<div id="activity-map" style="height: 500px;"></div>
|
14
|
-
<script>
|
15
|
-
var map = L.map('activity-map', {
|
16
|
-
fullscreenControl: true
|
17
|
-
});
|
18
|
-
L.tileLayer('/tile/grayscale/{z}/{x}/{y}.png', {
|
19
|
-
maxZoom: 19,
|
20
|
-
attribution: '{{ map_tile_attribution|safe }}'
|
21
|
-
}).addTo(map);
|
22
|
-
|
23
|
-
let geojson = L.geoJSON({{ geojson| safe }}, {
|
24
|
-
style: function (feature) { return { color: feature.properties.color } }
|
25
|
-
}).addTo(map)
|
26
|
-
map.fitBounds(geojson.getBounds());
|
27
|
-
</script>
|
28
|
-
</div>
|
29
|
-
</div>
|
30
|
-
|
31
|
-
<div class="row mb-3">
|
32
|
-
<div class="col">
|
33
|
-
<h2>Activities</h2>
|
34
|
-
|
35
|
-
<table class="table table-sort table-arrows">
|
36
|
-
<thead>
|
37
|
-
<tr>
|
38
|
-
<th>Name</th>
|
39
|
-
<th>Date</th>
|
40
|
-
<th>Distance / km</th>
|
41
|
-
<th>Elapsed time</th>
|
42
|
-
<th>Speed / km/h</th>
|
43
|
-
<th>Equipment</th>
|
44
|
-
<th>Kind</th>
|
45
|
-
</tr>
|
46
|
-
</thead>
|
47
|
-
<tbody>
|
48
|
-
{% for activity in activities %}
|
49
|
-
<tr>
|
50
|
-
<td><span style="color: {{ activity['color'] }};">█</span> <a
|
51
|
-
href="{{ url_for('activity.show', id=activity.id) }}">{{
|
52
|
-
activity.name }}</a></td>
|
53
|
-
<td>{{ activity.start|dt }}</td>
|
54
|
-
<td>{{ activity.distance_km | round(1) }}</td>
|
55
|
-
<td>{{ activity.elapsed_time|td }}</td>
|
56
|
-
<td>{{ activity.average_speed_moving_kmh|round(1) }}</td>
|
57
|
-
<td>{{ activity["equipment"] }}</td>
|
58
|
-
<td>{{ activity["kind"] }}</td>
|
59
|
-
</tr>
|
60
|
-
{% endfor %}
|
61
|
-
{% if activities|length > 1 %}
|
62
|
-
<tr>
|
63
|
-
<td><b>Total</b></td>
|
64
|
-
<td></td>
|
65
|
-
<td><b>{{ total_distance | round(1) }}</b></td>
|
66
|
-
<td><b>{{ total_elapsed_time|td }}</b></td>
|
67
|
-
<td></td>
|
68
|
-
<td></td>
|
69
|
-
</tr>
|
70
|
-
{% endif %}
|
71
|
-
</tbody>
|
72
|
-
</table>
|
73
|
-
</div>
|
74
|
-
</div>
|
75
|
-
|
76
|
-
<h2>Share picture</h2>
|
77
|
-
|
78
|
-
<p><img class="img-fluid" src="{{ url_for('.day_sharepic', year=year, month=month, day=day) }}" /></p>
|
79
|
-
|
80
|
-
{% endblock %}
|
@@ -1,42 +0,0 @@
|
|
1
|
-
{% extends "page.html.j2" %}
|
2
|
-
|
3
|
-
{% block container %}
|
4
|
-
|
5
|
-
<h1 class="mb-3">Edit Activity</h1>
|
6
|
-
|
7
|
-
<form method="POST">
|
8
|
-
<div class="mb-3">
|
9
|
-
<label for="name" class="form-label">Name</label>
|
10
|
-
<input type="text" class="form-control" id="name" name="name" value="{{ override['name'] }}" />
|
11
|
-
</div>
|
12
|
-
|
13
|
-
<div class="mb-3">
|
14
|
-
<label for="kind" class="form-label">Kind</label>
|
15
|
-
<input type="text" class="form-control" id="kind" name="kind" value="{{ override['kind'] }}" />
|
16
|
-
</div>
|
17
|
-
|
18
|
-
<div class="mb-3">
|
19
|
-
<label for="equipment" class="form-label">Equipment</label>
|
20
|
-
<input type="text" class="form-control" id="equipment" name="equipment" value="{{ override['equipment'] }}" />
|
21
|
-
</div>
|
22
|
-
|
23
|
-
<div class="mb-3">
|
24
|
-
<div class="form-check">
|
25
|
-
<input type="checkbox" class="form-check-input" id="commute" name="commute" {% if override['commute'] %}
|
26
|
-
checked {% endif %} />
|
27
|
-
<label for="commute" class="form-check-label">Commute</label>
|
28
|
-
</div>
|
29
|
-
</div>
|
30
|
-
|
31
|
-
<div class="mb-3">
|
32
|
-
<div class="form-check">
|
33
|
-
<input type="checkbox" class="form-check-input" id="consider_for_achievements"
|
34
|
-
name="consider_for_achievements" {% if override['consider_for_achievements'] %} checked {% endif %} />
|
35
|
-
<label for="consider_for_achievements" class="form-check-label">Consider for achievements</label>
|
36
|
-
</div>
|
37
|
-
</div>
|
38
|
-
|
39
|
-
<button type="submit" class="btn btn-primary">Save</button>
|
40
|
-
</form>
|
41
|
-
|
42
|
-
{% endblock %}
|
File without changes
|
@@ -1,23 +0,0 @@
|
|
1
|
-
from flask import Blueprint
|
2
|
-
from flask import render_template
|
3
|
-
|
4
|
-
from geo_activity_playground.webui.calendar.controller import CalendarController
|
5
|
-
|
6
|
-
|
7
|
-
def make_calendar_blueprint(calendar_controller: CalendarController) -> Blueprint:
|
8
|
-
blueprint = Blueprint("calendar", __name__, template_folder="templates")
|
9
|
-
|
10
|
-
@blueprint.route("/")
|
11
|
-
def index():
|
12
|
-
return render_template(
|
13
|
-
"calendar/index.html.j2", **calendar_controller.render_overview()
|
14
|
-
)
|
15
|
-
|
16
|
-
@blueprint.route("/<year>/<month>")
|
17
|
-
def month(year: str, month: str):
|
18
|
-
return render_template(
|
19
|
-
"calendar/month.html.j2",
|
20
|
-
**calendar_controller.render_month(int(year), int(month))
|
21
|
-
)
|
22
|
-
|
23
|
-
return blueprint
|
@@ -1,46 +0,0 @@
|
|
1
|
-
{% extends "page.html.j2" %}
|
2
|
-
|
3
|
-
{% block container %}
|
4
|
-
<div class="row mb-1">
|
5
|
-
<div class="col">
|
6
|
-
<h1>Calendar</h1>
|
7
|
-
</div>
|
8
|
-
</div>
|
9
|
-
|
10
|
-
<div class="row mb-1">
|
11
|
-
<div class="col">
|
12
|
-
<table class="table">
|
13
|
-
<thead>
|
14
|
-
<tr>
|
15
|
-
<th>Year</th>
|
16
|
-
{% for i in range(1, 13) %}
|
17
|
-
<th style="text-align: right;">{{ i }}</th>
|
18
|
-
{% endfor %}
|
19
|
-
<th style="text-align: right;">Total</th>
|
20
|
-
</tr>
|
21
|
-
</thead>
|
22
|
-
<tbody>
|
23
|
-
{% for year, month_data in monthly_distances.items() %}
|
24
|
-
{% set year_int = year|round(0)|int %}
|
25
|
-
<tr>
|
26
|
-
<td>{{ year_int }}</td>
|
27
|
-
{% for month in range(1, 13) %}
|
28
|
-
<td align="right">
|
29
|
-
{% set distance = month_data[month] %}
|
30
|
-
{% if distance %}
|
31
|
-
<a href="{{ url_for(".month", year=year_int, month=month) }}">{{ distance|int() }} km</a>
|
32
|
-
{% else %}
|
33
|
-
0 km
|
34
|
-
{% endif %}
|
35
|
-
</td>
|
36
|
-
{% endfor %}
|
37
|
-
<td align="right">{{ yearly_distances[year]|int() }} km</td>
|
38
|
-
</tr>
|
39
|
-
{% endfor %}
|
40
|
-
</tbody>
|
41
|
-
</table>
|
42
|
-
</div>
|
43
|
-
</div>
|
44
|
-
|
45
|
-
|
46
|
-
{% endblock %}
|
@@ -1,55 +0,0 @@
|
|
1
|
-
{% extends "page.html.j2" %}
|
2
|
-
|
3
|
-
{% block container %}
|
4
|
-
<div class="row mb-1">
|
5
|
-
<div class="col">
|
6
|
-
<h1>Calendar {{ year }}-{{ "{0:02d}".format(month) }}</h1>
|
7
|
-
</div>
|
8
|
-
</div>
|
9
|
-
|
10
|
-
<div class="row mb-1">
|
11
|
-
<div class="col">
|
12
|
-
<table class="table">
|
13
|
-
<thead>
|
14
|
-
<tr>
|
15
|
-
<th>Week</th>
|
16
|
-
<th>Monday</th>
|
17
|
-
<th>Tuesday</th>
|
18
|
-
<th>Wednesday</th>
|
19
|
-
<th>Thursday</th>
|
20
|
-
<th>Friday</th>
|
21
|
-
<th>Saturday</th>
|
22
|
-
<th>Sunday</th>
|
23
|
-
</tr>
|
24
|
-
</thead>
|
25
|
-
<tbody>
|
26
|
-
{% for week, week_data in weeks.items() %}
|
27
|
-
<tr>
|
28
|
-
<td>{{ week }}</td>
|
29
|
-
{% for day in range(1, 8) %}
|
30
|
-
<td>
|
31
|
-
{% if weeks[week][day] %}
|
32
|
-
<a href="{{ url_for('activity.day', year=year, month=month, day=day_of_month[week][day]) }}"><b>{{
|
33
|
-
day_of_month[week][day] }}.</b></a>
|
34
|
-
{% elif day_of_month[week][day] %}
|
35
|
-
<b>{{ day_of_month[week][day] }}.</b>
|
36
|
-
{% endif %}
|
37
|
-
|
38
|
-
{% if weeks[week][day] %}
|
39
|
-
<ul>
|
40
|
-
{% for activity in weeks[week][day] %}
|
41
|
-
<li><a href="{{ url_for('activity.show', id=activity.id) }}">{{ activity.name }}</a></li>
|
42
|
-
{% endfor %}
|
43
|
-
</ul>
|
44
|
-
{% endif %}
|
45
|
-
</td>
|
46
|
-
{% endfor %}
|
47
|
-
</tr>
|
48
|
-
{% endfor %}
|
49
|
-
</tbody>
|
50
|
-
</table>
|
51
|
-
</div>
|
52
|
-
</div>
|
53
|
-
|
54
|
-
|
55
|
-
{% endblock %}
|
@@ -1,63 +0,0 @@
|
|
1
|
-
import datetime
|
2
|
-
import itertools
|
3
|
-
|
4
|
-
import altair as alt
|
5
|
-
import pandas as pd
|
6
|
-
|
7
|
-
from geo_activity_playground.core.activities import ActivityRepository
|
8
|
-
from geo_activity_playground.core.activities import make_geojson_from_time_series
|
9
|
-
from geo_activity_playground.core.config import Config
|
10
|
-
from geo_activity_playground.webui.plot_util import make_kind_scale
|
11
|
-
|
12
|
-
|
13
|
-
class EntryController:
|
14
|
-
def __init__(self, repository: ActivityRepository, config: Config) -> None:
|
15
|
-
self._repository = repository
|
16
|
-
self._config = config
|
17
|
-
|
18
|
-
def render(self) -> dict:
|
19
|
-
result = {"latest_activities": []}
|
20
|
-
|
21
|
-
if len(self._repository):
|
22
|
-
kind_scale = make_kind_scale(self._repository.meta, self._config)
|
23
|
-
result["distance_last_30_days_plot"] = distance_last_30_days_meta_plot(
|
24
|
-
self._repository.meta, kind_scale
|
25
|
-
)
|
26
|
-
|
27
|
-
for activity in itertools.islice(
|
28
|
-
self._repository.iter_activities(dropna=True), 15
|
29
|
-
):
|
30
|
-
time_series = self._repository.get_time_series(activity["id"])
|
31
|
-
result["latest_activities"].append(
|
32
|
-
{
|
33
|
-
"line_geojson": make_geojson_from_time_series(time_series),
|
34
|
-
"activity": activity,
|
35
|
-
}
|
36
|
-
)
|
37
|
-
return result
|
38
|
-
|
39
|
-
|
40
|
-
def distance_last_30_days_meta_plot(meta: pd.DataFrame, kind_scale: alt.Scale) -> str:
|
41
|
-
before_30_days = pd.to_datetime(
|
42
|
-
datetime.datetime.now() - datetime.timedelta(days=31)
|
43
|
-
)
|
44
|
-
return (
|
45
|
-
alt.Chart(
|
46
|
-
meta.loc[meta["start"] > before_30_days],
|
47
|
-
width=700,
|
48
|
-
height=200,
|
49
|
-
title="Distance per day",
|
50
|
-
)
|
51
|
-
.mark_bar()
|
52
|
-
.encode(
|
53
|
-
alt.X("yearmonthdate(start)", title="Date"),
|
54
|
-
alt.Y("sum(distance_km)", title="Distance / km"),
|
55
|
-
alt.Color("kind", scale=kind_scale, title="Kind"),
|
56
|
-
[
|
57
|
-
alt.Tooltip("yearmonthdate(start)", title="Date"),
|
58
|
-
alt.Tooltip("kind", title="Kind"),
|
59
|
-
alt.Tooltip("sum(distance_km)", format=".1f", title="Distance / km"),
|
60
|
-
],
|
61
|
-
)
|
62
|
-
.to_json(format="vega")
|
63
|
-
)
|
File without changes
|
@@ -1,62 +0,0 @@
|
|
1
|
-
from flask import Blueprint
|
2
|
-
from flask import redirect
|
3
|
-
from flask import render_template
|
4
|
-
from flask import Response
|
5
|
-
from flask import url_for
|
6
|
-
|
7
|
-
from geo_activity_playground.webui.authenticator import Authenticator
|
8
|
-
from geo_activity_playground.webui.authenticator import needs_authentication
|
9
|
-
from geo_activity_playground.webui.explorer.controller import ExplorerController
|
10
|
-
|
11
|
-
|
12
|
-
def make_explorer_blueprint(
|
13
|
-
explorer_controller: ExplorerController,
|
14
|
-
authenticator: Authenticator,
|
15
|
-
) -> Blueprint:
|
16
|
-
blueprint = Blueprint("explorer", __name__, template_folder="templates")
|
17
|
-
|
18
|
-
@blueprint.route("/<zoom>")
|
19
|
-
def map(zoom: str):
|
20
|
-
return render_template(
|
21
|
-
"explorer/index.html.j2", **explorer_controller.render(int(zoom))
|
22
|
-
)
|
23
|
-
|
24
|
-
@blueprint.route("/enable-zoom-level/<zoom>")
|
25
|
-
@needs_authentication(authenticator)
|
26
|
-
def enable_zoom_level(zoom: str):
|
27
|
-
explorer_controller.enable_zoom_level(int(zoom))
|
28
|
-
return redirect(url_for(".map", zoom=zoom))
|
29
|
-
|
30
|
-
@blueprint.route("/<zoom>/<north>/<east>/<south>/<west>/explored.<suffix>")
|
31
|
-
def download(zoom: str, north: str, east: str, south: str, west: str, suffix: str):
|
32
|
-
mimetypes = {"geojson": "application/json", "gpx": "application/xml"}
|
33
|
-
return Response(
|
34
|
-
explorer_controller.export_explored_tiles(
|
35
|
-
int(zoom),
|
36
|
-
float(north),
|
37
|
-
float(east),
|
38
|
-
float(south),
|
39
|
-
float(west),
|
40
|
-
suffix,
|
41
|
-
),
|
42
|
-
mimetype=mimetypes[suffix],
|
43
|
-
headers={"Content-disposition": "attachment"},
|
44
|
-
)
|
45
|
-
|
46
|
-
@blueprint.route("/<zoom>/<north>/<east>/<south>/<west>/missing.<suffix>")
|
47
|
-
def missing(zoom: str, north: str, east: str, south: str, west: str, suffix: str):
|
48
|
-
mimetypes = {"geojson": "application/json", "gpx": "application/xml"}
|
49
|
-
return Response(
|
50
|
-
explorer_controller.export_missing_tiles(
|
51
|
-
int(zoom),
|
52
|
-
float(north),
|
53
|
-
float(east),
|
54
|
-
float(south),
|
55
|
-
float(west),
|
56
|
-
suffix,
|
57
|
-
),
|
58
|
-
mimetype=mimetypes[suffix],
|
59
|
-
headers={"Content-disposition": "attachment"},
|
60
|
-
)
|
61
|
-
|
62
|
-
return blueprint
|
File without changes
|
@@ -1,51 +0,0 @@
|
|
1
|
-
import dateutil.parser
|
2
|
-
from flask import Blueprint
|
3
|
-
from flask import render_template
|
4
|
-
from flask import request
|
5
|
-
from flask import Response
|
6
|
-
|
7
|
-
from geo_activity_playground.core.activities import ActivityRepository
|
8
|
-
from geo_activity_playground.core.config import Config
|
9
|
-
from geo_activity_playground.explorer.tile_visits import TileVisitAccessor
|
10
|
-
from geo_activity_playground.webui.heatmap.heatmap_controller import HeatmapController
|
11
|
-
from geo_activity_playground.webui.search_util import search_query_from_form
|
12
|
-
from geo_activity_playground.webui.search_util import SearchQueryHistory
|
13
|
-
|
14
|
-
|
15
|
-
def make_heatmap_blueprint(
|
16
|
-
repository: ActivityRepository,
|
17
|
-
tile_visit_accessor: TileVisitAccessor,
|
18
|
-
config: Config,
|
19
|
-
search_query_history: SearchQueryHistory,
|
20
|
-
) -> Blueprint:
|
21
|
-
heatmap_controller = HeatmapController(repository, tile_visit_accessor, config)
|
22
|
-
blueprint = Blueprint("heatmap", __name__, template_folder="templates")
|
23
|
-
|
24
|
-
@blueprint.route("/")
|
25
|
-
def index():
|
26
|
-
query = search_query_from_form(request.args)
|
27
|
-
search_query_history.register_query(query)
|
28
|
-
return render_template(
|
29
|
-
"heatmap/index.html.j2", **heatmap_controller.render(query)
|
30
|
-
)
|
31
|
-
|
32
|
-
@blueprint.route("/tile/<int:z>/<int:x>/<int:y>.png")
|
33
|
-
def tile(x: int, y: int, z: int):
|
34
|
-
query = search_query_from_form(request.args)
|
35
|
-
return Response(
|
36
|
-
heatmap_controller.render_tile(x, y, z, query),
|
37
|
-
mimetype="image/png",
|
38
|
-
)
|
39
|
-
|
40
|
-
@blueprint.route(
|
41
|
-
"/download/<float:north>/<float:east>/<float:south>/<float:west>/heatmap.png"
|
42
|
-
)
|
43
|
-
def download(north: float, east: float, south: float, west: float):
|
44
|
-
query = search_query_from_form(request.args)
|
45
|
-
return Response(
|
46
|
-
heatmap_controller.download_heatmap(north, east, south, west, query),
|
47
|
-
mimetype="image/png",
|
48
|
-
headers={"Content-disposition": 'attachment; filename="heatmap.png"'},
|
49
|
-
)
|
50
|
-
|
51
|
-
return blueprint
|