Show the reports as soon as they are added in the db

This commit is contained in:
Lucas Verney 2018-06-26 11:39:43 +02:00
parent e961a8dbb1
commit f30d000f92
14 changed files with 109 additions and 832 deletions

View File

@ -23,7 +23,8 @@
"vue-router": "^3.0.1",
"vue2-leaflet": "^1.0.2",
"vue2-leaflet-tracksymbol": "^1.0.10",
"vuetify": "^1.0.0"
"vuetify": "^1.0.0",
"vuex": "^3.0.1"
},
"devDependencies": {
"autoprefixer": "^7.1.2",

View File

@ -1,12 +1,24 @@
#!/usr/bin/env python
# coding: utf-8
import functools
import json
import bottle
from server import routes
from server.jsonapi import DateAwareJSONEncoder
from server.models import db, Report
if __name__ == "__main__":
db.connect()
db.create_tables([Report])
# Use DateAwareJSONEncoder to dump JSON strings
# From http://stackoverflow.com/questions/21282040/bottle-framework-how-to-return-datetime-in-json-response#comment55718456_21282666. pylint: disable=locally-disabled,line-too-long
bottle.install(
bottle.JSONPlugin(
json_dumps=functools.partial(json.dumps, cls=DateAwareJSONEncoder)
)
)
bottle.run(host='0.0.0.0', port='8081')

View File

@ -3,6 +3,7 @@
"""
Helpers to implement a JSON API with Bottle.
"""
import datetime
import json
import re
@ -11,6 +12,16 @@ import bottle
FILTER_RE = re.compile(r"filter\[([A-z0-9_]+)\]")
class DateAwareJSONEncoder(json.JSONEncoder):
"""
Extend the default JSON encoder to serialize datetimes to iso strings.
"""
def default(self, o): # pylint: disable=locally-disabled,E0202
if isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat()
return json.JSONEncoder.default(self, o)
@bottle.hook('after_request')
def enable_cors():
"""

View File

@ -38,4 +38,4 @@ class Report(BaseModel):
k: v for k, v in model_to_dict(self).items()
if k != "id"
}
}
}

View File

@ -93,7 +93,7 @@ def post_report():
return jsonapi.JsonApiError(400, "Invalid JSON payload: " + str(exc))
try:
Report.create(
r = Report.create(
type=payload['type'],
lat=payload['lat'],
lng=payload['lng']
@ -102,5 +102,5 @@ def post_report():
return jsonapi.JsonApiError(400, "Invalid report payload: " + str(exc))
return {
"status": "ok"
"data": r.to_json()
}

View File

@ -13,6 +13,8 @@ export function saveReport(type, lat, lng) {
lng,
}),
})
.then(response => response.json())
.then(response => response.data)
.catch(exc => console.error(`Unable to post report: ${exc}.`));
}

View File

@ -11,8 +11,6 @@
</template>
<script>
import * as api from '@/api';
import GCUMIcon from '@/assets/gcum.svg';
import ObstacleIcon from '@/assets/obstacle.svg';
import PotHoleIcon from '@/assets/pothole.svg';
@ -60,7 +58,11 @@ export default {
},
methods: {
saveReport(type) {
return api.saveReport(type, this.lat, this.lng)
return this.$store.dispatch('saveReport', {
type,
lat: this.lat,
lng: this.lng,
})
.then(() => {
this.isActive = !this.isActive;
});

View File

@ -10,8 +10,9 @@ import 'leaflet/dist/leaflet.css';
import 'vuetify/dist/vuetify.min.css';
import App from './App.vue';
import router from './router';
import i18n from './i18n';
import router from './router';
import store from './store';
Vue.use(Vuetify);
@ -28,6 +29,7 @@ new Vue({
el: '#app',
router,
i18n,
store,
components: { App },
template: '<App/>',
});

13
src/store/actions.js Normal file
View File

@ -0,0 +1,13 @@
import * as api from '@/api';
import { PUSH_REPORT, STORE_REPORTS } from './mutations-types';
export function fetchReports({ commit }) {
return api.getReports().then(
reports => commit(STORE_REPORTS, { reports }),
);
}
export function saveReport({ commit }, { type, lat, lng }) {
return api.saveReport(type, lat, lng)
.then(report => commit(PUSH_REPORT, { report }));
}

13
src/store/index.js Normal file
View File

@ -0,0 +1,13 @@
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import { initialState as state, mutations } from './mutations';
Vue.use(Vuex);
export default new Vuex.Store({
actions,
state,
mutations,
});

View File

@ -0,0 +1,2 @@
export const PUSH_REPORT = 'PUSH_REPORT';
export const STORE_REPORTS = 'STORE_REPORTS';

14
src/store/mutations.js Normal file
View File

@ -0,0 +1,14 @@
import * as types from './mutations-types';
export const initialState = {
reports: [],
};
export const mutations = {
[types.STORE_REPORTS](state, { reports }) {
state.reports = reports;
},
[types.PUSH_REPORT](state, { report }) {
state.reports.push(report);
},
};

View File

@ -30,7 +30,6 @@
<script>
import NoSleep from 'nosleep.js';
import * as api from '@/api';
import Map from '@/components/Map.vue';
import ReportDialog from '@/components/ReportDialog/index.vue';
import { distance, mockLocation } from '@/tools';
@ -47,7 +46,7 @@ export default {
created() {
this.initializePositionWatching();
this.setNoSleep();
this.fetchReports();
this.$store.dispatch('fetchReports');
},
beforeDestroy() {
this.disableNoSleep();
@ -55,10 +54,7 @@ export default {
},
computed: {
reportsMarkers() {
if (!this.reports) {
return [];
}
return this.reports.map(report => ({
return this.$store.state.reports.map(report => ({
id: report.id,
latLng: [report.attributes.lat, report.attributes.lng],
}));
@ -72,7 +68,6 @@ export default {
lat: null,
lng: null,
noSleep: null,
reports: null,
watchID: null,
};
},
@ -121,7 +116,7 @@ export default {
[position.coords.latitude, position.coords.longitude],
);
if (distanceFromPreviousPoint > UPDATE_REPORTS_DISTANCE_THRESHOLD) {
this.fetchReports();
this.$store.dispatch('fetchReports');
}
}
this.lat = position.coords.latitude;
@ -141,11 +136,6 @@ export default {
this.noSleep.disable();
}
},
fetchReports() {
api.getReports().then((reports) => {
this.reports = reports;
});
},
},
};
</script>

837
yarn.lock

File diff suppressed because it is too large Load Diff