diff --git a/db_schema.sql b/db_schema.sql index 43ad82ee8fb90635da6afe94d8e7ff19db7530b8..c1570e44f4003323ca541f159badb8fa0adec4cd 100644 --- a/db_schema.sql +++ b/db_schema.sql @@ -230,6 +230,24 @@ CREATE TABLE IF NOT EXISTS `sorterrorlog_data` ( `time_created` datetime NOT NULL ); +CREATE TABLE IF NOT EXISTS `worker` ( +`hostname` text NOT NULL PRIMARY KEY, + `last_ping` datetime NOT NULL +); + +CREATE TABLE IF NOT EXISTS `jobs` ( +`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `type` text NOT NULL, + `priority` INTEGER NOT NULL DEFAULT 0, + `state` text NOT NULL DEFAULT 'ready', + `time_finished` datetime DEFAULT '', + `time_created` datetime NOT NULL, + `last_ping` datetime NOT NULL DEFAULT '', + `worker` text DEFAULT NULL, + `data` text NOT NULL DEFAULT '{}', + `status` text NOT NULL DEFAULT '{}' +); + CREATE VIEW IF NOT EXISTS `courses` AS select * from `courses_data` where (not(`courses_data`.`deleted`)); CREATE VIEW IF NOT EXISTS `lectures` AS select `lectures_data`.* from `lectures_data` join `courses_data` on (`courses_data`.`id` = `course_id`) where (not(`lectures_data`.`deleted` or `courses_data`.`deleted`)); CREATE VIEW IF NOT EXISTS `videos` AS select `videos_data`.* from `videos_data` join `lectures_data` on (`lectures_data`.`id` = `lecture_id`) join `courses_data` on (`courses_data`.`id` = `course_id`) where (not(`videos_data`.`deleted` or `lectures_data`.`deleted` or `courses_data`.`deleted`)); diff --git a/jobs.py b/jobs.py index 8fea7a8b3a30ab107786c7a235a09319b13c9c5c..c5d6442f705f6bc0bb6f299109f529c02c166d8d 100644 --- a/jobs.py +++ b/jobs.py @@ -1,15 +1,51 @@ from server import * import traceback +import json @app.route('/jobs/overview') @register_navbar('Jobs', iconlib='fa', icon='suitcase') @mod_required def jobs_overview(): - # todo - return render_template('base.html') + worker = query('SELECT * FROM worker ORDER BY last_ping DESC') + jobs = query('SELECT * FROM jobs') + return render_template('jobs_overview.html',worker=worker,jobs=jobs) -@app.route('/jobs/api', methods=['GET', 'POST']) -@mod_required -def jobs_api(): - # todo - return render_template('base.html') +def jobs_api_token_required(func): + @wraps(func) + def decorator(*args, **kwargs): + if 'apikey' in request.values: + token = request.values['apikey'] + elif request.get_json() and ('apikey' in request.get_json()): + token = request.get_json()['apikey'] + else: + token = None + + if not token == config['JOBS_API_KEY']: + return 'Permission denied', 403 + else: + return func(*args, **kwargs) + return decorator + +def date_json_handler(obj): + return obj.isoformat() if hasattr(obj, 'isoformat') else obj + +@app.route('/jobs/api/ping', methods=['GET', 'POST']) +@jobs_api_token_required +def jobs_ping(): + hostname = request.values['host'] + query('INSERT OR REPLACE INTO worker (hostname, last_ping) values (?, ?)',hostname,datetime.now()) + return 'OK',200 + +@app.route('/jobs/api/schedule', methods=['POST']) +@jobs_api_token_required +def jobs_schedule(): + hostdata = request.get_json() + print(hostdata) + if not hostdata: + return 'no data', 500 + jobtypes = hostdata['jobtypes'] if 'jobtypes' in hostdata else [] + for i in query('SELECT * FROM jobs WHERE state = "ready" ORDER BY priority DESC'): + if i['type'] in hostdata['jobtypes'].split(','): + job=i + break + return Response(json.dumps(job, default=date_json_handler), mimetype='application/json') diff --git a/server.py b/server.py index 1bf0958f8d2701047f4fcf300b141373c5366f82..62918f7105c3d93daaad5c77ef8be8393d4bd49a 100644 --- a/server.py +++ b/server.py @@ -10,7 +10,6 @@ import random import sched import traceback import string -import traceback app = Flask(__name__) diff --git a/sorter.py b/sorter.py index f7473b10946cdbe8b1d352e102306fad7859eb66..b17ccb4c9b69ea92bb314f6b6b4e4736e641a781 100644 --- a/sorter.py +++ b/sorter.py @@ -33,7 +33,25 @@ def insert_video(lectureid,dbfilepath,filepath,fileformatid): (?,0,?,?,"","","",?,?,?,?,"",?)''', lectureid, dbfilepath, fileformatid, datetime.now(), datetime.now(), datetime.now(), -1, os.stat(filepath).st_size) query('INSERT INTO sortlog (lecture_id,video_id,path,`when`) VALUES (?,?,?,?)', lectureid, video_id, dbfilepath, datetime.now()) + schedule_thumbnail(lectureid) +def schedule_thumbnail(lectureid): + exists = query('SELECT * FROM jobs WHERE data LIKE ?','%"lectureid": "'+str(lectureid)+'"%' ) + if exists: + return + path = query('SELECT path FROM videos WHERE lecture_id') + videos = query(''' + SELECT videos.path + FROM videos + JOIN formats ON (videos.video_format = formats.id) + WHERE videos.lecture_id = ? + ORDER BY formats.prio DESC''', lectureid ) + if videos: + path = videos[0]['path'] + else: + return + data = '{"lectureid": "'+str(lectureid)+'", "path": "'+path+'"}' + query('INSERT INTO jobs (type, data, time_created) VALUES ("thumbnail", ?, ?)', data, datetime.now()); @app.route('/sort/now') @mod_required diff --git a/templates/jobs_overview.html b/templates/jobs_overview.html new file mode 100644 index 0000000000000000000000000000000000000000..a5af33befc55b799de503eb0751752f254aba51d --- /dev/null +++ b/templates/jobs_overview.html @@ -0,0 +1,87 @@ +{% extends "base.html" %} +{% block content %} +<div class="panel-group"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h1 class="panel-title"> + Worker + </h1> + </div> + <div class="panel-collapse collapse in"> + <div class="panel-body"> + <table class="table"> + <tr> + <th>Hostname</th> + <th>letzter Ping</th> + </tr> + {% for i in worker %} + {% set td = (datetime.now()-(i.last_ping) ) %} + + {% if td < timedelta(seconds=10) %} + <tr class="success"> + {% elif td < timedelta(seconds=30) %} + <tr class="warning"> + {% else %} + <tr class="danger"> + {% endif %} + <td>{{i.hostname}}</td> + <td>{{i.last_ping}}</td> + </tr> + {% endfor %} + </table> + </div> + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading"> + <h1 class="panel-title"> + Jobs + </h1> + </div> + <div class="panel-collapse collapse in"> + <div class="panel-body"> + <table class="table"> + <tr> + <th>ID</th> + <th>Type</th> + <th>Priority</th> + <th>Worker</th> + <th>letzter Ping</th> + <th>State</th> + <th>Eingereiht am</th> + <th>Fertig geworden am</th> + <th>Daten</th> + </tr> + {% for i in jobs %} + {% if i.last_ping %} + {% set td = (datetime.now()-(i.last_ping) ) %} + {% else %} + {% set td = -1 %} + {% endif %} + + {% if td == -1 %} + <tr> + {% elif td < timedelta(seconds=20) %} + <tr class="success"> + {% elif td < timedelta(seconds=60) %} + <tr class="warning"> + {% else %} + <tr class="danger"> + {% endif %} + <td>{{i.id}}</td> + <td>{{i.type}}</td> + <td>{{i.priority}}</td> + <td>{{i.worker}}</td> + <td>{{i.last_ping}}</td> + <td>{{i.state}}</td> + <td>{{i.time_created}}</td> + <td>{{i.time_finished}}</td> + <td>{{i.data}}</td> + </tr> + {% endfor %} + </table> + </div> + </div> + </div> +</div> +{% endblock %}