schedule editing
This commit is contained in:
parent
b58ff6286d
commit
3255ee33c0
4 changed files with 181 additions and 8 deletions
67
diffido.py
67
diffido.py
|
@ -87,23 +87,84 @@ class BaseHandler(tornado.web.RequestHandler):
|
|||
self.set_status(status)
|
||||
self.write({'error': True, 'message': message})
|
||||
|
||||
def build_success(self, message='', status=200):
|
||||
"""Build and write a success message.
|
||||
|
||||
:param message: textual message
|
||||
:type message: str
|
||||
:param status: HTTP status code
|
||||
:type status: int
|
||||
"""
|
||||
self.set_status(status)
|
||||
self.write({'error': False, 'message': message})
|
||||
|
||||
|
||||
class SchedulesHandler(BaseHandler):
|
||||
def read_schedules(self):
|
||||
if not os.path.isfile(SCHEDULES_FILE):
|
||||
return {}
|
||||
with open(SCHEDULES_FILE, 'r') as fd:
|
||||
return json.loads(fd.read())
|
||||
return {'schedules': {}}
|
||||
try:
|
||||
with open(SCHEDULES_FILE, 'r') as fd:
|
||||
return json.loads(fd.read())
|
||||
except Exception as e:
|
||||
self.logger.error('unable to read %s: %s' % (SCHEDULES_FILE, e))
|
||||
return {'schedules': {}}
|
||||
|
||||
def write_schedules(self, schedules):
|
||||
with open(SCHEDULES_FILE, 'w') as fd:
|
||||
fd.write(json.dumps(schedules, indent=2))
|
||||
|
||||
def next_id(self, schedules):
|
||||
ids = schedules.get('schedules', {}).keys()
|
||||
if not ids:
|
||||
return 1
|
||||
return max([int(i) for i in ids]) + 1
|
||||
|
||||
def _get_schedule(self, id_):
|
||||
schedules = self.read_schedules()
|
||||
data = schedules.get('schedules', {}).get(id_, {})
|
||||
data['id'] = str(id_)
|
||||
return data
|
||||
|
||||
@gen.coroutine
|
||||
def get(self, id_=None, *args, **kwargs):
|
||||
if id_ is not None:
|
||||
self.write({'schedule': self._get_schedule(id_)})
|
||||
return
|
||||
schedules = self.read_schedules()
|
||||
self.write(schedules)
|
||||
|
||||
@gen.coroutine
|
||||
def put(self, id_=None, *args, **kwargs):
|
||||
if id_ is None:
|
||||
return self.build_error(message='update action requires an ID')
|
||||
data = self.clean_body
|
||||
schedules = self.read_schedules()
|
||||
if id_ not in schedules.get('schedules', {}):
|
||||
return self.build_error(message='schedule %s not found' % id_)
|
||||
schedules['schedules'][id_] = data
|
||||
self.write_schedules(schedules)
|
||||
self.write(self._get_schedule(id_=id_))
|
||||
|
||||
@gen.coroutine
|
||||
def post(self, *args, **kwargs):
|
||||
data = self.clean_body
|
||||
schedules = self.read_schedules()
|
||||
id_ = str(self.next_id(schedules))
|
||||
schedules['schedules'][id_] = data
|
||||
self.write_schedules(schedules)
|
||||
self.write(self._get_schedule(id_=id_))
|
||||
|
||||
@gen.coroutine
|
||||
def delete(self, id_=None, *args, **kwargs):
|
||||
if id_ is None:
|
||||
return self.build_error(message='an ID must be specified')
|
||||
schedules = self.read_schedules()
|
||||
if id_ in schedules.get('schedules', {}):
|
||||
del schedules['schedules'][id_]
|
||||
self.write_schedules(schedules)
|
||||
self.build_success(message='removed schedule %s' % id_)
|
||||
|
||||
|
||||
class TemplateHandler(BaseHandler):
|
||||
"""Handler for the / path."""
|
||||
|
|
1
dist/base.html
vendored
1
dist/base.html
vendored
|
@ -6,6 +6,7 @@
|
|||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons">
|
||||
<link rel="stylesheet" href="/static/css/vue-material.min.css">
|
||||
<link rel="stylesheet" href="/static/css/themes/default.css">
|
||||
<script src="/static/js/lodash.min.js"></script>
|
||||
<script src="/static/js/vue.js"></script>
|
||||
<script src="/static/js/vue-material.min.js"></script>
|
||||
<script src="/static/js/axios.min.js"></script>
|
||||
|
|
21
dist/index.html
vendored
21
dist/index.html
vendored
|
@ -10,7 +10,7 @@
|
|||
</md-table-toolbar>
|
||||
<md-table-row slot="md-table-row" slot-scope="{item}">
|
||||
<md-table-cell md-label="#" md-sort-by="id" md-numeric>${ item.id }</md-table-cell>
|
||||
<md-table-cell md-label="title" md-sort-by="title">${ item.title }</md-table-cell>
|
||||
<md-table-cell md-label="title" md-sort-by="title"><a :href="settingsUrl(item)">${ item.title }</a></md-table-cell>
|
||||
<md-table-cell md-label="url" md-sort-by="email">${ item.url }</md-table-cell>
|
||||
</md-table-row>
|
||||
</md-table>
|
||||
|
@ -31,12 +31,25 @@ var app = new Vue({
|
|||
mounted: function() {
|
||||
this.getSchedules();
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
settingsUrl: function(item) {
|
||||
if (!(item && item.id !== undefined)) {
|
||||
return '';
|
||||
}
|
||||
return '/schedule.html?id=' + item.id;
|
||||
},
|
||||
getSchedules: function() {
|
||||
self = this;
|
||||
var data = axios.get('/api/schedules').then(function(response) {
|
||||
console.log(response);
|
||||
self.schedules = response.data.schedules || [];
|
||||
var schedules = [];
|
||||
_.forEach(response.data.schedules || {}, function(value, key) {
|
||||
value.id = key;
|
||||
schedules.push(value);
|
||||
});
|
||||
self.schedules = schedules;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +64,8 @@ body {
|
|||
|
||||
.md-table {
|
||||
width: 60%;
|
||||
min-height: 200px;
|
||||
max-height: 600px;
|
||||
min-height: 400px;
|
||||
max-height: 800px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
100
dist/schedule.html
vendored
100
dist/schedule.html
vendored
|
@ -1,5 +1,103 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
setting page {{ id }}
|
||||
<div id="app">
|
||||
<div class="md-layout">
|
||||
<div class="md-layout-item" md-card>
|
||||
<md-field>
|
||||
<label>title</label>
|
||||
<md-input v-model="schedule.title"></md-input>
|
||||
</md-field>
|
||||
<md-field>
|
||||
<label>url</label>
|
||||
<md-input v-model="schedule.url"></md-input>
|
||||
</md-field>
|
||||
<md-field>
|
||||
<label>notify email</label>
|
||||
<md-input v-model="schedule.email"></md-input>
|
||||
</md-field>
|
||||
<md-field>
|
||||
<label>XPath selector</label>
|
||||
<md-input v-model="schedule.xpath"></md-input>
|
||||
</md-field>
|
||||
<md-field>
|
||||
<label>minimum change</label>
|
||||
<md-input v-model="schedule.minimum_change"></md-input>
|
||||
</md-field>
|
||||
<md-switch v-model="schedule.enabled">enabled</md-switch>
|
||||
|
||||
<br />
|
||||
<md-button class="md-raised md-primary" @click="saveSchedule()">save</md-button>
|
||||
<md-button class="md-accent" :disabled="!hasID()" @click="deleteSchedule()">delete</md-button>
|
||||
<md-button href="/">cancel</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
Vue.use(VueMaterial.default);
|
||||
|
||||
var app = new Vue({
|
||||
el: '#app',
|
||||
delimiters: ['${', '}'],
|
||||
data: {
|
||||
{% if isinstance(id, str) %}
|
||||
id: "{{id}}",
|
||||
{% else %}
|
||||
id: null,
|
||||
{% end %}
|
||||
schedule: {}
|
||||
},
|
||||
mounted: function() {
|
||||
this.getSchedule(this.id);
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
hasID: function() {
|
||||
return !(this.id === undefined || this.id === null || this.id === '');
|
||||
},
|
||||
getSchedule: function() {
|
||||
if (!this.hasID()) {
|
||||
this.schedule = {enabled: true};
|
||||
return;
|
||||
}
|
||||
self = this;
|
||||
var data = axios.get('/api/schedules/' + this.id).then(function(response) {
|
||||
self.schedule = response.data.schedule || {};
|
||||
});
|
||||
},
|
||||
saveSchedule: function() {
|
||||
var data = this.schedule;
|
||||
if (this.hasID()) {
|
||||
axios.put('/api/schedules/' + this.id, data).then(function(response) {
|
||||
console.log(response);
|
||||
});
|
||||
} else {
|
||||
axios.post('/api/schedules', data).then(function(response) {
|
||||
console.log(response);
|
||||
window.location = '/schedule.html?id=' + response.data.id;
|
||||
});
|
||||
}
|
||||
},
|
||||
deleteSchedule: function() {
|
||||
if (!this.hasID()) {
|
||||
return;
|
||||
}
|
||||
axios.delete('/api/schedules/' + this.id).then(function(response) {
|
||||
window.location = '/';
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% end %}
|
||||
|
|
Loading…
Reference in a new issue