Commit 944b7e71dbbdae45d9813257d0e8b7252fe1d432

Authored by ailsoncgt
2 parents c37e0128 ce6e6ebe

Merge

README.md
... ... @@ -80,14 +80,31 @@ Para Classes que envolvem formulários:
80 80 * `CreateCourseForm`
81 81 * `UpdateCourseForm()`
82 82  
  83 +[PT-BR]
  84 +##API Descrição
  85 +Estamos usando em sua maioria viewsets ( http://www.django-rest-framework.org/api-guide/viewsets/) para construir os endpoints da nossa API. Ela tem como função compartilhar os dados da instância do Amadeus com aplicações credenciadas.
  86 +
  87 +##API Setup
  88 +**Criar aplicação**
  89 +* Vá para "/o/applications/" e clique "new application". Um formulário irá aparecer para preencher.
  90 +* No formulário, preencha somente o "Name" com o nome da aplicação, os campos "client id" e "client secret" são gerados automaticamente e não devem ser modificados.
  91 +"Client type" deve ser confidential, e "Authorization Grant Type" como " Resource owner password-based".
  92 +
  93 +**Obtendo um access Token**
  94 +
  95 +* Crie um request, usando um usuário valido, usando o seguinte abaixo (lembre-se que isso é  um POST, estou usando um comando curl para fins de teste):
  96 +curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://amadeus/o/token/
83 97  
84   -##API Description
85   -We are using mostly viewsets ( http://www.django-rest-framework.org/api-guide/viewsets/) to build our API endpoints now, so all default methods and API points were kept.
  98 +* finalmente, com o seu access token, você pode testar um dos endpoints usando o template abaixo:
  99 +curl -H "Authorization: Bearer <your_access_token>" -X POST -d"username=foo&password=bar" http://localhost:8000/users/ (inserting a new user)
  100 +
86 101  
87 102 * model list(GET) = list all objects from that mode in pagination mode, each page has 10
88 103 * model detail(GET) = give the details of the objects and most important fields of the ones objects its has relationships.
89 104 * model create
90 105  
  106 +**API Endpoints **
  107 +
91 108 **Courses (URL: coursesapi)**
92 109 * course list ("/coursesapi/")
93 110 * course detail ("/coursesapi/id") (id is a parameter)
... ... @@ -104,14 +121,7 @@ We are using mostly viewsets ( http://www.django-rest-framework.org/api-guide/vi
104 121 * logs list ("/logs/")
105 122 * log detail ("/logs/id") (id is a parameter)
106 123  
107   -#Obtaining an Access Token
108   -* First build an application o "amadeus/o/applications" following this tutorial: http://django-oauth-toolkit.readthedocs.io/en/latest/tutorial/tutorial_01.html#create-an-oauth2-client-application
109 124  
110   -* Then request, using a valid user, an access token using the following template (you'll have to know how to translate a GET Method into a POST one)
111   -curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://amadeus/o/token/
112   -
113   -* finally, with your access token you can use test using
114   -curl -H "Authorization: Bearer <your_access_token>" -X POST -d"username=foo&password=bar" http://localhost:8000/users/ (inserting a new user)
115 125  
116 126  
117 127 ## Link's úteis
... ...
app/locale/pt_BR/LC_MESSAGES/django.po
... ... @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 8 msgstr ""
9 9 "Project-Id-Version: PACKAGE VERSION\n"
10 10 "Report-Msgid-Bugs-To: \n"
11   -"POT-Creation-Date: 2016-11-23 23:14-0300\n"
  11 +"POT-Creation-Date: 2016-11-26 12:36-0300\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
... ... @@ -212,10 +212,18 @@ msgstr &quot;em&quot;
212 212 msgid "ago"
213 213 msgstr "atrás"
214 214  
  215 +#: .\views.py:38
  216 +msgid "Home | Amadeus"
  217 +msgstr "Página inicial | Amadeus"
  218 +
215 219 #: .\views.py:75
216 220 msgid "Changes saved."
217 221 msgstr "Mudanças salvas"
218 222  
  223 +#: .\views.py:82
  224 +msgid "Settings | Amadeus"
  225 +msgstr "Configurações | Amadeus"
  226 +
219 227 #, fuzzy
220 228 #~| msgid "Students:"
221 229 #~ msgid "Students"
... ...
app/views.py
... ... @@ -14,7 +14,7 @@ from .forms import EmailBackendForm
14 14 from courses.models import Course
15 15  
16 16 class AppIndex(LoginRequiredMixin, ListView, NotificationMixin):
17   - login_url = reverse_lazy("core:home")
  17 + login_url = reverse_lazy("core:home")
18 18 redirect_field_name = 'next'
19 19  
20 20 template_name = "home.html"
... ... @@ -34,15 +34,15 @@ class AppIndex(LoginRequiredMixin, ListView, NotificationMixin):
34 34 context['page_template'] = "home_admin_content.html"
35 35 else:
36 36 context['page_template'] = "home_teacher_student_content.html"
37   -
38   - context['title'] = 'Amadeus'
  37 +
  38 + context['title'] = _('Home | Amadeus')
39 39  
40 40 if self.request.is_ajax():
41 41 if self.request.user.is_staff:
42 42 self.template_name = "home_admin_content.html"
43 43 else:
44 44 self.template_name = "home_teacher_student_content.html"
45   -
  45 +
46 46 return self.response_class(request = self.request, template = self.template_name, context = context, using = self.template_engine, **response_kwargs)
47 47  
48 48 class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView):
... ... @@ -79,6 +79,7 @@ class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView):
79 79 def get_context_data(self, **kwargs):
80 80 context = super(AmadeusSettings, self).get_context_data(**kwargs)
81 81 context['page'] = self.kwargs.get('page')
  82 + context['title'] = _('Settings | Amadeus')
82 83 if not self.request.method == 'POST':
83 84 try:
84 85 setting = EmailBackend.objects.latest('id')
... ... @@ -86,6 +87,3 @@ class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView):
86 87 except:
87 88 pass
88 89 return context
89   -
90   -
91   -
... ...
core/decorators.py
1 1 from django.conf import settings
2 2 import json
  3 +import time
3 4 from functools import wraps
  5 +from django.shortcuts import get_object_or_404
4 6 from .models import Action, Resource, Action_Resource, Log, Notification
5 7  
6 8 def log_decorator(log_component = '', log_action = '', log_resource = ''):
... ... @@ -38,7 +40,6 @@ def log_decorator(log_component = &#39;&#39;, log_action = &#39;&#39;, log_resource = &#39;&#39;):
38 40 log = Log()
39 41 log.user = request.user
40 42 log.component = log_component
41   - #log.context = json.dumps(request.log_context)
42 43 log.context = request.log_context
43 44 log.action_resource = action_resource
44 45  
... ... @@ -51,6 +52,75 @@ def log_decorator(log_component = &#39;&#39;, log_action = &#39;&#39;, log_resource = &#39;&#39;):
51 52 return _log_decorator
52 53  
53 54  
  55 +def log_decorator_ajax(log_component = '', log_action = '', log_resource = ''):
  56 +
  57 + def _log_decorator_ajax(view_function):
  58 +
  59 + def _decorator(request, *args, **kwargs):
  60 + view_action = request.GET.get("action")
  61 +
  62 + if view_action == 'open':
  63 + if request.user.is_authenticated:
  64 + action = Action.objects.filter(name = log_action)
  65 + resource = Resource.objects.filter(name = log_resource)
  66 +
  67 + if not action:
  68 + action = Action(name = log_action)
  69 + action.save()
  70 + else:
  71 + action = action[0]
  72 +
  73 + if not resource:
  74 + resource = Resource(name = log_resource)
  75 + resource.save()
  76 + else:
  77 + resource = resource[0]
  78 +
  79 + action_resource = Action_Resource.objects.filter(action = action, resource = resource)
  80 +
  81 + if not action_resource:
  82 + action_resource = Action_Resource(action = action, resource = resource)
  83 + action_resource.save()
  84 + else:
  85 + action_resource = action_resource[0]
  86 +
  87 + log = Log()
  88 + log.user = request.user
  89 + log.component = log_component
  90 + log.context = ""
  91 + log.action_resource = action_resource
  92 +
  93 + log.save()
  94 +
  95 + response = view_function(request, *args, **kwargs)
  96 +
  97 + log = Log.objects.latest('id')
  98 + log.context = request.log_context
  99 + log.save()
  100 + elif view_action == 'close':
  101 + if request.user.is_authenticated:
  102 + log = get_object_or_404(Log, id = request.GET.get('log_id'))
  103 +
  104 + if type(log.context) == dict:
  105 + log_context = log.context
  106 + else:
  107 + log_context = json.loads(log.context)
  108 +
  109 + log_context['timestamp_end'] = str(int(time.time()))
  110 +
  111 + log.context = log_context
  112 +
  113 + log.save()
  114 +
  115 + response = view_function(request, *args, **kwargs)
  116 +
  117 + return response
  118 +
  119 + return wraps(view_function)(_decorator)
  120 +
  121 + return _log_decorator_ajax
  122 +
  123 +
54 124 def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource='', resource_link=''):
55 125  
56 126 def _notification_decorator(view_function):
... ...
core/locale/pt_BR/LC_MESSAGES/django.po
... ... @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 8 msgstr ""
9 9 "Project-Id-Version: PACKAGE VERSION\n"
10 10 "Report-Msgid-Bugs-To: \n"
11   -"POT-Creation-Date: 2016-11-23 23:16-0300\n"
  11 +"POT-Creation-Date: 2016-11-26 12:44-0300\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
... ...
core/middleware.py
... ... @@ -32,3 +32,17 @@ class TimeSpentMiddleware(object):
32 32 log.save()
33 33  
34 34 request.session['log_id'] = None
  35 +
  36 + oppened_logs = Log.objects.filter(user = request.user, context__contains={'timestamp_end': '-1'})
  37 +
  38 + for op_log in oppened_logs:
  39 + if type(op_log.context) == dict:
  40 + log_context = op_log.context
  41 + else:
  42 + log_context = json.loads(op_log.context)
  43 +
  44 + log_context['timestamp_end'] = str(int(time.time()))
  45 +
  46 + op_log.context = log_context
  47 +
  48 + op_log.save()
... ...
courses/locale/pt_BR/LC_MESSAGES/django.po
... ... @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 8 msgstr ""
9 9 "Project-Id-Version: PACKAGE VERSION\n"
10 10 "Report-Msgid-Bugs-To: \n"
11   -"POT-Creation-Date: 2016-11-23 23:19-0300\n"
  11 +"POT-Creation-Date: 2016-11-26 12:45-0300\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
... ... @@ -20,7 +20,7 @@ msgstr &quot;&quot;
20 20  
21 21 #: .\forms.py:13 .\forms.py:25 .\forms.py:47 .\forms.py:68 .\forms.py:91
22 22 #: .\models.py:14 .\models.py:26 .\models.py:39 .\models.py:68 .\models.py:96
23   -#: .\models.py:157 .\templates\subject\form_view_teacher.html:182
  23 +#: .\models.py:157 .\templates\subject\form_view_teacher.html:185
24 24 #: .\templates\subject\replicate.html:18 .\templates\topic\replicate.html:18
25 25 msgid "Name"
26 26 msgstr "Nome"
... ... @@ -55,7 +55,7 @@ msgid &quot;To define if the course can be accessed by people not registered&quot;
55 55 msgstr "Para definir se o curso pode ser acessado por pessoas não registradas"
56 56  
57 57 #: .\forms.py:69 .\forms.py:92 .\models.py:70 .\models.py:98 .\models.py:159
58   -#: .\templates\subject\form_view_teacher.html:53
  58 +#: .\templates\subject\form_view_teacher.html:56
59 59 #: .\templates\subject\index.html:53 .\templates\subject\replicate.html:25
60 60 #: .\templates\topic\replicate.html:24
61 61 msgid "Description"
... ... @@ -173,7 +173,7 @@ msgstr &quot;Todos estudantes&quot;
173 173  
174 174 #: .\models.py:143 .\models.py:148
175 175 #: .\templates\subject\form_view_student.html:42
176   -#: .\templates\subject\form_view_teacher.html:61
  176 +#: .\templates\subject\form_view_teacher.html:64
177 177 msgid "Material"
178 178 msgstr "Material"
179 179  
... ... @@ -228,7 +228,7 @@ msgstr &quot;Remover&quot;
228 228  
229 229 #: .\templates\course\course_card.html:18 .\templates\course\view.html:39
230 230 #: .\templates\course\view.html:90
231   -#: .\templates\subject\form_view_teacher.html:24
  231 +#: .\templates\subject\form_view_teacher.html:26
232 232 #: .\templates\subject\index.html:37 .\templates\subject\replicate.html:52
233 233 #: .\templates\topic\index.html:36
234 234 msgid "Replicate"
... ... @@ -236,14 +236,14 @@ msgstr &quot;Repetir&quot;
236 236  
237 237 #: .\templates\course\course_card.html:19 .\templates\course\view.html:40
238 238 #: .\templates\course\view.html:91
239   -#: .\templates\subject\form_view_teacher.html:25
  239 +#: .\templates\subject\form_view_teacher.html:27
240 240 #: .\templates\subject\index.html:38 .\templates\topic\index.html:39
241 241 msgid "Edit"
242 242 msgstr "Editar"
243 243  
244 244 #: .\templates\course\course_card.html:20 .\templates\course\view.html:41
245 245 #: .\templates\course\view.html:92
246   -#: .\templates\subject\form_view_teacher.html:26
  246 +#: .\templates\subject\form_view_teacher.html:28
247 247 #: .\templates\subject\index.html:39 .\templates\topic\index.html:42
248 248 msgid "Remove"
249 249 msgstr "Remover"
... ... @@ -276,7 +276,7 @@ msgstr &quot;Apagar curso&quot;
276 276 msgid "Are you sure you want to delete the course"
277 277 msgstr "Você tem certeza que deseja deletar o curso"
278 278  
279   -#: .\templates\course\filtered.html:11 .\views.py:176
  279 +#: .\templates\course\filtered.html:11
280 280 msgid "Create Course"
281 281 msgstr "Criar curso"
282 282  
... ... @@ -284,6 +284,10 @@ msgstr &quot;Criar curso&quot;
284 284 msgid "Categories:"
285 285 msgstr "Categorias:"
286 286  
  287 +#: .\templates\course\index.html:29
  288 +msgid "Search for Courses"
  289 +msgstr "Pesquisar por cursos"
  290 +
287 291 #: .\templates\course\view.html:41
288 292 msgid "Are you sure you want to delete this course?"
289 293 msgstr "Você tem certeza que deseja deletar este curso?"
... ... @@ -301,8 +305,8 @@ msgid &quot;Cancel&quot;
301 305 msgstr "Cancelar"
302 306  
303 307 #: .\templates\course\view.html:65
304   -#: .\templates\subject\form_view_teacher.html:164
305   -#: .\templates\subject\form_view_teacher.html:216
  308 +#: .\templates\subject\form_view_teacher.html:167
  309 +#: .\templates\subject\form_view_teacher.html:219
306 310 msgid "Confirm"
307 311 msgstr "Confirmar"
308 312  
... ... @@ -324,64 +328,64 @@ msgid &quot;exam&quot;
324 328 msgstr "Avaliação"
325 329  
326 330 #: .\templates\subject\form_view_student.html:55
327   -#: .\templates\subject\form_view_teacher.html:95
  331 +#: .\templates\subject\form_view_teacher.html:98
328 332 #: .\templates\topic\topic_card.html:18
329 333 msgid "Activities"
330 334 msgstr "Atividades"
331 335  
332   -#: .\templates\subject\form_view_teacher.html:49
  336 +#: .\templates\subject\form_view_teacher.html:52
333 337 msgid "Name Topic"
334 338 msgstr "Nome do tópico"
335 339  
336   -#: .\templates\subject\form_view_teacher.html:69
  340 +#: .\templates\subject\form_view_teacher.html:72
337 341 msgid "Create a Link"
338 342 msgstr "Criar link"
339 343  
340   -#: .\templates\subject\form_view_teacher.html:70
  344 +#: .\templates\subject\form_view_teacher.html:73
341 345 msgid "Create a file"
342 346 msgstr "Criar um arquivo"
343 347  
344   -#: .\templates\subject\form_view_teacher.html:103
  348 +#: .\templates\subject\form_view_teacher.html:106
345 349 msgid "Create Forum"
346 350 msgstr "Criar Forum"
347 351  
348   -#: .\templates\subject\form_view_teacher.html:104
  352 +#: .\templates\subject\form_view_teacher.html:107
349 353 msgid "Create Poll"
350 354 msgstr "Criar enquete"
351 355  
352   -#: .\templates\subject\form_view_teacher.html:105
  356 +#: .\templates\subject\form_view_teacher.html:108
353 357 msgid "Delivery Material"
354 358 msgstr "Entregar Material"
355 359  
356   -#: .\templates\subject\form_view_teacher.html:106
  360 +#: .\templates\subject\form_view_teacher.html:109
357 361 msgid "Create exam"
358 362 msgstr "Criar avaliação"
359 363  
360   -#: .\templates\subject\form_view_teacher.html:140
  364 +#: .\templates\subject\form_view_teacher.html:143
361 365 msgid "Back"
362 366 msgstr "Voltar"
363 367  
364   -#: .\templates\subject\form_view_teacher.html:160
  368 +#: .\templates\subject\form_view_teacher.html:163
365 369 msgid "Delete your Topic?"
366 370 msgstr "Deletar seu Tópico?"
367 371  
368   -#: .\templates\subject\form_view_teacher.html:178
  372 +#: .\templates\subject\form_view_teacher.html:181
369 373 msgid "Material EMBED"
370 374 msgstr "Incorporar Material"
371 375  
372   -#: .\templates\subject\form_view_teacher.html:189
  376 +#: .\templates\subject\form_view_teacher.html:192
373 377 msgid "Code"
374 378 msgstr "Código"
375 379  
376   -#: .\templates\subject\form_view_teacher.html:193
  380 +#: .\templates\subject\form_view_teacher.html:196
377 381 msgid "Material description"
378 382 msgstr "Descrição do material"
379 383  
380   -#: .\templates\subject\form_view_teacher.html:197
  384 +#: .\templates\subject\form_view_teacher.html:200
381 385 msgid "Height"
382 386 msgstr "Tamanho"
383 387  
384   -#: .\templates\subject\form_view_teacher.html:203
  388 +#: .\templates\subject\form_view_teacher.html:206
385 389 msgid "Weight"
386 390 msgstr "Peso"
387 391  
... ... @@ -445,45 +449,75 @@ msgstr &quot;Descrição do Tópico&quot;
445 449 msgid "Materials"
446 450 msgstr "Materiais"
447 451  
448   -#: .\views.py:218
449   -msgid "Replicate Course"
450   -msgstr "Replicar curso"
  452 +#: .\views.py:102
  453 +msgid "Courses | Amadeus"
  454 +msgstr "Cursos | Amadeus"
451 455  
452   -#: .\views.py:400
  456 +#: .\views.py:140
  457 +msgid "All Courses | Amadeus"
  458 +msgstr "Todos Cursos | Amadeus"
  459 +
  460 +#: .\views.py:178
  461 +msgid "Create Course | Amadeus"
  462 +msgstr "Criar curso | Amadeus"
  463 +
  464 +#: .\views.py:220
  465 +msgid "Replicate Course | Amadeus"
  466 +msgstr "Replicar curso | Amadeus"
  467 +
  468 +#: .\views.py:402
453 469 msgid "Course deleted successfully!"
454 470 msgstr "Curso deletado com sucesso!"
455 471  
456   -#: .\views.py:423
  472 +#: .\views.py:425
457 473 msgid "Successfully subscribed to the course!"
458 474 msgstr "Inscrição no curso realizada com sucesso!"
459 475  
460   -#: .\views.py:425
  476 +#: .\views.py:427
461 477 msgid ""
462 478 "An error has occured. Could not subscribe to this course, try again later"
463 479 msgstr "Ocorreu um erro. Não pôde inscrever no curso, tente novamente"
464 480  
465   -#: .\views.py:467
  481 +#: .\views.py:460
  482 +msgid "Categories | Amadeus"
  483 +msgstr "Categorias | Amadeus"
  484 +
  485 +#: .\views.py:474
  486 +#, python-format
466 487 msgid "Category \"%s\" created successfully!"
467 488 msgstr "Categoria \"%s\" criada com sucesso!"
468 489  
469   -#: .\views.py:482
  490 +#: .\views.py:479
  491 +msgid "Create Category | Amadeus"
  492 +msgstr "Criar Categoria | Amadeus"
  493 +
  494 +#: .\views.py:495
  495 +#, python-format
470 496 msgid "Category \"%s\" updated successfully!"
471 497 msgstr "Categoria \"%s\" editada com sucesso!"
472 498  
473   -#: .\views.py:507
  499 +#: .\views.py:521
474 500 msgid "Category deleted successfully!"
475 501 msgstr "Categoria deletada com sucesso!"
476 502  
477   -#: .\views.py:917
  503 +#: .\views.py:688
  504 +msgid "Create Topic | Amadeus"
  505 +msgstr "Criar Tópico | Amadeus"
  506 +
  507 +#: .\views.py:794
  508 +msgid "Create Subject | Amadeus"
  509 +msgstr "Criar Assunto | Amadeus"
  510 +
  511 +#: .\views.py:936
478 512 msgid "Successfully subscribed to the subject!"
479 513 msgstr "Inscrição no assunto realizada com sucesso!"
480 514  
481   -#: .\views.py:919
  515 +#: .\views.py:938
482 516 msgid ""
483 517 "An error has occured. Could not subscribe to this subject, try again later"
484 518 msgstr "Ocorreu um erro. Não pôde inscrever no assunto, tente novamente"
485 519  
486   -#: .\views.py:921
  520 +#: .\views.py:940
487 521 msgid "You're not subscribed in the course yet."
488 522 msgstr "Você não está inscrito no curso ainda."
489 523  
... ... @@ -517,16 +551,12 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
517 551 #~ msgid "Image"
518 552 #~ msgstr "Imagem"
519 553  
520   -
521 554 #~ msgid "CourseCategory"
522 555 #~ msgstr "Categoria do Curso"
523 556  
524 557 #~ msgid "Course objective"
525 558 #~ msgstr "Objetivo do Curso"
526 559  
527   -#~ msgid "Course modules"
528   -#~ msgstr "Módulos do curso"
529   -
530 560 #~ msgid "Max number of students that a class can have"
531 561 #~ msgstr "Número máximo de estudantes que uma classe pode ter"
532 562  
... ... @@ -545,17 +575,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
545 575 #~ msgid "Representative image of the course"
546 576 #~ msgstr "Imagem representativa do curso"
547 577  
548   -
549 578 #~| msgid "Category which the course belongs"
550 579 #~ msgid "CourseCategory which the course belongs"
551 580 #~ msgstr "Categoria de Curso ao qual o curso pertence"
552 581  
553   -
554 582 #~| msgid "Maximum Students"
555 583 #~ msgid "Student"
556 584 #~ msgstr "Quantidade máxima de estudantes"
557 585  
558   -
559 586 #~| msgid "Course modules"
560 587 #~ msgid "Course's Students"
561 588 #~ msgstr "Estudantes do curso"
... ... @@ -587,7 +614,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
587 614 #~ msgid "Profile"
588 615 #~ msgstr "Perfil"
589 616  
590   -
591 617 #~| msgid "Courses"
592 618 #~ msgid "My Courses"
593 619 #~ msgstr "Meus Cursos"
... ... @@ -595,7 +621,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
595 621 #~ msgid "Actions"
596 622 #~ msgstr "Ações"
597 623  
598   -
599 624 #~| msgid "Edit Category"
600 625 #~ msgid "List Category"
601 626 #~ msgstr "Listar Categorias"
... ... @@ -606,7 +631,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
606 631 #~ msgid "Edit Category"
607 632 #~ msgstr "Editar categoria"
608 633  
609   -
610 634 #~| msgid "Course name"
611 635 #~ msgid "Course Name"
612 636 #~ msgstr "Nome do Curso"
... ... @@ -617,22 +641,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
617 641 #~ msgid "No"
618 642 #~ msgstr "Não"
619 643  
620   -
621 644 #~| msgid "Course"
622 645 #~ msgid "Home Course"
623 646 #~ msgstr "Pagina Inicial do Curso"
624 647  
625   -
626 648 #~| msgid "Courses"
627 649 #~ msgid "My courses"
628 650 #~ msgstr "Meus Cursos"
629 651  
630   -
631   -#~| msgid "Courses"
632   -#~ msgid "All Courses"
633   -#~ msgstr "Todos Cursos"
634   -
635   -
636 652 #~| msgid "Manage Courses"
637 653 #~ msgid "Manage Users"
638 654 #~ msgstr "Gerenciar Usuários"
... ... @@ -643,12 +659,10 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
643 659 #~ msgid "No courses found"
644 660 #~ msgstr "Nenhum curso encontrado"
645 661  
646   -
647 662 #~| msgid "Image"
648 663 #~ msgid "Imagem"
649 664 #~ msgstr "Imagem"
650 665  
651   -
652 666 #~| msgid "Are you sure you want to delete the couse"
653 667 #~ msgid "Are you sure you want to remove this subject?"
654 668 #~ msgstr "Você tem certeza que deseja deletar este assunto?"
... ... @@ -665,7 +679,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
665 679 #~ msgid "Proposal Activity"
666 680 #~ msgstr "Atividade proposta"
667 681  
668   -
669 682 #~| msgid "Description"
670 683 #~ msgid "Describe"
671 684 #~ msgstr "Descreva"
... ... @@ -679,7 +692,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
679 692 #~ msgid "Send Later"
680 693 #~ msgstr "Enviar depois"
681 694  
682   -
683 695 #~| msgid "Manage Courses"
684 696 #~ msgid "Manage Subjects"
685 697 #~ msgstr "Gerenciar cursos"
... ... @@ -687,7 +699,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
687 699 #~ msgid "poll"
688 700 #~ msgstr "Enquete"
689 701  
690   -
691 702 #~| msgid "Create Category"
692 703 #~ msgid "Create Subject Category"
693 704 #~ msgstr "Criar Categoria de Assunto"
... ... @@ -695,17 +706,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
695 706 #~ msgid "Participants"
696 707 #~ msgstr "Participantes"
697 708  
698   -
699 709 #~| msgid "Duplicate Course"
700 710 #~ msgid "Replicate subject"
701 711 #~ msgstr "Replicar assunto"
702 712  
703   -
704 713 #~| msgid "Create Course"
705 714 #~ msgid "Create subject"
706 715 #~ msgstr "Criar assunto"
707 716  
708   -
709 717 #~| msgid "Edit Course"
710 718 #~ msgid "Edit subject"
711 719 #~ msgstr "Editar assunto"
... ... @@ -719,7 +727,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
719 727 #~ msgid "Send"
720 728 #~ msgstr "Enviar"
721 729  
722   -
723 730 #~| msgid "No categories found"
724 731 #~ msgid "No activity found"
725 732 #~ msgstr "Nenhuma atividade encontrada"
... ...
courses/static/js/course.js
... ... @@ -49,7 +49,7 @@ function subscribe(elem, url, id, confirm_message) {
49 49  
50 50 /*
51 51 *
52   -* Function to delete a course
  52 +* Function to delete a course
53 53 *
54 54 */
55 55  
... ... @@ -62,7 +62,7 @@ var RemoveCourse = {
62 62 $("#accordion").remove();
63 63 $(".modal-backdrop.in").remove();
64 64 alertify.success("Course removed successfully!");
65   - setTimeout(function () { location.reload(1); }, 2000);
  65 + setTimeout(function () { location.reload(1); }, 1);
66 66 }).fail(function(){
67 67 $("#modal_course").empty();
68 68 $("#modal_course").append(data);
... ... @@ -84,7 +84,7 @@ var delete_course = {
84 84 });
85 85 }
86 86 };
87   -/*
  87 +/*
88 88 *
89 89 * Function to load create course's form
90 90 *
... ... @@ -97,4 +97,4 @@ function replicate_course(url, course) {
97 97 $(".course_replicate_form").html(data);
98 98 }
99 99 });
100   -}
101 100 \ No newline at end of file
  101 +}
... ...
courses/static/js/topic.js 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +function openTopic(url, topic, btn) {
  2 + var icon = btn.find('i');
  3 + var action = '', log_id;
  4 +
  5 + if (icon.hasClass('fa-caret-square-o-down')) {
  6 + icon.removeClass('fa-caret-square-o-down');
  7 + icon.addClass('fa-caret-square-o-up');
  8 + action = 'open';
  9 + log_id = -1;
  10 + } else {
  11 + icon.addClass('fa-caret-square-o-down');
  12 + icon.removeClass('fa-caret-square-o-up');
  13 + action = 'close';
  14 + log_id = $(".topic_" + topic).find(".log_id").val();
  15 + }
  16 +
  17 + $.ajax({
  18 + url: url,
  19 + data: {"action": action, "log_id": log_id},
  20 + dataType: 'json',
  21 + success: function (data) {
  22 + if (action == 'open') {
  23 + $(".topic_" + topic).find(".log_id").val(data.log_id);
  24 + }
  25 + },
  26 + error: function(data) {
  27 + console.log('Error');
  28 + }
  29 + });
  30 +}
0 31 \ No newline at end of file
... ...
courses/templates/course/index.html
... ... @@ -26,7 +26,7 @@
26 26 <form id="searchform" method="get" accept-charset="utf-8">
27 27 <div class="input-group">
28 28 <div class="form-group is-empty">
29   - <input type="text" class="form-control" placeholder="Search Courses" name="q"></div>
  29 + <input type="text" class="form-control" placeholder="{% trans 'Search for Courses' %}" name="q"></div>
30 30 <span class="input-group-btn input-group-sm">
31 31 <button type="submit" class="btn btn-fab btn-fab-mini">
32 32 <i class="fa fa-search" aria-hidden="true"></i>
... ...
courses/templates/subject/form_view_student.html
... ... @@ -6,6 +6,7 @@
6 6 <script src="{% static 'js/file.js' %}"></script>
7 7 <script type="text/javascript" src="{% static 'js/material.js' %}"></script>
8 8 <script type = "text/javascript" src="{% static 'links.js' %}"></script>
  9 + <script type="text/javascript" src="{% static 'js/topic.js' %}"></script>
9 10 {% endblock %}
10 11 <div class="cards-detail">
11 12 <div class="panel-group accordion ui-accordion ui-widget ui-helper-reset ui-sortable" role="tablist" aria-multiselectable="false">
... ... @@ -13,7 +14,7 @@
13 14 <div class="panel-heading topic ui-sortable-handle" role="tab">
14 15 <div class="row">
15 16 <div class="col-md-1 moreAccordion" data-toggle="collapse" data-parent="#accordion-{{topic.slug}}" href=".collapseTopic-{{topic.slug}}" aria-expanded="false" aria-controls="collapseTopic-{{topic.slug}}">
16   - <button class="btn btn-default btn-sm caret-square"><i class="fa fa-caret-square-o-down fa-2x" aria-hidden="true"></i></button>
  17 + <button class="btn btn-default btn-sm caret-square" onclick="openTopic('{% url 'course:topic_log' topic.id %}', '{{topic.id}}', $(this));"><i class="fa fa-caret-square-o-down fa-2x" aria-hidden="true"></i></button>
17 18 </div>
18 19 <div class="col-xs-9 col-md-9 titleTopic">
19 20 <a href="{% url 'course:view_topic' topic.slug %}" role="button">
... ... @@ -22,7 +23,7 @@
22 23 </div>
23 24 </div>
24 25 </div>
25   - <div class="panel-collapse collapseTopic-{{topic.slug}} collapse in" role="tabpanel" aria-labelledby="heading_{{topic.id}}" aria-expanded="true" aria-hidden="false">
  26 + <div class="panel-collapse collapseTopic-{{topic.slug}} collapse" role="tabpanel" aria-labelledby="heading_{{topic.id}}" aria-expanded="false" aria-hidden="true">
26 27 <div class="panel-body">
27 28 <div class="presentation">
28 29 <p>
... ... @@ -32,8 +33,7 @@
32 33 </p>
33 34  
34 35 </div>
35   - </div>
36   - </div>
  36 +
37 37  
38 38 {% if not professor_links %}
39 39 <div class="row">
... ... @@ -82,4 +82,6 @@
82 82 {% include "links/update_link.html" %}
83 83 {% endif %}
84 84 </div>
  85 + </div>
  86 + </div>
85 87 </div>
86 88 \ No newline at end of file
... ...
courses/templates/subject/form_view_teacher.html
1 1 {% load static i18n list_topic_foruns permission_tags widget_tweaks professor_access list_topic_exercises %}
2 2  
  3 +<script type="text/javascript" src="{% static 'js/topic.js' %}"></script>
  4 +
3 5 <div class="panel panel-default cards-detail">
4 6 <div class="panel-heading topic">
5 7 <div class="row">
6 8 <div class="col-md-1 moreAccordion" data-toggle="collapse" data-parent="#accordion-{{topic.slug}}" href=".collapseTopic-{{topic.slug}}" aria-expanded="false" aria-controls="collapseTopic-{{topic.slug}}">
7   - <button class="btn btn-default btn-sm caret-square"><i class="fa fa-caret-square-o-down fa-2x" aria-hidden="true"></i></button>
  9 + <button class="btn btn-default btn-sm caret-square" onclick="openTopic('{% url 'course:topic_log' topic.id %}', '{{topic.id}}', $(this));"><i class="fa fa-caret-square-o-down fa-2x" aria-hidden="true"></i></button>
8 10 </div>
9 11 <div class="col-xs-9 col-md-9 titleTopic">
10 12 <a href="{% url 'course:view_topic' topic.slug %}" role="button">
... ... @@ -32,7 +34,8 @@
32 34 </div>
33 35 </div>
34 36 </div>
35   - <div class="panel-collapse collapseTopic-{{topic.slug}} topic_{{ topic.id }} collapse in" role="tabpanel" aria-labelledby="heading_{{topic.id}}" aria-expanded="true" aria-hidden="false">
  37 + <div class="panel-collapse collapseTopic-{{topic.slug}} topic_{{ topic.id }} collapse" role="tabpanel" aria-labelledby="heading_{{topic.id}}" aria-expanded="false" aria-hidden="true">
  38 + <input type="hidden" class="log_id" />
36 39 <div class="panel-body">
37 40  
38 41 {# dados do tópico no modo de visualização #}
... ...
courses/templates/topic/index.html
... ... @@ -33,7 +33,7 @@
33 33 </button>
34 34 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions">
35 35 <li>
36   - <a href="javascript:void(0)"><i class="fa fa-files-o fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Replicate" %}</a>
  36 + <a href="{% url 'course:replicate_topic' topic.slug %}"><i class="fa fa-files-o fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Replicate" %}</a>
37 37 </li>
38 38 <li>
39 39 <a href="{% url 'course:update_subject' subject.slug %}" data-toggle="modal" data-target="#editSubject"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Edit" %}</a>
... ...
courses/urls.py
... ... @@ -34,6 +34,7 @@ urlpatterns = [
34 34 url(r'^subjects/file-material-view/(?P<slug>[\w_-]+)/$', views.FileMaterialView.as_view(), name='file_material_view'),
35 35 url(r'^links/',include('links.urls',namespace = 'links')),
36 36 url(r'^exercise/', include('exercise.urls', namespace='exercise')),
  37 + url(r'^topic/(?P<topic>[\w_-]+)/$', views.topic_log, name='topic_log'),
37 38 url(r'^(?P<slug>[\w_-]+)/', include([
38 39 url(r'^$', views.CourseView.as_view(), name='view'),
39 40 url(r'^(?P<category>[\w_-]+)/$', views.CourseView.as_view(), name='view_filter')
... ...
courses/views.py
1 1 from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm
2 2 from .models import Course, Subject, CourseCategory, Topic, SubjectCategory, Activity, CategorySubject
3   -from core.decorators import log_decorator
  3 +from core.decorators import log_decorator, log_decorator_ajax
4 4 from core.mixins import LogMixin, NotificationMixin
5 5 from core.models import Log
6 6 from courses.models import Material
... ... @@ -99,6 +99,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
99 99 list_courses = self.get_queryset().filter(students__in = [self.request.user]).order_by('name')
100 100  
101 101 context['categorys_courses'] = course_category(list_courses)
  102 + context['title'] = _('Courses | Amadeus')
102 103 return context
103 104  
104 105 class AllCoursesView(LoginRequiredMixin, NotificationMixin, generic.ListView):
... ... @@ -136,6 +137,7 @@ class AllCoursesView(LoginRequiredMixin, NotificationMixin, generic.ListView):
136 137 list_courses = self.get_queryset()
137 138  
138 139 context['categorys_courses'] = course_category(list_courses)
  140 + context['title'] = _('All Courses | Amadeus')
139 141  
140 142 return context
141 143  
... ... @@ -161,7 +163,7 @@ class CreateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationM
161 163 self.log_context['course_slug'] = self.object.slug
162 164 self.log_context['course_category_id'] = self.object.category.id
163 165 self.log_context['course_category_name'] = self.object.category.name
164   -
  166 + messages.success(self.request,_("Course '%s' was successfully created!"%(self.object.name) ))
165 167 super(CreateCourseView, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
166 168  
167 169 return super(CreateCourseView, self).form_valid(form)
... ... @@ -173,7 +175,7 @@ class CreateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationM
173 175 elif has_role(self.request.user,'professor'):
174 176 courses = self.request.user.courses_student.all()
175 177 context['courses'] = courses
176   - context['title'] = _("Create Course")
  178 + context['title'] = _("Create Course | Amadeus")
177 179 context['now'] = date.today()
178 180 return context
179 181  
... ... @@ -215,7 +217,7 @@ class ReplicateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notificati
215 217 context['courses'] = courses
216 218 context['course'] = course
217 219 context['categorys_courses'] = categorys_courses
218   - context['title'] = _("Replicate Course")
  220 + context['title'] = _("Replicate Course | Amadeus")
219 221 context['now'] = date.today()
220 222 print (course.public)
221 223 return context
... ... @@ -245,7 +247,6 @@ class UpdateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.Updat
245 247 def form_valid(self, form):
246 248 self.object = form.save()
247 249  
248   - print (form)
249 250 self.log_context['course_id'] = self.object.id
250 251 self.log_context['course_name'] = self.object.name
251 252 self.log_context['course_slug'] = self.object.slug
... ... @@ -453,6 +454,11 @@ class IndexCatView(LoginRequiredMixin, generic.ListView):
453 454 context_object_name = 'categories'
454 455 paginate_by = 10
455 456  
  457 + def get_context_data (self, **kwargs):
  458 + context = super(IndexCatView, self).get_context_data(**kwargs)
  459 + context['title'] = _('Categories | Amadeus')
  460 + return context
  461 +
456 462 class CreateCatView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView):
457 463  
458 464 allowed_roles = ['professor', 'system_admin']
... ... @@ -467,6 +473,12 @@ class CreateCatView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView):
467 473 messages.success(self.request, _('Category "%s" created successfully!')%(objeto))
468 474 return reverse_lazy('course:manage_cat')
469 475  
  476 + def get_context_data (self, **kwargs):
  477 + context = super(CreateCatView, self).get_context_data(**kwargs)
  478 + context['title'] = _('Create Category | Amadeus')
  479 +
  480 + return context
  481 +
470 482 class UpdateCatView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView):
471 483  
472 484 allowed_roles = ['professor', 'system_admin']
... ... @@ -482,6 +494,7 @@ class UpdateCatView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView):
482 494 messages.success(self.request, _('Category "%s" updated successfully!')%(objeto))
483 495 #return reverse_lazy('course:update_cat', kwargs={'slug' : self.object.slug})
484 496 return reverse_lazy('course:manage_cat')
  497 +
485 498 class DeleteCatView(LoginRequiredMixin, HasRoleMixin, generic.DeleteView):
486 499  
487 500 allowed_roles = ['professor', 'system_admin']
... ... @@ -556,6 +569,7 @@ class SubjectsView(LoginRequiredMixin, LogMixin, generic.ListView):
556 569 context['subject'] = subject
557 570 context['topics'] = Topic.objects.filter(subject = subject)
558 571 context['exercise'] = Exercise.objects.filter(topic__subject=subject)
  572 + context['title'] = subject.name
559 573 if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'):
560 574 context['files'] = TopicFile.objects.filter(professor__name = self.request.user.name)
561 575 else:
... ... @@ -631,7 +645,7 @@ class TopicsView(LoginRequiredMixin, LogMixin, generic.ListView):
631 645 activitys = Activity.objects.filter(topic__name = topic.name)
632 646 students_activit = User.objects.filter(activities__in = Activity.objects.all())
633 647 materials = Material.objects.filter(topic = topic)
634   -
  648 +
635 649 users = User.objects.filter(subject_student__in = Subject.objects.all())
636 650 context['users'] = users
637 651 exercises = Exercise.objects.filter(Q(students=self.request.user)|Q(professors=self.request.user))
... ... @@ -644,6 +658,7 @@ class TopicsView(LoginRequiredMixin, LogMixin, generic.ListView):
644 658 context['students_activit'] = students_activit
645 659 context['materials'] = materials
646 660 context['form'] = ActivityForm
  661 + context['title'] = topic.name
647 662  
648 663 return context
649 664  
... ... @@ -669,6 +684,7 @@ class CreateTopicView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationMi
669 684 context['course'] = subject.course
670 685 context['subject'] = subject
671 686 context['subjects'] = subject.course.subjects.all()
  687 + context['title'] = _('Create Topic | Amadeus')
672 688 return context
673 689  
674 690 def form_valid(self, form):
... ... @@ -774,6 +790,7 @@ class CreateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notification
774 790 context['subjects'] = course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user]))
775 791 if (has_role(self.request.user,'system_admin')):
776 792 context['subjects'] = course.subjects.all()
  793 + context['title'] = _('Create Subject | Amadeus')
777 794 return context
778 795  
779 796 def form_valid(self, form):
... ... @@ -848,6 +865,7 @@ class UpdateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.Upda
848 865 context['course'] = self.object.course
849 866 context['subject'] = self.object
850 867 context['subjects'] = self.object.course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user]))
  868 + context['title'] = self.object.name
851 869 if (has_role(self.request.user,'system_admin')):
852 870 context['subjects'] = self.object.course.subjects.all()
853 871 return context
... ... @@ -970,6 +988,35 @@ class FileMaterialView(LoginRequiredMixin, LogMixin, generic.DetailView):
970 988  
971 989 return super(FileMaterialView, self).dispatch(*args, **kwargs)
972 990  
  991 +@login_required
  992 +@log_decorator_ajax("courses", "viewed", "topic")
  993 +def topic_log(request, topic):
  994 + action = request.GET.get('action')
  995 +
  996 + if action == 'open':
  997 + topic = get_object_or_404(Topic, id = topic)
  998 + log_context = {}
  999 + log_context['topic_id'] = topic.id
  1000 + log_context['topic_name'] = topic.name
  1001 + log_context['topic_slug'] = topic.slug
  1002 + log_context['subject_id'] = topic.subject.id
  1003 + log_context['subject_name'] = topic.subject.name
  1004 + log_context['subject_slug'] = topic.subject.slug
  1005 + log_context['course_id'] = topic.subject.course.id
  1006 + log_context['course_name'] = topic.subject.course.name
  1007 + log_context['course_slug'] = topic.subject.course.slug
  1008 + log_context['course_category_id'] = topic.subject.course.category.id
  1009 + log_context['course_category_name'] = topic.subject.course.category.name
  1010 + log_context['timestamp_start'] = str(int(time.time()))
  1011 + log_context['timestamp_end'] = "-1"
  1012 + request.log_context = log_context
  1013 + log_id = Log.objects.latest('id').id
  1014 +
  1015 + response = JsonResponse({"message": "ok", "log_id": log_id})
  1016 + else:
  1017 + response = JsonResponse({"message": "ok"})
  1018 +
  1019 + return response
973 1020  
974 1021 #API VIEWS
975 1022 class CourseViewSet(viewsets.ModelViewSet):
... ... @@ -1011,6 +1058,7 @@ class ReplicateTopicView (LoginRequiredMixin, HasRoleMixin, LogMixin, Notificati
1011 1058 context['subject'] = subject
1012 1059 context['subjects'] = subject.course.subjects.all()
1013 1060 context['topic'] = topic
  1061 + context['title'] = subject.name
1014 1062 return context
1015 1063  
1016 1064 def form_valid(self, form):
... ... @@ -1065,6 +1113,7 @@ class ReplicateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notificat
1065 1113 context['course'] = course
1066 1114 context['subjects'] = course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user]))
1067 1115 context['subject'] = subject
  1116 + context['title'] = course.name
1068 1117 if (has_role(self.request.user,'system_admin')):
1069 1118 context['subjects'] = course.subjects.all()
1070 1119 return context
... ...
exam/admin.py
1 1 from django.contrib import admin
2 2  
3   -from .models import Exam, Answer, AnswersStudent
  3 +from .models import Exam, Answer, AnswersStudent, Question, Alternative
4 4  
5 5 class ExamAdmin(admin.ModelAdmin):
6 6 list_display = ['name', 'slug','begin_date','limit_date']
... ... @@ -17,3 +17,5 @@ class AnswersStudentAdmin(admin.ModelAdmin):
17 17 admin.site.register(Exam, ExamAdmin)
18 18 admin.site.register(Answer, AnswerAdmin)
19 19 admin.site.register(AnswersStudent, AnswersStudentAdmin)
  20 +admin.site.register(Question)
  21 +admin.site.register(Alternative)
... ...
exam/forms.py
... ... @@ -25,7 +25,7 @@ class ExamForm(forms.ModelForm):
25 25  
26 26 class Meta:
27 27 model = Exam
28   - fields = ['name','begin_date','limit_date','students','all_students']
  28 + fields = ['name','begin_date','limit_date','students','all_students', 'begin_exam', 'end_exam']
29 29  
30 30 widgets = {
31 31 'name': forms.TextInput(attrs={'placeholder': 'Exam?'}),
... ...
exam/migrations/0003_auto_20161125_0808.py 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-25 11:08
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations, models
  6 +import django.utils.timezone
  7 +
  8 +
  9 +class Migration(migrations.Migration):
  10 +
  11 + dependencies = [
  12 + ('exam', '0002_auto_20161124_1217'),
  13 + ]
  14 +
  15 + operations = [
  16 + migrations.AddField(
  17 + model_name='exam',
  18 + name='begin_exam',
  19 + field=models.DateField(blank=True, default=django.utils.timezone.now, verbose_name='Begin of Exam'),
  20 + preserve_default=False,
  21 + ),
  22 + migrations.AddField(
  23 + model_name='exam',
  24 + name='end_exam',
  25 + field=models.DateField(blank=True, default=django.utils.timezone.now, verbose_name='End of Exam'),
  26 + preserve_default=False,
  27 + ),
  28 + ]
... ...
exam/models.py
... ... @@ -6,15 +6,17 @@ from core.models import Resource
6 6 from courses.models import Activity
7 7  
8 8 class Exam(Activity):
9   - begin_date = models.DateField(_('Begin of Course Date'), blank=True)
10   - exibe = models.BooleanField(_('Exibe?'), default=False)
  9 + begin_date = models.DateField(_('Begin of Course Date'), blank=True)
  10 + begin_exam = models.DateField(_('Begin of Exam'), blank = True)
  11 + end_exam = models.DateField(_('End of Exam'), blank = True)
  12 + exibe = models.BooleanField(_('Exibe?'), default=False)
11 13  
12   - class Meta:
13   - verbose_name = _('Exam')
14   - verbose_name_plural = _('Exams')
  14 + class Meta:
  15 + verbose_name = _('Exam')
  16 + verbose_name_plural = _('Exams')
15 17  
16   - def __str__(self):
17   - return str(self.name) + str("/") + str(self.topic)
  18 + def __str__(self):
  19 + return str(self.name) + str("/") + str(self.topic)
18 20  
19 21  
20 22 class Answer(models.Model):
... ... @@ -43,3 +45,12 @@ class AnswersStudent(models.Model):
43 45  
44 46 def __str__(self):
45 47 return str(self.student) + str("/") + str(self.exam)
  48 +
  49 +class Question(models.Model):
  50 + exam = models.ForeignKey(Exam, verbose_name=_('Exam'), related_name='question_exam')
  51 + statement = models.TextField(_("Statement"), blank=False)
  52 +
  53 +class Alternative(models.Model):
  54 + question = models.ForeignKey(Question, verbose_name=_("Question"), related_name="alternative_question")
  55 + statement = models.TextField(_("Statement"), blank=False)
  56 + answer = models.BooleanField(_("answer"), default=False)
46 57 \ No newline at end of file
... ...
exam/static/js/Exam.js
... ... @@ -95,7 +95,7 @@
95 95 }
96 96 //Bug quando criamos sem ser na ordem
97 97 function functionNewAlternative(Question_Id){
98   - var alternative = parseInt($("div input").last().val()) + 1;
  98 + var alternative = parseInt($(Question_Id).find("input:last").val()) + 1;
99 99 var element = '<div class="radio radio-primary form-group">' +
100 100 '<label>' +
101 101 '<input type="radio" name="alternatives" id="alternative_'+alternative+'_'+Question_Id+'"' + 'value="'+alternative+'">' +
... ... @@ -106,9 +106,9 @@ function functionNewAlternative(Question_Id){
106 106 $.material.init() //O material deve ser iniciado aqui para funcionar os botoes de radio.
107 107 }
108 108 function functionNewAlternativeTF(Question_Id){
109   - var alternative = parseInt($("div").last().val()) + 1;
  109 + var alternative = parseInt($('#radiosTF_1').find('div:last').attr('value')) + 1;
110 110 var element =
111   - '<div class="radio form-group">'+
  111 + '<div class="radio radio-primary form-group" value="'+alternative+'">'+
112 112 '<label class="primary-label-TF" >'+
113 113 '<textarea class="form-control" rows="1" placeholder="Write your alternative"></textarea>'+
114 114 '</label>'+
... ... @@ -122,4 +122,9 @@ function functionNewAlternativeTF(Question_Id){
122 122 $(Question_Id).append(element);
123 123 $('.primary-label-TF').css('padding-left', '0px');
124 124 $.material.init() //O material deve ser iniciado aqui para funcionar os botoes de radio.
125   -}
126 125 \ No newline at end of file
  126 +}
  127 +var locale = navigator.language || navigator.userLanguage;
  128 +
  129 + $('.date-picker').datepicker({
  130 + language: locale,
  131 + });
127 132 \ No newline at end of file
... ...
exam/templates/exam/create.html
... ... @@ -13,22 +13,40 @@
13 13 <h4 class="panel-title" id="exam-title">{% trans "Create a Exam" %}</h4>
14 14 </div>
15 15 <div class="panel-body">
16   - <div class="row form-group">
17   - <label for="exam_name" class="col-md-2 control-label">{% trans "Exam Name" %}</label>
18   - <div class="col-md-10">
19   - <input type="text" name="exam_name" class="form-control" id="exam_name" placeholder="{% trans 'Exam Name' %}">
20   - </div>
21   - </div>
22   - <div class="row form-group">
23   - <label for="begin_date" class="col-md-2 control-label">{% trans "Exam's begin date" %}</label>
24   - <div class="col-md-4">
25   - <input type="date" name="begin_date" class="form-control" id="begin_date" placeholder='{% trans "Begin Date" %}'>
26   - </div>
27   - <label for="end_date" class="col-md-2 control-label">{% trans "Exam's end date" %}</label>
28   - <div class="col-md-4">
29   - <input type="date" name="end_date" class="form-control" id="end_date" placeholder='{% trans "End Date" %}'>
  16 + {% csrf_token %}
  17 + {% for field in form %}
  18 + {% if field.auto_id != 'id_begin_exam' and field.auto_id != 'id_end_exam' and field.auto_id != 'id_begin_date' and field.auto_id != 'id_limit_date' %}
  19 + <div class="row form-group">
  20 + {% if field.field.required %}
  21 + <label for="{{ field.auto_id }}" class="col-md-2 control-label">{{ field.label }}</label>
  22 + {% else %}
  23 + <label for="{{ field.auto_id }}" class="col-md-2 control-label">{{ field.label }}</label>
  24 + {% endif %}
  25 + <div class="col-md-10">
  26 + {% if field.auto_id == 'id_all_students' %}
  27 + {% render_field field class='form-control input-sm' %}
  28 + {% else %}
  29 + {% render_field field class='form-control input-sm' %}
  30 + {% endif %}
  31 + </div>
  32 + </div>
  33 + {% endif %}
  34 + {% endfor %}
  35 + <div class="row form-group">
  36 + {% for field in form %}
  37 + {% if field.auto_id == 'id_begin_date' or field.auto_id == 'id_limit_date' %}
  38 + {% if field.field.required %}
  39 + <label for="{{ field.auto_id }}" class="col-md-2 control-label">{{ field.label }}</label>
  40 + {% else %}
  41 + <label for="{{ field.auto_id }}" class="col-md-2 control-label">{{ field.label }}</label>
  42 + {% endif %}
  43 + <div class="col-md-4">
  44 + {% render_field field class='form-control date-picker' %}
  45 + </div>
  46 + {% endif %}
  47 + {% endfor %}
30 48 </div>
31   - </div>
  49 +
32 50 <div class="row form-group">
33 51 <div class="col-md-10">
34 52 <div class="checkbox">
... ... @@ -38,6 +56,7 @@
38 56 </div>
39 57 </div>
40 58 </div>
  59 +
41 60 <div class="row form-group" id="buttonAddQuestion">
42 61 <div class="col-md-10">
43 62 <button id="addQuestion" type="button" class="btn btn-raised btn-default">Add new question buton</button>
... ... @@ -54,7 +73,6 @@
54 73 </div>
55 74  
56 75 {% block javascript %}
57   - <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
58 76 <script type="text/javascript">
59 77 //Insert Create select with question type
60 78 var idQuestionType = 1;
... ...
links/image_crawler.py
1 1 from bs4 import BeautifulSoup
2 2 from urllib.request import urlopen
  3 +from urllib.parse import urlparse
3 4 import urllib.request
4 5  
5 6 def make_soup(url):
... ... @@ -20,6 +21,8 @@ def get_images(url,slug):
20 21 return ("Use default image",downloaded)
21 22 images = [img for img in soup.findAll('img')]
22 23 image_links = [each.get('src') for each in images]
  24 + parsed_uri = urlparse(url)
  25 + domain = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri)
23 26 link_slug = slug
24 27 filename = ''
25 28 for each in image_links:
... ... @@ -46,15 +49,25 @@ def get_images(url,slug):
46 49 filename = '.jpeg'
47 50 if not booleano:
48 51 continue
49   -
50   - if each[0] + each[1] == '//' or each[0] == '/':
51   - each = 'http:'+each
52   - if each[0:4] != 'http' and each[0:5] != 'https':
53   - each = url[0:url.index('/',8)] + each
54 52 caminho = "links/static/images/"
55 53 try:
56 54 urllib.request.urlretrieve(each,"%s"%(caminho)+str(link_slug)+filename)
57 55 downloaded = True
58 56 except Exception:
59   - continue
  57 + try:
  58 + aux = domain + each
  59 + urllib.request.urlretrieve(aux,"%s"%(caminho)+str(link_slug)+filename)
  60 + downloaded = True
  61 + except Exception as e:
  62 + try:
  63 + aux2 = url[0:url.index('/',8)] + each
  64 + urllib.request.urlretrieve(aux2,"%s"%(caminho)+str(link_slug)+filename)
  65 + downloaded = True
  66 + except Exception as e:
  67 + try:
  68 + aux3 = 'http:' + each
  69 + urllib.request.urlretrieve(aux3,"%s"%(caminho)+str(link_slug)+filename)
  70 + downloaded = True
  71 + except Exception as e:
  72 + continue
60 73 return filename,downloaded
... ...
links/templates/links/view_link.html
... ... @@ -14,7 +14,7 @@
14 14 <div class="card-block">
15 15 <b class="card-title">{{link.name}}</b><p></p>
16 16 <p class="card-text"> </p><p>{{link.link_description}}</p>
17   - <a href="{{ link.link_url }}" class="btn btn-raised btn-primary">{% trans 'Read more' %}</a>
  17 + <a href="{{ link.link_url }}" class="btn btn-raised btn-primary" target="_blank">{% trans 'Read more' %}</a>
18 18 </div>
19 19 </article>
20 20 <!-- .end Card -->
... ...
users/locale/pt_BR/LC_MESSAGES/django.po
... ... @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 8 msgstr ""
9 9 "Project-Id-Version: PACKAGE VERSION\n"
10 10 "Report-Msgid-Bugs-To: \n"
11   -"POT-Creation-Date: 2016-11-23 23:09-0300\n"
  11 +"POT-Creation-Date: 2016-11-26 00:29-0300\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
... ... @@ -217,7 +217,7 @@ msgstr &quot;Início&quot;
217 217 msgid "Manage Users"
218 218 msgstr "Gerenciar Usuários"
219 219  
220   -#: .\templates\users\profile.html:16 .\views.py:75
  220 +#: .\templates\users\profile.html:16 .\views.py:80
221 221 msgid "Add User"
222 222 msgstr "Adicionar usuário"
223 223  
... ... @@ -313,28 +313,30 @@ msgstr &quot;CPF&quot;
313 313 msgid "Birth date:"
314 314 msgstr "Data de nascimento:"
315 315  
316   -#: .\views.py:70 .\views.py:103
  316 +#: .\views.py:75 .\views.py:108
317 317 #, fuzzy
318 318 #| msgid "User"
319 319 msgid "User "
320   -msgstr "Usuário"
  320 +msgstr "Usuário "
  321 +
  322 +#: .\views.py:75
  323 +msgid " created successfully!"
  324 +msgstr " criado com sucesso!"
  325 +
  326 +#: .\views.py:108
  327 +msgid " updated successfully!"
  328 +msgstr " editado com sucesso!"
321 329  
322   -#: .\views.py:120 .\views.py:126
  330 +#: .\views.py:125 .\views.py:131
323 331 #, fuzzy
324 332 #| msgid "User edited successfully!"
325 333 msgid "User deleted Successfully!"
326   -msgstr "Usuário editado com sucesso!"
  334 +msgstr "Usuário apagado com sucesso!"
327 335  
328   -#: .\views.py:156
  336 +#: .\views.py:161
329 337 msgid "Profile edited successfully!"
330 338 msgstr "Perfil editado com sucesso!"
331 339  
332   -#~ msgid "User created successfully!"
333   -#~ msgstr "Usuário criado com sucesso!"
334   -
335   -#~ msgid "User edited successfully!"
336   -#~ msgstr "Usuário editado com sucesso!"
337   -
338 340 #~ msgid "Administrador"
339 341 #~ msgstr "Administrador"
340 342  
... ...
users/templates/users/profile.html
... ... @@ -11,12 +11,6 @@
11 11  
12 12 {% endblock %}
13 13  
14   -{% block menu %}
15   - {% if user|has_role:'system_admin' %}
16   - <li> <a href="{% url 'users:create' %}">{% trans 'Add User' %}</a></li>
17   - {% endif %}
18   -{% endblock %}
19   -
20 14 {% block content %}
21 15 {% if messages %}
22 16 {% for message in messages %}
... ...
users/views.py
... ... @@ -45,6 +45,11 @@ class UsersListView(HasRoleMixin, LoginRequiredMixin, generic.ListView):
45 45  
46 46 return users
47 47  
  48 + def get_context_data (self, **kwargs):
  49 + context = super(UsersListView, self).get_context_data(**kwargs)
  50 + context['title'] = 'Manage Users | Amadeus'
  51 + return context
  52 +
48 53 class Create(HasRoleMixin, LoginRequiredMixin, generic.edit.CreateView):
49 54  
50 55 allowed_roles = ['system_admin']
... ... @@ -67,12 +72,12 @@ class Create(HasRoleMixin, LoginRequiredMixin, generic.edit.CreateView):
67 72  
68 73 self.object.save()
69 74  
70   - messages.success(self.request, _('User ')+self.object.name+(' created successfully!'))
  75 + messages.success(self.request, ('User ')+self.object.name+(' created successfully!'))
71 76  
72 77 return super(Create, self).form_valid(form)
73 78 def get_context_data (self, **kwargs):
74 79 context = super(Create, self).get_context_data(**kwargs)
75   - context['title'] = _("Add User")
  80 + context['title'] = "Add User | Amadeus"
76 81 return context
77 82  
78 83 class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView):
... ... @@ -100,10 +105,15 @@ class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView):
100 105  
101 106 self.object.save()
102 107  
103   - messages.success(self.request, _('User ')+self.object.name+(' updated successfully!'))
  108 + messages.success(self.request, _('User ')+self.object.name+_(' updated successfully!'))
104 109  
105 110 return super(Update, self).form_valid(form)
106 111  
  112 + def get_context_data (self, **kwargs):
  113 + context = super(Update, self).get_context_data(**kwargs)
  114 + context['title'] = "Update User | Amadeus"
  115 + return context
  116 +
107 117 class View(LoginRequiredMixin, generic.DetailView):
108 118  
109 119 login_url = reverse_lazy("core:home")
... ... @@ -114,6 +124,11 @@ class View(LoginRequiredMixin, generic.DetailView):
114 124 slug_field = 'username'
115 125 slug_url_kwarg = 'username'
116 126  
  127 + def get_context_data (self, **kwargs):
  128 + context = super(View, self).get_context_data(**kwargs)
  129 + context['title'] = "User | Amadeus"
  130 + return context
  131 +
117 132 def delete_user(request,username):
118 133 user = get_object_or_404(User,username = username)
119 134 user.delete()
... ... @@ -129,9 +144,18 @@ def remove_account(request,username):
129 144 class Change_password(generic.TemplateView):
130 145 template_name = 'users/change_password.html'
131 146  
  147 + def get_context_data (self, **kwargs):
  148 + context = super(Change_password, self).get_context_data(**kwargs)
  149 + context['title'] = "Change Password | Amadeus"
  150 + return context
  151 +
132 152 class Remove_account(generic.TemplateView):
133 153 template_name = 'users/remove_account.html'
134 154  
  155 + def get_context_data (self, **kwargs):
  156 + context = super(Remove_account, self).get_context_data(**kwargs)
  157 + context['title'] = "Remove Account | Amadeus"
  158 + return context
135 159  
136 160 class UpdateProfile(LoginRequiredMixin, generic.edit.UpdateView):
137 161 login_url = reverse_lazy("core:home")
... ... @@ -145,6 +169,7 @@ class UpdateProfile(LoginRequiredMixin, generic.edit.UpdateView):
145 169  
146 170 def get_context_data(self, **kwargs):
147 171 context = super(UpdateProfile, self).get_context_data(**kwargs)
  172 + context['title'] = 'Update Profile | Amadeus'
148 173 if has_role(self.request.user, 'system_admin'):
149 174 context['form'] = UpdateProfileFormAdmin(instance = self.object)
150 175 else:
... ... @@ -179,6 +204,12 @@ class Profile(LoginRequiredMixin, generic.DetailView):
179 204 def get_object(self):
180 205 user = get_object_or_404(User, username = self.request.user.username)
181 206 return user
  207 +
  208 + def get_context_data (self, **kwargs):
  209 + context = super(Profile, self).get_context_data(**kwargs)
  210 + context['title'] = "Profile | Amadeus"
  211 + return context
  212 +
182 213 class SearchView(LoginRequiredMixin, generic.ListView):
183 214  
184 215 login_url = reverse_lazy("core:home")
... ...