Better handling of expiration of GCUM and accidents report types.
This commit is contained in:
parent
bc52d4f929
commit
9d6ed7e74c
@ -80,13 +80,6 @@ adapt its behavior:
|
||||
You can use the `wsgi.py` script at the root of the git repository to serve
|
||||
the server side part.
|
||||
|
||||
#### Useful scripts
|
||||
|
||||
The `scripts` folder contain some useful scripts:
|
||||
|
||||
* `purge_old_gcum_and_accidents.py` deletes `gcum` and `accident` type report
|
||||
older than one hour. You should set a crontask to call it regularly.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
import os
|
||||
import sys
|
||||
SCRIPT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.abspath(os.path.join(SCRIPT_DIRECTORY, '..')))
|
||||
|
||||
import arrow
|
||||
|
||||
from server.models import db, Report
|
||||
|
||||
if __name__ == "__main__":
|
||||
db.connect()
|
||||
one_hour_ago = arrow.utcnow().shift(hours=-1).datetime
|
||||
nb = Report.delete().where(
|
||||
((Report.type == 'accident') | (Report.type == 'gcum')) &
|
||||
(Report.datetime < one_hour_ago)
|
||||
).execute()
|
||||
print("%d accident/GCUM reports purged." % nb)
|
||||
if not db.is_closed():
|
||||
db.close()
|
@ -43,6 +43,7 @@ class Report(BaseModel):
|
||||
datetime = peewee.DateTimeField(
|
||||
default=lambda: arrow.utcnow().replace(microsecond=0).datetime
|
||||
)
|
||||
expiration_datetime = peewee.DateTimeField(null=True)
|
||||
is_open = peewee.BooleanField(default=True)
|
||||
upvotes = peewee.IntegerField(default=0)
|
||||
downvotes = peewee.IntegerField(default=0)
|
||||
|
@ -3,6 +3,7 @@
|
||||
"""
|
||||
Routes definitions
|
||||
"""
|
||||
import arrow
|
||||
import json
|
||||
|
||||
import bottle
|
||||
@ -11,14 +12,9 @@ from server.models import Report
|
||||
from server import jsonapi
|
||||
|
||||
|
||||
@bottle.route('/api/v1/reports', ["GET", "OPTIONS"])
|
||||
def get_reports():
|
||||
def get_reports(only_active=False):
|
||||
"""
|
||||
API v1 GET reports route.
|
||||
|
||||
Example::
|
||||
|
||||
GET /api/v1/reports
|
||||
Get reports for the reports getting routes.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -57,6 +53,11 @@ def get_reports():
|
||||
query = Report.select()
|
||||
if filters:
|
||||
query = query.where(*filters)
|
||||
if only_active:
|
||||
query = query.where(
|
||||
(Report.expiration_datetime == None) |
|
||||
(Report.expiration_datetime > arrow.utcnow().replace(microsecond=0).datetime)
|
||||
)
|
||||
query = query.order_by(*sorting)
|
||||
if page_number and page_size:
|
||||
query = query.paginate(page_number, page_size)
|
||||
@ -69,6 +70,69 @@ def get_reports():
|
||||
}
|
||||
|
||||
|
||||
@bottle.route('/api/v1/reports', ["GET", "OPTIONS"])
|
||||
def get_all_reports():
|
||||
"""
|
||||
API v1 GET reports route. Get all reports.
|
||||
|
||||
Example::
|
||||
|
||||
GET /api/v1/reports
|
||||
|
||||
.. note::
|
||||
|
||||
Filtering can be done through the ``filter`` GET param, according
|
||||
to JSON API spec (http://jsonapi.org/recommendations/#filtering).
|
||||
|
||||
.. note::
|
||||
|
||||
By default no pagination is done. Pagination can be forced using
|
||||
``page[size]`` to specify a number of items per page and
|
||||
``page[number]`` to specify which page to return. Pages are numbered
|
||||
starting from 0.
|
||||
|
||||
.. note::
|
||||
|
||||
Sorting can be handled through the ``sort`` GET param, according to
|
||||
JSON API spec (http://jsonapi.org/format/#fetching-sorting).
|
||||
|
||||
:return: The available reports objects in a JSON ``data`` dict.
|
||||
"""
|
||||
return get_reports(only_active=False)
|
||||
|
||||
|
||||
@bottle.route('/api/v1/reports/active', ["GET", "OPTIONS"])
|
||||
def get_active_reports():
|
||||
"""
|
||||
API v1 GET reports route. Only get active reports (those with
|
||||
``expiration_datetime`` in the future).
|
||||
|
||||
Example::
|
||||
|
||||
GET /api/v1/reports/active
|
||||
|
||||
.. note::
|
||||
|
||||
Filtering can be done through the ``filter`` GET param, according
|
||||
to JSON API spec (http://jsonapi.org/recommendations/#filtering).
|
||||
|
||||
.. note::
|
||||
|
||||
By default no pagination is done. Pagination can be forced using
|
||||
``page[size]`` to specify a number of items per page and
|
||||
``page[number]`` to specify which page to return. Pages are numbered
|
||||
starting from 0.
|
||||
|
||||
.. note::
|
||||
|
||||
Sorting can be handled through the ``sort`` GET param, according to
|
||||
JSON API spec (http://jsonapi.org/format/#fetching-sorting).
|
||||
|
||||
:return: The available reports objects in a JSON ``data`` dict.
|
||||
"""
|
||||
return get_reports(only_active=True)
|
||||
|
||||
|
||||
@bottle.route('/api/v1/reports', ["POST", "OPTIONS"])
|
||||
def post_report():
|
||||
"""
|
||||
@ -93,11 +157,17 @@ def post_report():
|
||||
return jsonapi.JsonApiError(400, "Invalid JSON payload: " + str(exc))
|
||||
|
||||
try:
|
||||
r = Report.create(
|
||||
r = Report(
|
||||
type=payload['type'],
|
||||
lat=payload['lat'],
|
||||
lng=payload['lng']
|
||||
)
|
||||
# Handle expiration
|
||||
if r.type in ['accident', 'gcum']:
|
||||
r.expiration_datetime = (
|
||||
arrow.utcnow().replace(microsecond=0).shift(hours=+1).datetime
|
||||
)
|
||||
r.save()
|
||||
except KeyError as exc:
|
||||
return jsonapi.JsonApiError(400, "Invalid report payload: " + str(exc))
|
||||
|
||||
|
@ -21,8 +21,8 @@ export function saveReport(type, lat, lng) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getReports() {
|
||||
return fetch(`${BASE_URL}api/v1/reports`)
|
||||
export function getActiveReports() {
|
||||
return fetch(`${BASE_URL}api/v1/reports/active`)
|
||||
.then(response => response.json())
|
||||
.then(response => response.data)
|
||||
.catch((exc) => {
|
||||
|
@ -34,9 +34,9 @@ export default {
|
||||
},
|
||||
reportLabels: {
|
||||
accident: 'Accident',
|
||||
accidentDescription: 'Any accident on the road',
|
||||
accidentDescription: 'Any accident on the road (active for one hour).',
|
||||
gcum: 'GCUM',
|
||||
gcumDescription: 'A car poorly parked on a bike lane. Such reports are automatically deleted after one hour, as they are by nature temporary.',
|
||||
gcumDescription: 'A car poorly parked on a bike lane. Such reports are automatically deleted after one hour, as they are by nature temporary (active for one hour).',
|
||||
interrupt: 'Interruption',
|
||||
interruptDescription: 'An interruption of the bike lane (works, unexpected end of the bike lane, etc.).',
|
||||
misc: 'Other',
|
||||
|
@ -34,9 +34,9 @@ export default {
|
||||
},
|
||||
reportLabels: {
|
||||
accident: 'Accident',
|
||||
accidentDescription: 'Un accident sur la route.',
|
||||
accidentDescription: 'Un accident sur la route (actif pour une heure).',
|
||||
gcum: 'GCUM',
|
||||
gcumDescription: "Une voiture (mal) garée sur la piste cyclable. Ces signalements sont automatiquement supprimés au bout d'une heure car ils sont par essence temporaires.",
|
||||
gcumDescription: "Une voiture (mal) garée sur la piste cyclable. Ces signalements sont automatiquement supprimés au bout d'une heure car ils sont par essence temporaires (actif pour une heure).",
|
||||
interrupt: 'Interruption',
|
||||
interruptDescription: "Une interruption d'itinéraire cyclable (travaux, arrêt inattendu d'une piste cyclable, etc)",
|
||||
misc: 'Autre',
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
|
||||
export function fetchReports({ commit }) {
|
||||
commit(IS_LOADING);
|
||||
return api.getReports()
|
||||
return api.getActiveReports()
|
||||
.then(reports => commit(STORE_REPORTS, { reports }))
|
||||
.finally(() => commit(IS_DONE_LOADING));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user