Show the reports as soon as they are added in the db
This commit is contained in:
parent
e961a8dbb1
commit
f30d000f92
@ -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",
|
||||
|
@ -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')
|
||||
|
@ -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():
|
||||
"""
|
||||
|
@ -38,4 +38,4 @@ class Report(BaseModel):
|
||||
k: v for k, v in model_to_dict(self).items()
|
||||
if k != "id"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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}.`));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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
13
src/store/actions.js
Normal 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
13
src/store/index.js
Normal 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,
|
||||
});
|
2
src/store/mutations-types.js
Normal file
2
src/store/mutations-types.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const PUSH_REPORT = 'PUSH_REPORT';
|
||||
export const STORE_REPORTS = 'STORE_REPORTS';
|
14
src/store/mutations.js
Normal file
14
src/store/mutations.js
Normal 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);
|
||||
},
|
||||
};
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user