edit.py 6.63 KB
Newer Older
Andreas Valder's avatar
Andreas Valder committed
1
2
3
from server import *

# name: (tablename, idcolumn, [editable_fields], [fields_to_set_at_creation_time])
Andreas Valder's avatar
Andreas Valder committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# field types:
# 	boolean
# 	shortstring
# 	text
# 	datetime
# 	duration
# 	videotime
editable_tables = {
	'courses': {
		'table': 'courses_data',
		'idcolumn': 'id',
		'editable_fields': {
			'visible':	{'type': 'boolean'},
			'listed':	{'type': 'boolean'},
			'title':	{'type': 'shortstring'},
			'short':	{'type': 'shortstring'},
			'handle':	{'type': 'shortstring'},
			'organizer':	{'type': 'shortstring'},
			'subject':	{'type': 'shortstring'},
			'semester':	{'type': 'shortstring'},
			'downloadable':	{'type': 'boolean'},
			'internal':	{'type': 'text'},
			'responsible':	{'type': 'shortstring'},
			'deleted':	{'type': 'boolean'},
			'description':	{'type': 'text'} },
		'creationtime_fields': ['created_by', 'time_created', 'time_updated'] },
	'lectures': {
		'table': 'lectures_data',
		'idcolumn': 'id',
		'editable_fields': {
			'visible':	{'type': 'boolean'},
			'title':	{'type': 'shortstring'},
			'comment':	{'type': 'text'},
			'internal':	{'type': 'text'},
			'speaker':	{'type': 'shortstring'},
			'place':	{'type': 'shortstring'},
			'time':		{'type': 'datetime'},
			'duration':	{'type': 'duration'},
			'jumplist':	{'type': ''},
			'deleted':	{'type': 'boolean'}},
		'creationtime_fields': ['course_id', 'time_created', 'time_updated'] },
	'videos': {
		'table': 'videos_data',
		'idcolumn': 'id',
		'editable_fields': {
			'visible':	{'type': 'boolean'},
			'deleted':	{'type': 'boolean'}},
		'creationtime_fields': ['created_by', 'time_created', 'time_updated'] },
	'chapters': {
		'table': 'chapters',
		'idcolumn': 'id',
		'editable_fields': {
			'time':		{'type': 'videotime'},
			'text':		{'type': 'shortstring'},
			'visible':	{'type': 'boolean'},
			'deleted':	{'type': 'boolean'}},
		'creationtime_fields': ['created_by', 'time_created', 'time_updated'] },
	'announcements': {
		'table': 'announcements',
		'idcolumn': 'id',
		'editable_fields': {
			'text':		{'type': 'text'},
			'level':	{'type': 'integer'},
			'visible':	{'type': 'boolean'},
			'deleted':	{'type': 'boolean'},
			'time_publish':	{'type': 'datetime'},
			'time_expire':	{'type': 'datetime'}},
		'creationtime_fields': ['created_by', 'time_created', 'time_updated'] },
	'featured': {
		'table': 'featured',
		'idcolumn': 'id',
		'editable_fields':	{
			'title':	{'type': 'shortstring'},
			'text':		{'type': 'text'},
			'internal':	{'type': 'text'},
			'visible':	{'type': 'boolean'},
			'deleted':	{'type': 'boolean'},
			'param':	{'type': 'shortstring'},
			'param2':	{'type': 'shortstring'},
			'order':	{'type': 'integer' }},
		'creationtime_fields': ['created_by', 'time_created', 'time_updated', 'type'] },
	'perm': {
		'table': 'perm',
		'idcolumn': 'id',
		'editable_fields': {
			'type':		{'type': 'shortstring'},
			'param1':	{'type': 'shortstring'},
			'param2':	{'type': 'shortstring'},
			'deleted':	{'type': 'boolean'}},
		'creationtime_fields': ['course_id', 'lecture_id', 'video_id', 'created_by', 'time_created', 'time_updated'] },
	'sorterrorlog': {
		'table': 'sorterrorlog_data',
		'idcolumn': 'id',
		'editable_fields': {
			'deleted':	{'type': 'boolean'}},
		'creationtime_fields': ['time_created', 'time_updated'] }
	}

#parses the path to a dict, containing the table, id, field and field type
@app.template_filter(name='parseeditpath')
def parseeditpath(path):
	table, id, column = path.split('.', 2)
	assert table in editable_tables
	assert column in editable_tables[table]['editable_fields']
	type = editable_tables[table]['editable_fields'][column]['type']
	return {'table': table, 'id': id, 'column': column, 'type': type, 'tableinfo': editable_tables[table]}
Andreas Valder's avatar
Andreas Valder committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

@app.route('/internal/edit', methods=['GET', 'POST'])
@mod_required
@csrf_protect
def edit(prefix='', ignore=[]):
	# All editable tables are expected to have a 'time_updated' field
	ignore.append('ref')
	ignore.append('prefix')
	ignore.append('_csrf_token')
	if not prefix and 'prefix' in request.args:
		prefix = request.args['prefix']
	changes = request.values.items()
	if (request.method == 'POST') and (request.get_json()):
		changes = request.get_json().items()
	for key, val in changes:
		if key in ignore:
			continue
		key = prefix+key
Andreas Valder's avatar
Andreas Valder committed
128
129
130
131
132
		path = parseeditpath(key)
		modify('INSERT INTO changelog (`table`,id_value, id_key, field, value_new, value_old, `when`, who, executed) \
			VALUES (?,?,?,?,?,(SELECT `%s` FROM %s WHERE %s = ?),?,?,1)'%(path['column'], path['tableinfo']['table'], path['tableinfo']['idcolumn']),
				path['table'], path['id'], path['tableinfo']['idcolumn'], path['column'], val, path['id'], datetime.now(), session['user']['dbid'])
		modify('UPDATE %s SET `%s` = ?, time_updated = ? WHERE `%s` = ?'%(path['tableinfo']['table'], path['column'], path['tableinfo']['idcolumn']), val, datetime.now(),path['id'])
Andreas Valder's avatar
Andreas Valder committed
133
134
135
136
137
138
139
140
	if 'ref' in request.values:
		return redirect(request.values['ref'])
	return "OK", 200

@app.route('/internal/new/<table>', methods=['GET', 'POST'])
@mod_required
@csrf_protect
def create(table):
Andreas Valder's avatar
Andreas Valder committed
141
	assert table in editable_tables
Andreas Valder's avatar
Andreas Valder committed
142
143
144
145
	defaults = {'created_by': session['user']['dbid'], 'time_created': datetime.now(), 'time_updated': datetime.now()}
	columns = []
	values = []
	for column, val in defaults.items():
Andreas Valder's avatar
Andreas Valder committed
146
		if column in editable_tables[table]['creationtime_fields']:
Andreas Valder's avatar
Andreas Valder committed
147
148
149
150
151
152
153
154
			columns.append(column)
			values.append(val)
	args = request.values.items()
	if (request.method == 'POST') and (request.get_json()):
		args = request.get_json().items()
	for column, val in args:
		if (column == 'ref') or (column == '_csrf_token'):
			continue
Andreas Valder's avatar
Andreas Valder committed
155
		assert column in list(editable_tables[table]['editable_fields'].keys())+editable_tables[table]['creationtime_fields']
Andreas Valder's avatar
Andreas Valder committed
156
157
158
		assert column not in defaults
		columns.append('`'+column+'`')
		values.append(val)
Andreas Valder's avatar
Andreas Valder committed
159
	id = modify('INSERT INTO %s (%s) VALUES (%s)'%(editable_tables[table]['table'],
Andreas Valder's avatar
Andreas Valder committed
160
161
162
163
				','.join(columns), ','.join(['?']*len(values))), *values)
	if 'ref' in request.values:
		return redirect(request.values['ref'])
	return str(id), 200
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

@app.route('/internal/changelog')
@register_navbar('Changelog', icon='book')
@mod_required
def changelog():
	if 'page' in request.args:
		page = max(0, int(request.args['page']))
	else:
		page = 0
	if 'pagesize' in request.args:
		pagesize = min(500, int(request.args['pagesize']))
	else:
		pagesize = 50
	changelog = query('SELECT * FROM changelog LEFT JOIN users ON (changelog.who = users.id) ORDER BY `when` DESC LIMIT ? OFFSET ?', pagesize, page*pagesize)
	pagecount = math.ceil(query('SELECT count(id) as count FROM changelog')[0]['count']/pagesize)
	for entry in changelog:
		entry['path'] = '.'.join([entry['table'], entry['id_value'], entry['field']])
	return render_template('changelog.html', changelog=changelog, page=page, pagesize=pagesize, pagecount=pagecount)