Commit 14a879832960375bdb519f612fda70131a7c4499

Authored by Adabriand Furtado
1 parent dc11a23e
Exists in master

Lógica em JavaScript movida para o validador.js para modularização do código.

main.py
... ... @@ -34,8 +34,11 @@ def create_project():
34 34  
35 35 @app.route("/finish_task", methods=["POST"])
36 36 def finish_task():
37   - # TODO read - request.data['upload_session_id'] e request.data['sign_name']
38   - return
  37 + try:
  38 + return controller.finish_task()
  39 + except:
  40 + pyutil.print_stack_trace()
  41 + raise
39 42  
40 43 def read_settings(app):
41 44 here = os.path.abspath(__file__)
... ... @@ -52,7 +55,7 @@ def setup_controller():
52 55  
53 56 def run():
54 57 setup_controller()
55   - app.run(port=app.config['SERVER_PORT'])
  58 + app.run(host=app.config['SERVER_HOST'], port=app.config['SERVER_PORT'])
56 59  
57 60 if __name__ == '__main__':
58 61 try:
... ...
settings_local.py.tmpl
... ... @@ -2,6 +2,7 @@
2 2 # Corretor Server Configuration
3 3 SERVER_HOST = "localhost"
4 4 SERVER_PORT = 8001
  5 +AGREEMENT_NUMBER = 3
5 6  
6 7 # PyBossa Configuration
7 8 PYBOSSA_APP_NAME = "Validador de Sinais"
... ...
validador.py
  1 +# -*- coding: utf-8 -*-
1 2 from flask import request, make_response
2 3 from werkzeug import secure_filename
3 4 import pbclient
... ... @@ -60,3 +61,38 @@ class Validador:
60 61 result_msg = "The project " + app_short_name + " was updated."
61 62 pyutil.log(result_msg)
62 63 return result_msg
  64 +
  65 + def __find_task(self, project_id, task_id):
  66 + tasks = pbclient.find_tasks(project_id, id=task_id)
  67 + return tasks[0] if len(tasks) > 0 else None
  68 +
  69 + def __find_taskruns(self, project_id, task_id):
  70 + return pbclient.find_taskruns(project_id, id=task_id)
  71 +
  72 + def __number_of_taskruns(self, project_id, task_id):
  73 + taskruns = self.__find_taskruns(project_id, task_id)
  74 + return len(taskruns)
  75 +
  76 + def __close_task(self, project_id, task_id):
  77 + pyutil.log("Closing the task with ID=" + str(task_id) + ".")
  78 + task = self.__find_task(project_id, task_id)
  79 + number_of_taskruns = self.__number_of_taskruns(project_id, task_id)
  80 + task.n_answers = number_of_taskruns + 1
  81 + pbclient.update_task(task)
  82 + return "The task with ID=" + str(task_id) + " was closed."
  83 +
  84 + def finish_task(self):
  85 + task_id = request.form['task_id']
  86 + project_id = request.form['project_id']
  87 + number_of_approval = int(request.form['number_of_approval'])
  88 + number_of_avatar_disapproval = int(request.form['number_of_avatar_disapproval'])
  89 + number_of_ref_disapproval = int(request.form['number_of_ref_disapproval'])
  90 + agreement_number = self.config['AGREEMENT_NUMBER']
  91 + result_msg = ""
  92 + code = 200
  93 + if (number_of_approval >= agreement_number or number_of_avatar_disapproval >= agreement_number or number_of_ref_disapproval >= agreement_number):
  94 + result_msg = self.__close_task(project_id, task_id)
  95 + else:
  96 + result_msg = "The task with ID=" + str(task_id) + " didn't reach the agreement number yet."
  97 + pyutil.log(result_msg)
  98 + return make_response(result_msg, code)
... ...
view/assets/css/main.css
... ... @@ -26,7 +26,7 @@
26 26 }
27 27  
28 28 /* Fontes */
29   -.btn-default, .finish-task-button, h1,
  29 +.btn-default, .finish-task-button, .radio-options span, h1,
30 30 h2, h3, h4, h5, h6 {
31 31 font-family: 'Titillium Web', sans-serif;
32 32 }
... ... @@ -73,10 +73,17 @@ h6 {
73 73 }
74 74  
75 75 #finish-task-container {
76   - padding-top: 40px;
77 76 padding-right: 40px;
78 77 }
79 78  
  79 +.finish-padding-top {
  80 + padding-top: 10px;
  81 +}
  82 +
  83 +.finish-padding-top-adjust {
  84 + padding-top: 70px;
  85 +}
  86 +
80 87 .finish-task-button {
81 88 float: right;
82 89 padding-bottom: 0px;
... ... @@ -94,3 +101,56 @@ h6 {
94 101 filter: alpha(opacity = 50);
95 102 opacity: 0.5;
96 103 }
  104 +
  105 +.radio-options span {
  106 + padding-right: 5px;
  107 +}
  108 +
  109 +.radio-options input[type=radio] {
  110 + width: 18px;
  111 + height: 18px;
  112 +}
  113 +
  114 +.correct-answer-container {
  115 + padding-right: 10px;
  116 + float: left;
  117 +}
  118 +
  119 +.correct-answer-label {
  120 + color: #5fc64e;
  121 +}
  122 +
  123 +.incorrect-answer-label {
  124 + color: #ec2327;
  125 +}
  126 +
  127 +#comment-ref {
  128 + display: none;
  129 + padding-right: 40px;
  130 +}
  131 +
  132 +#comment-avatar {
  133 + display: none;
  134 +}
  135 +
  136 +.mask {
  137 + filter: alpha(opacity = 50);
  138 + opacity: 0.5;
  139 +}
  140 +
  141 +#loading-container {
  142 + display: none;
  143 + position: fixed;
  144 + top: 0;
  145 + right: 0;
  146 + bottom: 0;
  147 + left: 0;
  148 + z-index: 1040;
  149 +}
  150 +
  151 +#loading-container img {
  152 + position: absolute;
  153 + width: 80px;
  154 + top: 37%;
  155 + left: 47%;
  156 +}
97 157 \ No newline at end of file
... ...
view/assets/js/validador.js 0 → 100644
... ... @@ -0,0 +1,244 @@
  1 +(function(validador, $, undefined) {
  2 +
  3 + var videos_url = "";
  4 + var base_url = "";
  5 + var current_task_id = -1;
  6 +
  7 + function _disableFinishButton() {
  8 + $("#finish-button").off("click");
  9 + $("#finish-button").removeClass("enabled-button");
  10 + $("#finish-button").addClass("disabled-button");
  11 + }
  12 +
  13 + function _enableFinishButton(task, deferred) {
  14 + $("#finish-button").removeClass("disabled-button");
  15 + $("#finish-button").addClass("enabled-button");
  16 + $("#finish-button").off("click").on("click", function() {
  17 + _readAnswer(task, deferred, false);
  18 + });
  19 + }
  20 +
  21 + function _hideCommentAvatar() {
  22 + $("#comment-avatar").hide();
  23 + $("#finish-task-container").removeClass("finish-padding-top-adjust");
  24 + }
  25 +
  26 + function _hideCommentRef() {
  27 + $("#comment-ref").hide();
  28 + }
  29 +
  30 + function resetComments() {
  31 + $("#comment-avatar").val("");
  32 + $("#comment-ref").val("");
  33 + _hideCommentAvatar();
  34 + _hideCommentRef();
  35 + }
  36 +
  37 + function _enableLoading() {
  38 + $("#loading-container").show();
  39 + $("#main-container").addClass("mask");
  40 + }
  41 +
  42 + function _disableLoading() {
  43 + $("#loading-container").hide();
  44 + $("#main-container").removeClass("mask");
  45 + }
  46 +
  47 + function _handleAvatarRadioClick(el, task, deferred) {
  48 + var is_incorrect_button = $(el).val() == "INCORRECT";
  49 + if (is_incorrect_button) {
  50 + _hideCommentRef();
  51 + $("#comment-avatar").show();
  52 + $("#finish-task-container").addClass("finish-padding-top-adjust");
  53 + } else {
  54 + _hideCommentAvatar();
  55 + }
  56 + var isRefChecked = $("#ref-radio-answers input[type=radio]").is(
  57 + ":checked");
  58 + if (isRefChecked) {
  59 + _enableFinishButton(task, deferred);
  60 + } else {
  61 + _disableFinishButton();
  62 + }
  63 + }
  64 +
  65 + function _handleRefRadioClick(el, task, deferred) {
  66 + var is_incorrect_button = $(el).val() == "INCORRECT";
  67 + if (is_incorrect_button) {
  68 + $("#incorrect-avatar-button").prop("checked", true);
  69 + $("#comment-ref").show();
  70 + _hideCommentAvatar();
  71 + } else {
  72 + var is_avatar_disabled = $("#avatar-radio-answers input[type=radio]").is(":disabled");
  73 + if (is_avatar_disabled) {
  74 + $("#incorrect-avatar-button").prop("checked", false);
  75 + }
  76 + _hideCommentRef();
  77 + }
  78 + $("#avatar-radio-answers input[type=radio]").prop("disabled",
  79 + is_incorrect_button);
  80 + var is_avatar_checked = $("#avatar-radio-answers input[type=radio]").is(
  81 + ":checked");
  82 + if (is_avatar_checked) {
  83 + _enableFinishButton(task, deferred);
  84 + } else {
  85 + _disableFinishButton();
  86 + }
  87 + }
  88 +
  89 + function _setupGUI(task, deferred) {
  90 + resetComments();
  91 + _disableFinishButton();
  92 + $("#avatar-radio-answers input[type=radio]").prop("disabled", false);
  93 + $("#avatar-radio-answers input[type=radio]").prop("checked", false);
  94 + $("#ref-radio-answers input[type=radio]").prop("checked", false);
  95 + $("#avatar-radio-answers input[type=radio]").off("click").on("click",
  96 + function() {
  97 + _handleAvatarRadioClick(this, task, deferred);
  98 + });
  99 + $("#ref-radio-answers input[type=radio]").off("click").on("click",
  100 + function() {
  101 + _handleRefRadioClick(this, task, deferred);
  102 + });
  103 + $("#skip-button").off("click").on("click", function() {
  104 + _readAnswer(task, deferred, true);
  105 + });
  106 + }
  107 +
  108 + function _readAnswer(task, deferred, has_skipped) {
  109 + var status = "";
  110 + var avatar_answer = $("#avatar-radio-answers input[type=radio]:checked")
  111 + .val();
  112 + var ref_answer = $("#ref-radio-answers input[type=radio]:checked")
  113 + .val();
  114 + if (has_skipped) {
  115 + status = "SKIPPED";
  116 + } else if (ref_answer == "INCORRECT") {
  117 + status = "REF_DISAPPROVED";
  118 + } else if (avatar_answer == "INCORRECT") {
  119 + status = "AVATAR_DISAPPROVED";
  120 + } else {
  121 + status = "AVATAR_APPROVED";
  122 + }
  123 + _submitAnswer(task, deferred, status, has_skipped);
  124 + }
  125 +
  126 + function _createAnswer(task, status) {
  127 + var answer = {};
  128 + var last_answer = task.info.last_answer;
  129 + var hasLastAnswer = typeof last_answer != "undefined";
  130 + if (hasLastAnswer) {
  131 + answer = last_answer;
  132 + } else {
  133 + answer = {
  134 + "number_of_approval" : 0,
  135 + "number_of_avatar_disapproval" : 0,
  136 + "number_of_ref_disapproval" : 0
  137 + };
  138 + }
  139 + answer["status"] = status;
  140 + answer["comment_avatar"] = "";
  141 + answer["comment_ref"] = "";
  142 + if (status == "AVATAR_APPROVED") {
  143 + answer["number_of_approval"] = answer.number_of_approval + 1;
  144 + } else if (status == "AVATAR_DISAPPROVED") {
  145 + answer["number_of_avatar_disapproval"] = answer.number_of_avatar_disapproval + 1;
  146 + var comment_avatar = $("#comment-avatar textarea").val();
  147 + if (comment_avatar.trim() != "") {
  148 + answer["comment_avatar"] = comment_avatar;
  149 + }
  150 + } else if (status == "REF_DISAPPROVED") {
  151 + answer["number_of_ref_disapproval"] = answer.number_of_ref_disapproval + 1;
  152 + var comment_ref = $("#comment-ref textarea").val();
  153 + if (comment_ref.trim() != "") {
  154 + answer["comment_ref"] = comment_ref;
  155 + }
  156 + }
  157 + return answer;
  158 + }
  159 +
  160 + function _finishTask(task, deferred, answer) {
  161 + _enableLoading();
  162 + $
  163 + .ajax({
  164 + type : "POST",
  165 + url : base_url + "/finish_task",
  166 + data : {
  167 + "task_id" : task.id,
  168 + "project_id" : task.project_id,
  169 + "number_of_approval" : answer.number_of_approval,
  170 + "number_of_avatar_disapproval" : answer.number_of_avatar_disapproval,
  171 + "number_of_ref_disapproval" : answer.number_of_ref_disapproval
  172 + },
  173 + success : function(response) {
  174 + pybossa.saveTask(task.id, answer).done(function() {
  175 + _disableLoading();
  176 + $("#success").fadeIn(500);
  177 + $("#main-container").hide();
  178 + setTimeout(function() {
  179 + deferred.resolve();
  180 + }, 2000);
  181 + });
  182 + },
  183 + error : function(xhr, textStatus, error) {
  184 + _disableLoading();
  185 + alert(xhr.responseText);
  186 + }
  187 + });
  188 +
  189 + }
  190 +
  191 + function _submitAnswer(task, deferred, status, has_skipped) {
  192 + var answer = _createAnswer(task, status);
  193 + if (has_skipped) {
  194 + _saveAnswer(task, deferred, answer);
  195 + } else {
  196 + _finishTask(task, deferred, answer);
  197 + }
  198 + }
  199 +
  200 + function _saveAnswer(task, deferred, answer) {
  201 + pybossa.saveTask(task.id, answer).done(function() {
  202 + $("#success").fadeIn(500);
  203 + $("#main-container").hide();
  204 + setTimeout(function() {
  205 + deferred.resolve();
  206 + }, 2000);
  207 + });
  208 + }
  209 +
  210 + function _loadTaskInfo(task) {
  211 + current_task_id = task.id;
  212 + var sign_name = task.info.sign_name;
  213 + var avatar_vid_link = videos_url + sign_name + "_AVATAR.webm";
  214 + var ref_vid_link = videos_url + sign_name + "_REF.webm";
  215 + $(".sign-label").text(sign_name);
  216 + $("#avatar-video").attr("src", avatar_vid_link);
  217 + $("#ref-video").attr("src", ref_vid_link);
  218 + }
  219 +
  220 + pybossa.presentTask(function(task, deferred) {
  221 + if (!$.isEmptyObject(task) && current_task_id != task.id) {
  222 + _loadTaskInfo(task);
  223 + _setupGUI(task, deferred);
  224 + $("#success").hide();
  225 + $("#main-container").fadeIn(500);
  226 + } else {
  227 + $("#main-container").hide();
  228 + $("#finish").fadeIn(500);
  229 + }
  230 + });
  231 +
  232 + // Private methods
  233 + function _run(projectname) {
  234 + pybossa.run(projectname);
  235 + }
  236 +
  237 + // Public methods
  238 + validador.run = function(serverhost, projectname) {
  239 + base_url = serverhost;
  240 + videos_url = base_url + "/videos/";
  241 + _run(projectname);
  242 + };
  243 +
  244 +}(window.validador = window.validador || {}, jQuery));
0 245 \ No newline at end of file
... ...
view/img/correct.png 0 → 100644

4.98 KB

view/img/incorrect.png 0 → 100644

4.88 KB

view/img/loading.gif 0 → 100644

78 KB

view/img/no.png

6.12 KB

view/template.html
1 1 <link rel="stylesheet" href="{{ server }}/assets/css/main.css">
2 2  
  3 +<script src="{{ server }}/assets/js/validador.js"></script>
  4 +
3 5 <div class="row">
4 6 <div id="success" class="alert alert-success" style="display: none;">
5 7 <strong>Parabéns!</strong> <span>Tarefa concluída.</span>
... ... @@ -13,7 +15,9 @@
13 15 </div>
14 16 </div>
15 17 </div>
16   -
  18 +<div id="loading-container">
  19 + <img src="{{ server }}/img/loading.gif">
  20 +</div>
17 21 <div id="main-container" class="container">
18 22 <div id="validador-header">
19 23 <h2>
... ... @@ -34,6 +38,23 @@
34 38 <source type="video/webm">
35 39 </video>
36 40 </div>
  41 + <div id="avatar-radio-answers" class="row radio-options">
  42 + <div class="correct-answer-container"">
  43 + <span class="correct-answer-label">ESTÁ CORRETO</span><img
  44 + class="icon" src="{{ server }}/img/correct.png"></img><input
  45 + value="CORRECT" type="radio" name="avatar-answers">
  46 + </div>
  47 + <div>
  48 + <span class="incorrect-answer-label">ESTÁ ERRADO</span><img
  49 + class="icon" src="{{ server }}/img/incorrect.png"></img><input
  50 + id="incorrect-avatar-button" value="INCORRECT" type="radio"
  51 + name="avatar-answers">
  52 + </div>
  53 + </div>
  54 + <div id="comment-avatar" class="form-group">
  55 + <h6>ENVIAR COMENTÁRIO SOBRE A ANIMAÇÃO:</h6>
  56 + <textarea class="form-control" rows="2"></textarea>
  57 + </div>
37 58 </div>
38 59 <div id="ref-container" class="col-sm-6 video-container">
39 60 <div class="row">
... ... @@ -47,125 +68,36 @@
47 68 <source type="video/webm">
48 69 </video>
49 70 </div>
50   - <div id="finish-task-container" class="row">
51   - <div id="finish-button" class="finish-task-button enabled-button">
52   - <span id="finish-button-text">SIM</span><img class="icon"
53   - src="{{ server }}/img/finish.svg"></img>
  71 + <div id="ref-radio-answers" class="row radio-options">
  72 + <div class="correct-answer-container"">
  73 + <span class="correct-answer-label">ESTÁ CORRETO</span><img
  74 + class="icon" src="{{ server }}/img/correct.png"></img><input
  75 + value="CORRECT" type="radio" name="ref-answers">
54 76 </div>
55   - <div id="no-button" class="finish-task-button enabled-button"
56   - data-toggle="modal" data-target="#feedback-modal">
57   - NÃO<img class="icon" src="{{ server }}/img/no.png"></img>
  77 + <div>
  78 + <span class="incorrect-answer-label">ESTÁ ERRADO</span><img
  79 + class="icon" src="{{ server }}/img/incorrect.png"></img><input
  80 + id="incorrect-ref-button" value="INCORRECT" type="radio"
  81 + name="ref-answers">
  82 + </div>
  83 + </div>
  84 + <div id="comment-ref" class="form-group">
  85 + <h6>ENVIAR COMENTÁRIO SOBRE O VÍDEO DE REFERÊNCIA:</h6>
  86 + <textarea class="form-control" rows="2"></textarea>
  87 + </div>
  88 + <div id="finish-task-container" class="row finish-padding-top">
  89 + <div id="finish-button" class="finish-task-button enabled-button">
  90 + <span id="finish-button-text">ENVIAR ANÁLISE E FINALIZAR</span><img
  91 + class="icon" src="{{ server }}/img/finish.svg"></img>
58 92 </div>
59 93 <div id="skip-button" class="finish-task-button enabled-button">
60 94 PULAR<img class="icon" src="{{ server }}/img/skip.svg"></img>
61 95 </div>
62 96 </div>
63 97 </div>
64   - <div id="feedback-modal" class="modal fade" tabindex="-1"
65   - role="dialog" aria-labelledby="myModalLabel">
66   - <div class="modal-dialog" role="document">
67   - <div class="modal-content">
68   - <div class="modal-header">
69   - <button type="button" class="close" data-dismiss="modal"
70   - aria-label="FECHAR">
71   - <span aria-hidden="true">&times;</span>
72   - </button>
73   - <h5 class="modal-title" id="myModalLabel">Feedback da
74   - avaliação</h5>
75   - </div>
76   - <div class="modal-body">
77   - <h6 style="margin-top: 0px;">O que precisa ser melhorado?</h6>
78   - <div class="radio">
79   - <input type="radio" name="optradio"> A animação do
80   - avatar.
81   - </div>
82   - <div class="radio">
83   - <input type="radio" name="optradio">O vídeo de
84   - referência.
85   - </div>
86   - </div>
87   - <div class="modal-footer">
88   - <button type="button" class="btn btn-default" data-dismiss="modal">FECHAR</button>
89   - <button id="no-finish-button" type="button"
90   - class="btn btn-default disabled" data-dismiss="modal">FINALIZAR</button>
91   - </div>
92   - </div>
93   - </div>
94   - </div>
95 98 </div>
96 99 </div>
97 100  
98 101 <script type="text/javascript">
99   - var base_url = "{{ server }}/videos/";
100   - var current_task_id = -1;
101   -
102   - function setupButtons(task, deferred) {
103   - $("#finish-button").off("click").on("click", function() {
104   - console.log($(this).text().trim() == "SIM");
105   - saveAnswer(task, deferred, "APPROVED");
106   - });
107   - $("#skip-button").off("click").on("click", function() {
108   - saveAnswer(task, deferred, "SKIPPED");
109   - });
110   - $("#no-finish-button").off("click").on("click", function() {
111   - saveAnswer(task, deferred, "DISAPPROVED");
112   - });
113   - $("#no-finish-button").addClass("disabled");
114   - $("#feedback-modal input[name='optradio']").prop("checked", false);
115   - $("#feedback-modal input[name='optradio']").off("click").on("click",
116   - function() {
117   - $("#no-finish-button").removeClass("disabled");
118   - });
119   - }
120   -
121   - function createAnswer(task, status) {
122   - var answer = {
123   - "status" : status,
124   - "number_of_approval" : 0
125   - };
126   - var last_answer = task.info.last_answer;
127   - var hasLastAnswer = typeof last_answer != "undefined";
128   - if (hasLastAnswer) {
129   - answer = last_answer;
130   - }
131   - if (status == "APPROVED") {
132   - answer["number_of_approval"] = answer.number_of_approval + 1;
133   - }
134   - return answer;
135   - }
136   -
137   - function saveAnswer(task, deferred, status) {
138   - var answer = createAnswer(task, status);
139   - pybossa.saveTask(task.id, answer).done(function() {
140   - $("#success").fadeIn(500);
141   - $("#main-container").hide();
142   - setTimeout(function() {
143   - deferred.resolve();
144   - }, 2000);
145   - });
146   - }
147   -
148   - function loadTaskInfo(task) {
149   - current_task_id = task.id;
150   - var sign_name = task.info.sign_name;
151   - var avatar_vid_link = base_url + sign_name + "_AVATAR.webm";
152   - var ref_vid_link = base_url + sign_name + "_REF.webm";
153   - $(".sign-label").text(sign_name);
154   - $("#avatar-video").attr("src", avatar_vid_link);
155   - $("#ref-video").attr("src", ref_vid_link);
156   - }
157   -
158   - pybossa.presentTask(function(task, deferred) {
159   - if (!$.isEmptyObject(task) && current_task_id != task.id) {
160   - loadTaskInfo(task);
161   - setupButtons(task, deferred);
162   - $("#success").hide();
163   - $("#main-container").fadeIn(500);
164   - } else {
165   - $("#main-container").hide();
166   - $("#finish").fadeIn(500);
167   - }
168   - });
169   -
170   - pybossa.run('{{ app_shortname }}');
  102 + validador.run("{{ server }}", "{{ app_shortname }}");
171 103 </script>
... ...