diff --git a/main.py b/main.py index 9c2f021..acc3ca4 100644 --- a/main.py +++ b/main.py @@ -34,8 +34,11 @@ def create_project(): @app.route("/finish_task", methods=["POST"]) def finish_task(): - # TODO read - request.data['upload_session_id'] e request.data['sign_name'] - return + try: + return controller.finish_task() + except: + pyutil.print_stack_trace() + raise def read_settings(app): here = os.path.abspath(__file__) @@ -52,7 +55,7 @@ def setup_controller(): def run(): setup_controller() - app.run(port=app.config['SERVER_PORT']) + app.run(host=app.config['SERVER_HOST'], port=app.config['SERVER_PORT']) if __name__ == '__main__': try: diff --git a/settings_local.py.tmpl b/settings_local.py.tmpl index 9621e29..29ae7ad 100644 --- a/settings_local.py.tmpl +++ b/settings_local.py.tmpl @@ -2,6 +2,7 @@ # Corretor Server Configuration SERVER_HOST = "localhost" SERVER_PORT = 8001 +AGREEMENT_NUMBER = 3 # PyBossa Configuration PYBOSSA_APP_NAME = "Validador de Sinais" diff --git a/validador.py b/validador.py index 4067e47..b161ac2 100644 --- a/validador.py +++ b/validador.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from flask import request, make_response from werkzeug import secure_filename import pbclient @@ -60,3 +61,38 @@ class Validador: result_msg = "The project " + app_short_name + " was updated." pyutil.log(result_msg) return result_msg + + def __find_task(self, project_id, task_id): + tasks = pbclient.find_tasks(project_id, id=task_id) + return tasks[0] if len(tasks) > 0 else None + + def __find_taskruns(self, project_id, task_id): + return pbclient.find_taskruns(project_id, id=task_id) + + def __number_of_taskruns(self, project_id, task_id): + taskruns = self.__find_taskruns(project_id, task_id) + return len(taskruns) + + def __close_task(self, project_id, task_id): + pyutil.log("Closing the task with ID=" + str(task_id) + ".") + task = self.__find_task(project_id, task_id) + number_of_taskruns = self.__number_of_taskruns(project_id, task_id) + task.n_answers = number_of_taskruns + 1 + pbclient.update_task(task) + return "The task with ID=" + str(task_id) + " was closed." + + def finish_task(self): + task_id = request.form['task_id'] + project_id = request.form['project_id'] + number_of_approval = int(request.form['number_of_approval']) + number_of_avatar_disapproval = int(request.form['number_of_avatar_disapproval']) + number_of_ref_disapproval = int(request.form['number_of_ref_disapproval']) + agreement_number = self.config['AGREEMENT_NUMBER'] + result_msg = "" + code = 200 + if (number_of_approval >= agreement_number or number_of_avatar_disapproval >= agreement_number or number_of_ref_disapproval >= agreement_number): + result_msg = self.__close_task(project_id, task_id) + else: + result_msg = "The task with ID=" + str(task_id) + " didn't reach the agreement number yet." + pyutil.log(result_msg) + return make_response(result_msg, code) diff --git a/view/assets/css/main.css b/view/assets/css/main.css index b7548b9..d6c0f9a 100755 --- a/view/assets/css/main.css +++ b/view/assets/css/main.css @@ -26,7 +26,7 @@ } /* Fontes */ -.btn-default, .finish-task-button, h1, +.btn-default, .finish-task-button, .radio-options span, h1, h2, h3, h4, h5, h6 { font-family: 'Titillium Web', sans-serif; } @@ -73,10 +73,17 @@ h6 { } #finish-task-container { - padding-top: 40px; padding-right: 40px; } +.finish-padding-top { + padding-top: 10px; +} + +.finish-padding-top-adjust { + padding-top: 70px; +} + .finish-task-button { float: right; padding-bottom: 0px; @@ -94,3 +101,56 @@ h6 { filter: alpha(opacity = 50); opacity: 0.5; } + +.radio-options span { + padding-right: 5px; +} + +.radio-options input[type=radio] { + width: 18px; + height: 18px; +} + +.correct-answer-container { + padding-right: 10px; + float: left; +} + +.correct-answer-label { + color: #5fc64e; +} + +.incorrect-answer-label { + color: #ec2327; +} + +#comment-ref { + display: none; + padding-right: 40px; +} + +#comment-avatar { + display: none; +} + +.mask { + filter: alpha(opacity = 50); + opacity: 0.5; +} + +#loading-container { + display: none; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; +} + +#loading-container img { + position: absolute; + width: 80px; + top: 37%; + left: 47%; +} \ No newline at end of file diff --git a/view/assets/js/validador.js b/view/assets/js/validador.js new file mode 100644 index 0000000..2b2f763 --- /dev/null +++ b/view/assets/js/validador.js @@ -0,0 +1,244 @@ +(function(validador, $, undefined) { + + var videos_url = ""; + var base_url = ""; + var current_task_id = -1; + + function _disableFinishButton() { + $("#finish-button").off("click"); + $("#finish-button").removeClass("enabled-button"); + $("#finish-button").addClass("disabled-button"); + } + + function _enableFinishButton(task, deferred) { + $("#finish-button").removeClass("disabled-button"); + $("#finish-button").addClass("enabled-button"); + $("#finish-button").off("click").on("click", function() { + _readAnswer(task, deferred, false); + }); + } + + function _hideCommentAvatar() { + $("#comment-avatar").hide(); + $("#finish-task-container").removeClass("finish-padding-top-adjust"); + } + + function _hideCommentRef() { + $("#comment-ref").hide(); + } + + function resetComments() { + $("#comment-avatar").val(""); + $("#comment-ref").val(""); + _hideCommentAvatar(); + _hideCommentRef(); + } + + function _enableLoading() { + $("#loading-container").show(); + $("#main-container").addClass("mask"); + } + + function _disableLoading() { + $("#loading-container").hide(); + $("#main-container").removeClass("mask"); + } + + function _handleAvatarRadioClick(el, task, deferred) { + var is_incorrect_button = $(el).val() == "INCORRECT"; + if (is_incorrect_button) { + _hideCommentRef(); + $("#comment-avatar").show(); + $("#finish-task-container").addClass("finish-padding-top-adjust"); + } else { + _hideCommentAvatar(); + } + var isRefChecked = $("#ref-radio-answers input[type=radio]").is( + ":checked"); + if (isRefChecked) { + _enableFinishButton(task, deferred); + } else { + _disableFinishButton(); + } + } + + function _handleRefRadioClick(el, task, deferred) { + var is_incorrect_button = $(el).val() == "INCORRECT"; + if (is_incorrect_button) { + $("#incorrect-avatar-button").prop("checked", true); + $("#comment-ref").show(); + _hideCommentAvatar(); + } else { + var is_avatar_disabled = $("#avatar-radio-answers input[type=radio]").is(":disabled"); + if (is_avatar_disabled) { + $("#incorrect-avatar-button").prop("checked", false); + } + _hideCommentRef(); + } + $("#avatar-radio-answers input[type=radio]").prop("disabled", + is_incorrect_button); + var is_avatar_checked = $("#avatar-radio-answers input[type=radio]").is( + ":checked"); + if (is_avatar_checked) { + _enableFinishButton(task, deferred); + } else { + _disableFinishButton(); + } + } + + function _setupGUI(task, deferred) { + resetComments(); + _disableFinishButton(); + $("#avatar-radio-answers input[type=radio]").prop("disabled", false); + $("#avatar-radio-answers input[type=radio]").prop("checked", false); + $("#ref-radio-answers input[type=radio]").prop("checked", false); + $("#avatar-radio-answers input[type=radio]").off("click").on("click", + function() { + _handleAvatarRadioClick(this, task, deferred); + }); + $("#ref-radio-answers input[type=radio]").off("click").on("click", + function() { + _handleRefRadioClick(this, task, deferred); + }); + $("#skip-button").off("click").on("click", function() { + _readAnswer(task, deferred, true); + }); + } + + function _readAnswer(task, deferred, has_skipped) { + var status = ""; + var avatar_answer = $("#avatar-radio-answers input[type=radio]:checked") + .val(); + var ref_answer = $("#ref-radio-answers input[type=radio]:checked") + .val(); + if (has_skipped) { + status = "SKIPPED"; + } else if (ref_answer == "INCORRECT") { + status = "REF_DISAPPROVED"; + } else if (avatar_answer == "INCORRECT") { + status = "AVATAR_DISAPPROVED"; + } else { + status = "AVATAR_APPROVED"; + } + _submitAnswer(task, deferred, status, has_skipped); + } + + function _createAnswer(task, status) { + var answer = {}; + var last_answer = task.info.last_answer; + var hasLastAnswer = typeof last_answer != "undefined"; + if (hasLastAnswer) { + answer = last_answer; + } else { + answer = { + "number_of_approval" : 0, + "number_of_avatar_disapproval" : 0, + "number_of_ref_disapproval" : 0 + }; + } + answer["status"] = status; + answer["comment_avatar"] = ""; + answer["comment_ref"] = ""; + if (status == "AVATAR_APPROVED") { + answer["number_of_approval"] = answer.number_of_approval + 1; + } else if (status == "AVATAR_DISAPPROVED") { + answer["number_of_avatar_disapproval"] = answer.number_of_avatar_disapproval + 1; + var comment_avatar = $("#comment-avatar textarea").val(); + if (comment_avatar.trim() != "") { + answer["comment_avatar"] = comment_avatar; + } + } else if (status == "REF_DISAPPROVED") { + answer["number_of_ref_disapproval"] = answer.number_of_ref_disapproval + 1; + var comment_ref = $("#comment-ref textarea").val(); + if (comment_ref.trim() != "") { + answer["comment_ref"] = comment_ref; + } + } + return answer; + } + + function _finishTask(task, deferred, answer) { + _enableLoading(); + $ + .ajax({ + type : "POST", + url : base_url + "/finish_task", + data : { + "task_id" : task.id, + "project_id" : task.project_id, + "number_of_approval" : answer.number_of_approval, + "number_of_avatar_disapproval" : answer.number_of_avatar_disapproval, + "number_of_ref_disapproval" : answer.number_of_ref_disapproval + }, + success : function(response) { + pybossa.saveTask(task.id, answer).done(function() { + _disableLoading(); + $("#success").fadeIn(500); + $("#main-container").hide(); + setTimeout(function() { + deferred.resolve(); + }, 2000); + }); + }, + error : function(xhr, textStatus, error) { + _disableLoading(); + alert(xhr.responseText); + } + }); + + } + + function _submitAnswer(task, deferred, status, has_skipped) { + var answer = _createAnswer(task, status); + if (has_skipped) { + _saveAnswer(task, deferred, answer); + } else { + _finishTask(task, deferred, answer); + } + } + + function _saveAnswer(task, deferred, answer) { + pybossa.saveTask(task.id, answer).done(function() { + $("#success").fadeIn(500); + $("#main-container").hide(); + setTimeout(function() { + deferred.resolve(); + }, 2000); + }); + } + + function _loadTaskInfo(task) { + current_task_id = task.id; + var sign_name = task.info.sign_name; + var avatar_vid_link = videos_url + sign_name + "_AVATAR.webm"; + var ref_vid_link = videos_url + sign_name + "_REF.webm"; + $(".sign-label").text(sign_name); + $("#avatar-video").attr("src", avatar_vid_link); + $("#ref-video").attr("src", ref_vid_link); + } + + pybossa.presentTask(function(task, deferred) { + if (!$.isEmptyObject(task) && current_task_id != task.id) { + _loadTaskInfo(task); + _setupGUI(task, deferred); + $("#success").hide(); + $("#main-container").fadeIn(500); + } else { + $("#main-container").hide(); + $("#finish").fadeIn(500); + } + }); + + // Private methods + function _run(projectname) { + pybossa.run(projectname); + } + + // Public methods + validador.run = function(serverhost, projectname) { + base_url = serverhost; + videos_url = base_url + "/videos/"; + _run(projectname); + }; + +}(window.validador = window.validador || {}, jQuery)); \ No newline at end of file diff --git a/view/img/correct.png b/view/img/correct.png new file mode 100644 index 0000000..3340434 Binary files /dev/null and b/view/img/correct.png differ diff --git a/view/img/incorrect.png b/view/img/incorrect.png new file mode 100644 index 0000000..be2d49f Binary files /dev/null and b/view/img/incorrect.png differ diff --git a/view/img/loading.gif b/view/img/loading.gif new file mode 100644 index 0000000..0fcd282 Binary files /dev/null and b/view/img/loading.gif differ diff --git a/view/img/no.png b/view/img/no.png deleted file mode 100644 index 3879b2f..0000000 Binary files a/view/img/no.png and /dev/null differ diff --git a/view/template.html b/view/template.html index b96818c..a16db2f 100755 --- a/view/template.html +++ b/view/template.html @@ -1,5 +1,7 @@ + +
ENVIAR COMENTÁRIO SOBRE A ANIMAÇÃO:
+ +