Commit 944b7e71dbbdae45d9813257d0e8b7252fe1d432

Authored by ailsoncgt
2 parents c37e0128 ce6e6ebe

Merge

@@ -80,14 +80,31 @@ Para Classes que envolvem formulários: @@ -80,14 +80,31 @@ Para Classes que envolvem formulários:
80 * `CreateCourseForm` 80 * `CreateCourseForm`
81 * `UpdateCourseForm()` 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 * model list(GET) = list all objects from that mode in pagination mode, each page has 10 102 * model list(GET) = list all objects from that mode in pagination mode, each page has 10
88 * model detail(GET) = give the details of the objects and most important fields of the ones objects its has relationships. 103 * model detail(GET) = give the details of the objects and most important fields of the ones objects its has relationships.
89 * model create 104 * model create
90 105
  106 +**API Endpoints **
  107 +
91 **Courses (URL: coursesapi)** 108 **Courses (URL: coursesapi)**
92 * course list ("/coursesapi/") 109 * course list ("/coursesapi/")
93 * course detail ("/coursesapi/id") (id is a parameter) 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,14 +121,7 @@ We are using mostly viewsets ( http://www.django-rest-framework.org/api-guide/vi
104 * logs list ("/logs/") 121 * logs list ("/logs/")
105 * log detail ("/logs/id") (id is a parameter) 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 ## Link's úteis 127 ## Link's úteis
app/locale/pt_BR/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid &quot;&quot; @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 msgstr "" 8 msgstr ""
9 "Project-Id-Version: PACKAGE VERSION\n" 9 "Project-Id-Version: PACKAGE VERSION\n"
10 "Report-Msgid-Bugs-To: \n" 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 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -212,10 +212,18 @@ msgstr &quot;em&quot; @@ -212,10 +212,18 @@ msgstr &quot;em&quot;
212 msgid "ago" 212 msgid "ago"
213 msgstr "atrás" 213 msgstr "atrás"
214 214
  215 +#: .\views.py:38
  216 +msgid "Home | Amadeus"
  217 +msgstr "Página inicial | Amadeus"
  218 +
215 #: .\views.py:75 219 #: .\views.py:75
216 msgid "Changes saved." 220 msgid "Changes saved."
217 msgstr "Mudanças salvas" 221 msgstr "Mudanças salvas"
218 222
  223 +#: .\views.py:82
  224 +msgid "Settings | Amadeus"
  225 +msgstr "Configurações | Amadeus"
  226 +
219 #, fuzzy 227 #, fuzzy
220 #~| msgid "Students:" 228 #~| msgid "Students:"
221 #~ msgid "Students" 229 #~ msgid "Students"
@@ -14,7 +14,7 @@ from .forms import EmailBackendForm @@ -14,7 +14,7 @@ from .forms import EmailBackendForm
14 from courses.models import Course 14 from courses.models import Course
15 15
16 class AppIndex(LoginRequiredMixin, ListView, NotificationMixin): 16 class AppIndex(LoginRequiredMixin, ListView, NotificationMixin):
17 - login_url = reverse_lazy("core:home") 17 + login_url = reverse_lazy("core:home")
18 redirect_field_name = 'next' 18 redirect_field_name = 'next'
19 19
20 template_name = "home.html" 20 template_name = "home.html"
@@ -34,15 +34,15 @@ class AppIndex(LoginRequiredMixin, ListView, NotificationMixin): @@ -34,15 +34,15 @@ class AppIndex(LoginRequiredMixin, ListView, NotificationMixin):
34 context['page_template'] = "home_admin_content.html" 34 context['page_template'] = "home_admin_content.html"
35 else: 35 else:
36 context['page_template'] = "home_teacher_student_content.html" 36 context['page_template'] = "home_teacher_student_content.html"
37 -  
38 - context['title'] = 'Amadeus' 37 +
  38 + context['title'] = _('Home | Amadeus')
39 39
40 if self.request.is_ajax(): 40 if self.request.is_ajax():
41 if self.request.user.is_staff: 41 if self.request.user.is_staff:
42 self.template_name = "home_admin_content.html" 42 self.template_name = "home_admin_content.html"
43 else: 43 else:
44 self.template_name = "home_teacher_student_content.html" 44 self.template_name = "home_teacher_student_content.html"
45 - 45 +
46 return self.response_class(request = self.request, template = self.template_name, context = context, using = self.template_engine, **response_kwargs) 46 return self.response_class(request = self.request, template = self.template_name, context = context, using = self.template_engine, **response_kwargs)
47 47
48 class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView): 48 class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView):
@@ -79,6 +79,7 @@ class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView): @@ -79,6 +79,7 @@ class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView):
79 def get_context_data(self, **kwargs): 79 def get_context_data(self, **kwargs):
80 context = super(AmadeusSettings, self).get_context_data(**kwargs) 80 context = super(AmadeusSettings, self).get_context_data(**kwargs)
81 context['page'] = self.kwargs.get('page') 81 context['page'] = self.kwargs.get('page')
  82 + context['title'] = _('Settings | Amadeus')
82 if not self.request.method == 'POST': 83 if not self.request.method == 'POST':
83 try: 84 try:
84 setting = EmailBackend.objects.latest('id') 85 setting = EmailBackend.objects.latest('id')
@@ -86,6 +87,3 @@ class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView): @@ -86,6 +87,3 @@ class AmadeusSettings(LoginRequiredMixin, HasRoleMixin, generic.CreateView):
86 except: 87 except:
87 pass 88 pass
88 return context 89 return context
89 -  
90 -  
91 -  
core/decorators.py
1 from django.conf import settings 1 from django.conf import settings
2 import json 2 import json
  3 +import time
3 from functools import wraps 4 from functools import wraps
  5 +from django.shortcuts import get_object_or_404
4 from .models import Action, Resource, Action_Resource, Log, Notification 6 from .models import Action, Resource, Action_Resource, Log, Notification
5 7
6 def log_decorator(log_component = '', log_action = '', log_resource = ''): 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,7 +40,6 @@ def log_decorator(log_component = &#39;&#39;, log_action = &#39;&#39;, log_resource = &#39;&#39;):
38 log = Log() 40 log = Log()
39 log.user = request.user 41 log.user = request.user
40 log.component = log_component 42 log.component = log_component
41 - #log.context = json.dumps(request.log_context)  
42 log.context = request.log_context 43 log.context = request.log_context
43 log.action_resource = action_resource 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,6 +52,75 @@ def log_decorator(log_component = &#39;&#39;, log_action = &#39;&#39;, log_resource = &#39;&#39;):
51 return _log_decorator 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 def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource='', resource_link=''): 124 def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource='', resource_link=''):
55 125
56 def _notification_decorator(view_function): 126 def _notification_decorator(view_function):
core/locale/pt_BR/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid &quot;&quot; @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 msgstr "" 8 msgstr ""
9 "Project-Id-Version: PACKAGE VERSION\n" 9 "Project-Id-Version: PACKAGE VERSION\n"
10 "Report-Msgid-Bugs-To: \n" 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 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "Language-Team: LANGUAGE <LL@li.org>\n"
core/middleware.py
@@ -32,3 +32,17 @@ class TimeSpentMiddleware(object): @@ -32,3 +32,17 @@ class TimeSpentMiddleware(object):
32 log.save() 32 log.save()
33 33
34 request.session['log_id'] = None 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,7 +8,7 @@ msgid &quot;&quot;
8 msgstr "" 8 msgstr ""
9 "Project-Id-Version: PACKAGE VERSION\n" 9 "Project-Id-Version: PACKAGE VERSION\n"
10 "Report-Msgid-Bugs-To: \n" 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 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -20,7 +20,7 @@ msgstr &quot;&quot; @@ -20,7 +20,7 @@ msgstr &quot;&quot;
20 20
21 #: .\forms.py:13 .\forms.py:25 .\forms.py:47 .\forms.py:68 .\forms.py:91 21 #: .\forms.py:13 .\forms.py:25 .\forms.py:47 .\forms.py:68 .\forms.py:91
22 #: .\models.py:14 .\models.py:26 .\models.py:39 .\models.py:68 .\models.py:96 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 #: .\templates\subject\replicate.html:18 .\templates\topic\replicate.html:18 24 #: .\templates\subject\replicate.html:18 .\templates\topic\replicate.html:18
25 msgid "Name" 25 msgid "Name"
26 msgstr "Nome" 26 msgstr "Nome"
@@ -55,7 +55,7 @@ msgid &quot;To define if the course can be accessed by people not registered&quot; @@ -55,7 +55,7 @@ msgid &quot;To define if the course can be accessed by people not registered&quot;
55 msgstr "Para definir se o curso pode ser acessado por pessoas não registradas" 55 msgstr "Para definir se o curso pode ser acessado por pessoas não registradas"
56 56
57 #: .\forms.py:69 .\forms.py:92 .\models.py:70 .\models.py:98 .\models.py:159 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 #: .\templates\subject\index.html:53 .\templates\subject\replicate.html:25 59 #: .\templates\subject\index.html:53 .\templates\subject\replicate.html:25
60 #: .\templates\topic\replicate.html:24 60 #: .\templates\topic\replicate.html:24
61 msgid "Description" 61 msgid "Description"
@@ -173,7 +173,7 @@ msgstr &quot;Todos estudantes&quot; @@ -173,7 +173,7 @@ msgstr &quot;Todos estudantes&quot;
173 173
174 #: .\models.py:143 .\models.py:148 174 #: .\models.py:143 .\models.py:148
175 #: .\templates\subject\form_view_student.html:42 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 msgid "Material" 177 msgid "Material"
178 msgstr "Material" 178 msgstr "Material"
179 179
@@ -228,7 +228,7 @@ msgstr &quot;Remover&quot; @@ -228,7 +228,7 @@ msgstr &quot;Remover&quot;
228 228
229 #: .\templates\course\course_card.html:18 .\templates\course\view.html:39 229 #: .\templates\course\course_card.html:18 .\templates\course\view.html:39
230 #: .\templates\course\view.html:90 230 #: .\templates\course\view.html:90
231 -#: .\templates\subject\form_view_teacher.html:24 231 +#: .\templates\subject\form_view_teacher.html:26
232 #: .\templates\subject\index.html:37 .\templates\subject\replicate.html:52 232 #: .\templates\subject\index.html:37 .\templates\subject\replicate.html:52
233 #: .\templates\topic\index.html:36 233 #: .\templates\topic\index.html:36
234 msgid "Replicate" 234 msgid "Replicate"
@@ -236,14 +236,14 @@ msgstr &quot;Repetir&quot; @@ -236,14 +236,14 @@ msgstr &quot;Repetir&quot;
236 236
237 #: .\templates\course\course_card.html:19 .\templates\course\view.html:40 237 #: .\templates\course\course_card.html:19 .\templates\course\view.html:40
238 #: .\templates\course\view.html:91 238 #: .\templates\course\view.html:91
239 -#: .\templates\subject\form_view_teacher.html:25 239 +#: .\templates\subject\form_view_teacher.html:27
240 #: .\templates\subject\index.html:38 .\templates\topic\index.html:39 240 #: .\templates\subject\index.html:38 .\templates\topic\index.html:39
241 msgid "Edit" 241 msgid "Edit"
242 msgstr "Editar" 242 msgstr "Editar"
243 243
244 #: .\templates\course\course_card.html:20 .\templates\course\view.html:41 244 #: .\templates\course\course_card.html:20 .\templates\course\view.html:41
245 #: .\templates\course\view.html:92 245 #: .\templates\course\view.html:92
246 -#: .\templates\subject\form_view_teacher.html:26 246 +#: .\templates\subject\form_view_teacher.html:28
247 #: .\templates\subject\index.html:39 .\templates\topic\index.html:42 247 #: .\templates\subject\index.html:39 .\templates\topic\index.html:42
248 msgid "Remove" 248 msgid "Remove"
249 msgstr "Remover" 249 msgstr "Remover"
@@ -276,7 +276,7 @@ msgstr &quot;Apagar curso&quot; @@ -276,7 +276,7 @@ msgstr &quot;Apagar curso&quot;
276 msgid "Are you sure you want to delete the course" 276 msgid "Are you sure you want to delete the course"
277 msgstr "Você tem certeza que deseja deletar o curso" 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 msgid "Create Course" 280 msgid "Create Course"
281 msgstr "Criar curso" 281 msgstr "Criar curso"
282 282
@@ -284,6 +284,10 @@ msgstr &quot;Criar curso&quot; @@ -284,6 +284,10 @@ msgstr &quot;Criar curso&quot;
284 msgid "Categories:" 284 msgid "Categories:"
285 msgstr "Categorias:" 285 msgstr "Categorias:"
286 286
  287 +#: .\templates\course\index.html:29
  288 +msgid "Search for Courses"
  289 +msgstr "Pesquisar por cursos"
  290 +
287 #: .\templates\course\view.html:41 291 #: .\templates\course\view.html:41
288 msgid "Are you sure you want to delete this course?" 292 msgid "Are you sure you want to delete this course?"
289 msgstr "Você tem certeza que deseja deletar este curso?" 293 msgstr "Você tem certeza que deseja deletar este curso?"
@@ -301,8 +305,8 @@ msgid &quot;Cancel&quot; @@ -301,8 +305,8 @@ msgid &quot;Cancel&quot;
301 msgstr "Cancelar" 305 msgstr "Cancelar"
302 306
303 #: .\templates\course\view.html:65 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 msgid "Confirm" 310 msgid "Confirm"
307 msgstr "Confirmar" 311 msgstr "Confirmar"
308 312
@@ -324,64 +328,64 @@ msgid &quot;exam&quot; @@ -324,64 +328,64 @@ msgid &quot;exam&quot;
324 msgstr "Avaliação" 328 msgstr "Avaliação"
325 329
326 #: .\templates\subject\form_view_student.html:55 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 #: .\templates\topic\topic_card.html:18 332 #: .\templates\topic\topic_card.html:18
329 msgid "Activities" 333 msgid "Activities"
330 msgstr "Atividades" 334 msgstr "Atividades"
331 335
332 -#: .\templates\subject\form_view_teacher.html:49 336 +#: .\templates\subject\form_view_teacher.html:52
333 msgid "Name Topic" 337 msgid "Name Topic"
334 msgstr "Nome do tópico" 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 msgid "Create a Link" 341 msgid "Create a Link"
338 msgstr "Criar link" 342 msgstr "Criar link"
339 343
340 -#: .\templates\subject\form_view_teacher.html:70 344 +#: .\templates\subject\form_view_teacher.html:73
341 msgid "Create a file" 345 msgid "Create a file"
342 msgstr "Criar um arquivo" 346 msgstr "Criar um arquivo"
343 347
344 -#: .\templates\subject\form_view_teacher.html:103 348 +#: .\templates\subject\form_view_teacher.html:106
345 msgid "Create Forum" 349 msgid "Create Forum"
346 msgstr "Criar Forum" 350 msgstr "Criar Forum"
347 351
348 -#: .\templates\subject\form_view_teacher.html:104 352 +#: .\templates\subject\form_view_teacher.html:107
349 msgid "Create Poll" 353 msgid "Create Poll"
350 msgstr "Criar enquete" 354 msgstr "Criar enquete"
351 355
352 -#: .\templates\subject\form_view_teacher.html:105 356 +#: .\templates\subject\form_view_teacher.html:108
353 msgid "Delivery Material" 357 msgid "Delivery Material"
354 msgstr "Entregar Material" 358 msgstr "Entregar Material"
355 359
356 -#: .\templates\subject\form_view_teacher.html:106 360 +#: .\templates\subject\form_view_teacher.html:109
357 msgid "Create exam" 361 msgid "Create exam"
358 msgstr "Criar avaliação" 362 msgstr "Criar avaliação"
359 363
360 -#: .\templates\subject\form_view_teacher.html:140 364 +#: .\templates\subject\form_view_teacher.html:143
361 msgid "Back" 365 msgid "Back"
362 msgstr "Voltar" 366 msgstr "Voltar"
363 367
364 -#: .\templates\subject\form_view_teacher.html:160 368 +#: .\templates\subject\form_view_teacher.html:163
365 msgid "Delete your Topic?" 369 msgid "Delete your Topic?"
366 msgstr "Deletar seu Tópico?" 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 msgid "Material EMBED" 373 msgid "Material EMBED"
370 msgstr "Incorporar Material" 374 msgstr "Incorporar Material"
371 375
372 -#: .\templates\subject\form_view_teacher.html:189 376 +#: .\templates\subject\form_view_teacher.html:192
373 msgid "Code" 377 msgid "Code"
374 msgstr "Código" 378 msgstr "Código"
375 379
376 -#: .\templates\subject\form_view_teacher.html:193 380 +#: .\templates\subject\form_view_teacher.html:196
377 msgid "Material description" 381 msgid "Material description"
378 msgstr "Descrição do material" 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 msgid "Height" 385 msgid "Height"
382 msgstr "Tamanho" 386 msgstr "Tamanho"
383 387
384 -#: .\templates\subject\form_view_teacher.html:203 388 +#: .\templates\subject\form_view_teacher.html:206
385 msgid "Weight" 389 msgid "Weight"
386 msgstr "Peso" 390 msgstr "Peso"
387 391
@@ -445,45 +449,75 @@ msgstr &quot;Descrição do Tópico&quot; @@ -445,45 +449,75 @@ msgstr &quot;Descrição do Tópico&quot;
445 msgid "Materials" 449 msgid "Materials"
446 msgstr "Materiais" 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 msgid "Course deleted successfully!" 469 msgid "Course deleted successfully!"
454 msgstr "Curso deletado com sucesso!" 470 msgstr "Curso deletado com sucesso!"
455 471
456 -#: .\views.py:423 472 +#: .\views.py:425
457 msgid "Successfully subscribed to the course!" 473 msgid "Successfully subscribed to the course!"
458 msgstr "Inscrição no curso realizada com sucesso!" 474 msgstr "Inscrição no curso realizada com sucesso!"
459 475
460 -#: .\views.py:425 476 +#: .\views.py:427
461 msgid "" 477 msgid ""
462 "An error has occured. Could not subscribe to this course, try again later" 478 "An error has occured. Could not subscribe to this course, try again later"
463 msgstr "Ocorreu um erro. Não pôde inscrever no curso, tente novamente" 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 msgid "Category \"%s\" created successfully!" 487 msgid "Category \"%s\" created successfully!"
467 msgstr "Categoria \"%s\" criada com sucesso!" 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 msgid "Category \"%s\" updated successfully!" 496 msgid "Category \"%s\" updated successfully!"
471 msgstr "Categoria \"%s\" editada com sucesso!" 497 msgstr "Categoria \"%s\" editada com sucesso!"
472 498
473 -#: .\views.py:507 499 +#: .\views.py:521
474 msgid "Category deleted successfully!" 500 msgid "Category deleted successfully!"
475 msgstr "Categoria deletada com sucesso!" 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 msgid "Successfully subscribed to the subject!" 512 msgid "Successfully subscribed to the subject!"
479 msgstr "Inscrição no assunto realizada com sucesso!" 513 msgstr "Inscrição no assunto realizada com sucesso!"
480 514
481 -#: .\views.py:919 515 +#: .\views.py:938
482 msgid "" 516 msgid ""
483 "An error has occured. Could not subscribe to this subject, try again later" 517 "An error has occured. Could not subscribe to this subject, try again later"
484 msgstr "Ocorreu um erro. Não pôde inscrever no assunto, tente novamente" 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 msgid "You're not subscribed in the course yet." 521 msgid "You're not subscribed in the course yet."
488 msgstr "Você não está inscrito no curso ainda." 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,16 +551,12 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
517 #~ msgid "Image" 551 #~ msgid "Image"
518 #~ msgstr "Imagem" 552 #~ msgstr "Imagem"
519 553
520 -  
521 #~ msgid "CourseCategory" 554 #~ msgid "CourseCategory"
522 #~ msgstr "Categoria do Curso" 555 #~ msgstr "Categoria do Curso"
523 556
524 #~ msgid "Course objective" 557 #~ msgid "Course objective"
525 #~ msgstr "Objetivo do Curso" 558 #~ msgstr "Objetivo do Curso"
526 559
527 -#~ msgid "Course modules"  
528 -#~ msgstr "Módulos do curso"  
529 -  
530 #~ msgid "Max number of students that a class can have" 560 #~ msgid "Max number of students that a class can have"
531 #~ msgstr "Número máximo de estudantes que uma classe pode ter" 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,17 +575,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
545 #~ msgid "Representative image of the course" 575 #~ msgid "Representative image of the course"
546 #~ msgstr "Imagem representativa do curso" 576 #~ msgstr "Imagem representativa do curso"
547 577
548 -  
549 #~| msgid "Category which the course belongs" 578 #~| msgid "Category which the course belongs"
550 #~ msgid "CourseCategory which the course belongs" 579 #~ msgid "CourseCategory which the course belongs"
551 #~ msgstr "Categoria de Curso ao qual o curso pertence" 580 #~ msgstr "Categoria de Curso ao qual o curso pertence"
552 581
553 -  
554 #~| msgid "Maximum Students" 582 #~| msgid "Maximum Students"
555 #~ msgid "Student" 583 #~ msgid "Student"
556 #~ msgstr "Quantidade máxima de estudantes" 584 #~ msgstr "Quantidade máxima de estudantes"
557 585
558 -  
559 #~| msgid "Course modules" 586 #~| msgid "Course modules"
560 #~ msgid "Course's Students" 587 #~ msgid "Course's Students"
561 #~ msgstr "Estudantes do curso" 588 #~ msgstr "Estudantes do curso"
@@ -587,7 +614,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -587,7 +614,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
587 #~ msgid "Profile" 614 #~ msgid "Profile"
588 #~ msgstr "Perfil" 615 #~ msgstr "Perfil"
589 616
590 -  
591 #~| msgid "Courses" 617 #~| msgid "Courses"
592 #~ msgid "My Courses" 618 #~ msgid "My Courses"
593 #~ msgstr "Meus Cursos" 619 #~ msgstr "Meus Cursos"
@@ -595,7 +621,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -595,7 +621,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
595 #~ msgid "Actions" 621 #~ msgid "Actions"
596 #~ msgstr "Ações" 622 #~ msgstr "Ações"
597 623
598 -  
599 #~| msgid "Edit Category" 624 #~| msgid "Edit Category"
600 #~ msgid "List Category" 625 #~ msgid "List Category"
601 #~ msgstr "Listar Categorias" 626 #~ msgstr "Listar Categorias"
@@ -606,7 +631,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -606,7 +631,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
606 #~ msgid "Edit Category" 631 #~ msgid "Edit Category"
607 #~ msgstr "Editar categoria" 632 #~ msgstr "Editar categoria"
608 633
609 -  
610 #~| msgid "Course name" 634 #~| msgid "Course name"
611 #~ msgid "Course Name" 635 #~ msgid "Course Name"
612 #~ msgstr "Nome do Curso" 636 #~ msgstr "Nome do Curso"
@@ -617,22 +641,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -617,22 +641,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
617 #~ msgid "No" 641 #~ msgid "No"
618 #~ msgstr "Não" 642 #~ msgstr "Não"
619 643
620 -  
621 #~| msgid "Course" 644 #~| msgid "Course"
622 #~ msgid "Home Course" 645 #~ msgid "Home Course"
623 #~ msgstr "Pagina Inicial do Curso" 646 #~ msgstr "Pagina Inicial do Curso"
624 647
625 -  
626 #~| msgid "Courses" 648 #~| msgid "Courses"
627 #~ msgid "My courses" 649 #~ msgid "My courses"
628 #~ msgstr "Meus Cursos" 650 #~ msgstr "Meus Cursos"
629 651
630 -  
631 -#~| msgid "Courses"  
632 -#~ msgid "All Courses"  
633 -#~ msgstr "Todos Cursos"  
634 -  
635 -  
636 #~| msgid "Manage Courses" 652 #~| msgid "Manage Courses"
637 #~ msgid "Manage Users" 653 #~ msgid "Manage Users"
638 #~ msgstr "Gerenciar Usuários" 654 #~ msgstr "Gerenciar Usuários"
@@ -643,12 +659,10 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -643,12 +659,10 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
643 #~ msgid "No courses found" 659 #~ msgid "No courses found"
644 #~ msgstr "Nenhum curso encontrado" 660 #~ msgstr "Nenhum curso encontrado"
645 661
646 -  
647 #~| msgid "Image" 662 #~| msgid "Image"
648 #~ msgid "Imagem" 663 #~ msgid "Imagem"
649 #~ msgstr "Imagem" 664 #~ msgstr "Imagem"
650 665
651 -  
652 #~| msgid "Are you sure you want to delete the couse" 666 #~| msgid "Are you sure you want to delete the couse"
653 #~ msgid "Are you sure you want to remove this subject?" 667 #~ msgid "Are you sure you want to remove this subject?"
654 #~ msgstr "Você tem certeza que deseja deletar este assunto?" 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,7 +679,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
665 #~ msgid "Proposal Activity" 679 #~ msgid "Proposal Activity"
666 #~ msgstr "Atividade proposta" 680 #~ msgstr "Atividade proposta"
667 681
668 -  
669 #~| msgid "Description" 682 #~| msgid "Description"
670 #~ msgid "Describe" 683 #~ msgid "Describe"
671 #~ msgstr "Descreva" 684 #~ msgstr "Descreva"
@@ -679,7 +692,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -679,7 +692,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
679 #~ msgid "Send Later" 692 #~ msgid "Send Later"
680 #~ msgstr "Enviar depois" 693 #~ msgstr "Enviar depois"
681 694
682 -  
683 #~| msgid "Manage Courses" 695 #~| msgid "Manage Courses"
684 #~ msgid "Manage Subjects" 696 #~ msgid "Manage Subjects"
685 #~ msgstr "Gerenciar cursos" 697 #~ msgstr "Gerenciar cursos"
@@ -687,7 +699,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -687,7 +699,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
687 #~ msgid "poll" 699 #~ msgid "poll"
688 #~ msgstr "Enquete" 700 #~ msgstr "Enquete"
689 701
690 -  
691 #~| msgid "Create Category" 702 #~| msgid "Create Category"
692 #~ msgid "Create Subject Category" 703 #~ msgid "Create Subject Category"
693 #~ msgstr "Criar Categoria de Assunto" 704 #~ msgstr "Criar Categoria de Assunto"
@@ -695,17 +706,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -695,17 +706,14 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
695 #~ msgid "Participants" 706 #~ msgid "Participants"
696 #~ msgstr "Participantes" 707 #~ msgstr "Participantes"
697 708
698 -  
699 #~| msgid "Duplicate Course" 709 #~| msgid "Duplicate Course"
700 #~ msgid "Replicate subject" 710 #~ msgid "Replicate subject"
701 #~ msgstr "Replicar assunto" 711 #~ msgstr "Replicar assunto"
702 712
703 -  
704 #~| msgid "Create Course" 713 #~| msgid "Create Course"
705 #~ msgid "Create subject" 714 #~ msgid "Create subject"
706 #~ msgstr "Criar assunto" 715 #~ msgstr "Criar assunto"
707 716
708 -  
709 #~| msgid "Edit Course" 717 #~| msgid "Edit Course"
710 #~ msgid "Edit subject" 718 #~ msgid "Edit subject"
711 #~ msgstr "Editar assunto" 719 #~ msgstr "Editar assunto"
@@ -719,7 +727,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot; @@ -719,7 +727,6 @@ msgstr &quot;Você não está inscrito no curso ainda.&quot;
719 #~ msgid "Send" 727 #~ msgid "Send"
720 #~ msgstr "Enviar" 728 #~ msgstr "Enviar"
721 729
722 -  
723 #~| msgid "No categories found" 730 #~| msgid "No categories found"
724 #~ msgid "No activity found" 731 #~ msgid "No activity found"
725 #~ msgstr "Nenhuma atividade encontrada" 732 #~ msgstr "Nenhuma atividade encontrada"
courses/static/js/course.js
@@ -49,7 +49,7 @@ function subscribe(elem, url, id, confirm_message) { @@ -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,7 +62,7 @@ var RemoveCourse = {
62 $("#accordion").remove(); 62 $("#accordion").remove();
63 $(".modal-backdrop.in").remove(); 63 $(".modal-backdrop.in").remove();
64 alertify.success("Course removed successfully!"); 64 alertify.success("Course removed successfully!");
65 - setTimeout(function () { location.reload(1); }, 2000); 65 + setTimeout(function () { location.reload(1); }, 1);
66 }).fail(function(){ 66 }).fail(function(){
67 $("#modal_course").empty(); 67 $("#modal_course").empty();
68 $("#modal_course").append(data); 68 $("#modal_course").append(data);
@@ -84,7 +84,7 @@ var delete_course = { @@ -84,7 +84,7 @@ var delete_course = {
84 }); 84 });
85 } 85 }
86 }; 86 };
87 -/* 87 +/*
88 * 88 *
89 * Function to load create course's form 89 * Function to load create course's form
90 * 90 *
@@ -97,4 +97,4 @@ function replicate_course(url, course) { @@ -97,4 +97,4 @@ function replicate_course(url, course) {
97 $(".course_replicate_form").html(data); 97 $(".course_replicate_form").html(data);
98 } 98 }
99 }); 99 });
100 -}  
101 \ No newline at end of file 100 \ No newline at end of file
  101 +}
courses/static/js/topic.js 0 → 100644
@@ -0,0 +1,30 @@ @@ -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 \ No newline at end of file 31 \ No newline at end of file
courses/templates/course/index.html
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 <form id="searchform" method="get" accept-charset="utf-8"> 26 <form id="searchform" method="get" accept-charset="utf-8">
27 <div class="input-group"> 27 <div class="input-group">
28 <div class="form-group is-empty"> 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 <span class="input-group-btn input-group-sm"> 30 <span class="input-group-btn input-group-sm">
31 <button type="submit" class="btn btn-fab btn-fab-mini"> 31 <button type="submit" class="btn btn-fab btn-fab-mini">
32 <i class="fa fa-search" aria-hidden="true"></i> 32 <i class="fa fa-search" aria-hidden="true"></i>
courses/templates/subject/form_view_student.html
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 <script src="{% static 'js/file.js' %}"></script> 6 <script src="{% static 'js/file.js' %}"></script>
7 <script type="text/javascript" src="{% static 'js/material.js' %}"></script> 7 <script type="text/javascript" src="{% static 'js/material.js' %}"></script>
8 <script type = "text/javascript" src="{% static 'links.js' %}"></script> 8 <script type = "text/javascript" src="{% static 'links.js' %}"></script>
  9 + <script type="text/javascript" src="{% static 'js/topic.js' %}"></script>
9 {% endblock %} 10 {% endblock %}
10 <div class="cards-detail"> 11 <div class="cards-detail">
11 <div class="panel-group accordion ui-accordion ui-widget ui-helper-reset ui-sortable" role="tablist" aria-multiselectable="false"> 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,7 +14,7 @@
13 <div class="panel-heading topic ui-sortable-handle" role="tab"> 14 <div class="panel-heading topic ui-sortable-handle" role="tab">
14 <div class="row"> 15 <div class="row">
15 <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 <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 </div> 18 </div>
18 <div class="col-xs-9 col-md-9 titleTopic"> 19 <div class="col-xs-9 col-md-9 titleTopic">
19 <a href="{% url 'course:view_topic' topic.slug %}" role="button"> 20 <a href="{% url 'course:view_topic' topic.slug %}" role="button">
@@ -22,7 +23,7 @@ @@ -22,7 +23,7 @@
22 </div> 23 </div>
23 </div> 24 </div>
24 </div> 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 <div class="panel-body"> 27 <div class="panel-body">
27 <div class="presentation"> 28 <div class="presentation">
28 <p> 29 <p>
@@ -32,8 +33,7 @@ @@ -32,8 +33,7 @@
32 </p> 33 </p>
33 34
34 </div> 35 </div>
35 - </div>  
36 - </div> 36 +
37 37
38 {% if not professor_links %} 38 {% if not professor_links %}
39 <div class="row"> 39 <div class="row">
@@ -82,4 +82,6 @@ @@ -82,4 +82,6 @@
82 {% include "links/update_link.html" %} 82 {% include "links/update_link.html" %}
83 {% endif %} 83 {% endif %}
84 </div> 84 </div>
  85 + </div>
  86 + </div>
85 </div> 87 </div>
86 \ No newline at end of file 88 \ No newline at end of file
courses/templates/subject/form_view_teacher.html
1 {% load static i18n list_topic_foruns permission_tags widget_tweaks professor_access list_topic_exercises %} 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 <div class="panel panel-default cards-detail"> 5 <div class="panel panel-default cards-detail">
4 <div class="panel-heading topic"> 6 <div class="panel-heading topic">
5 <div class="row"> 7 <div class="row">
6 <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}}"> 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 </div> 10 </div>
9 <div class="col-xs-9 col-md-9 titleTopic"> 11 <div class="col-xs-9 col-md-9 titleTopic">
10 <a href="{% url 'course:view_topic' topic.slug %}" role="button"> 12 <a href="{% url 'course:view_topic' topic.slug %}" role="button">
@@ -32,7 +34,8 @@ @@ -32,7 +34,8 @@
32 </div> 34 </div>
33 </div> 35 </div>
34 </div> 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 <div class="panel-body"> 39 <div class="panel-body">
37 40
38 {# dados do tópico no modo de visualização #} 41 {# dados do tópico no modo de visualização #}
courses/templates/topic/index.html
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </button> 33 </button>
34 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions"> 34 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions">
35 <li> 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 </li> 37 </li>
38 <li> 38 <li>
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> 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,6 +34,7 @@ urlpatterns = [
34 url(r'^subjects/file-material-view/(?P<slug>[\w_-]+)/$', views.FileMaterialView.as_view(), name='file_material_view'), 34 url(r'^subjects/file-material-view/(?P<slug>[\w_-]+)/$', views.FileMaterialView.as_view(), name='file_material_view'),
35 url(r'^links/',include('links.urls',namespace = 'links')), 35 url(r'^links/',include('links.urls',namespace = 'links')),
36 url(r'^exercise/', include('exercise.urls', namespace='exercise')), 36 url(r'^exercise/', include('exercise.urls', namespace='exercise')),
  37 + url(r'^topic/(?P<topic>[\w_-]+)/$', views.topic_log, name='topic_log'),
37 url(r'^(?P<slug>[\w_-]+)/', include([ 38 url(r'^(?P<slug>[\w_-]+)/', include([
38 url(r'^$', views.CourseView.as_view(), name='view'), 39 url(r'^$', views.CourseView.as_view(), name='view'),
39 url(r'^(?P<category>[\w_-]+)/$', views.CourseView.as_view(), name='view_filter') 40 url(r'^(?P<category>[\w_-]+)/$', views.CourseView.as_view(), name='view_filter')
courses/views.py
1 from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm 1 from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm
2 from .models import Course, Subject, CourseCategory, Topic, SubjectCategory, Activity, CategorySubject 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 from core.mixins import LogMixin, NotificationMixin 4 from core.mixins import LogMixin, NotificationMixin
5 from core.models import Log 5 from core.models import Log
6 from courses.models import Material 6 from courses.models import Material
@@ -99,6 +99,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView): @@ -99,6 +99,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
99 list_courses = self.get_queryset().filter(students__in = [self.request.user]).order_by('name') 99 list_courses = self.get_queryset().filter(students__in = [self.request.user]).order_by('name')
100 100
101 context['categorys_courses'] = course_category(list_courses) 101 context['categorys_courses'] = course_category(list_courses)
  102 + context['title'] = _('Courses | Amadeus')
102 return context 103 return context
103 104
104 class AllCoursesView(LoginRequiredMixin, NotificationMixin, generic.ListView): 105 class AllCoursesView(LoginRequiredMixin, NotificationMixin, generic.ListView):
@@ -136,6 +137,7 @@ class AllCoursesView(LoginRequiredMixin, NotificationMixin, generic.ListView): @@ -136,6 +137,7 @@ class AllCoursesView(LoginRequiredMixin, NotificationMixin, generic.ListView):
136 list_courses = self.get_queryset() 137 list_courses = self.get_queryset()
137 138
138 context['categorys_courses'] = course_category(list_courses) 139 context['categorys_courses'] = course_category(list_courses)
  140 + context['title'] = _('All Courses | Amadeus')
139 141
140 return context 142 return context
141 143
@@ -161,7 +163,7 @@ class CreateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationM @@ -161,7 +163,7 @@ class CreateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationM
161 self.log_context['course_slug'] = self.object.slug 163 self.log_context['course_slug'] = self.object.slug
162 self.log_context['course_category_id'] = self.object.category.id 164 self.log_context['course_category_id'] = self.object.category.id
163 self.log_context['course_category_name'] = self.object.category.name 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 super(CreateCourseView, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context) 167 super(CreateCourseView, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
166 168
167 return super(CreateCourseView, self).form_valid(form) 169 return super(CreateCourseView, self).form_valid(form)
@@ -173,7 +175,7 @@ class CreateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationM @@ -173,7 +175,7 @@ class CreateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationM
173 elif has_role(self.request.user,'professor'): 175 elif has_role(self.request.user,'professor'):
174 courses = self.request.user.courses_student.all() 176 courses = self.request.user.courses_student.all()
175 context['courses'] = courses 177 context['courses'] = courses
176 - context['title'] = _("Create Course") 178 + context['title'] = _("Create Course | Amadeus")
177 context['now'] = date.today() 179 context['now'] = date.today()
178 return context 180 return context
179 181
@@ -215,7 +217,7 @@ class ReplicateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notificati @@ -215,7 +217,7 @@ class ReplicateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notificati
215 context['courses'] = courses 217 context['courses'] = courses
216 context['course'] = course 218 context['course'] = course
217 context['categorys_courses'] = categorys_courses 219 context['categorys_courses'] = categorys_courses
218 - context['title'] = _("Replicate Course") 220 + context['title'] = _("Replicate Course | Amadeus")
219 context['now'] = date.today() 221 context['now'] = date.today()
220 print (course.public) 222 print (course.public)
221 return context 223 return context
@@ -245,7 +247,6 @@ class UpdateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.Updat @@ -245,7 +247,6 @@ class UpdateCourseView(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.Updat
245 def form_valid(self, form): 247 def form_valid(self, form):
246 self.object = form.save() 248 self.object = form.save()
247 249
248 - print (form)  
249 self.log_context['course_id'] = self.object.id 250 self.log_context['course_id'] = self.object.id
250 self.log_context['course_name'] = self.object.name 251 self.log_context['course_name'] = self.object.name
251 self.log_context['course_slug'] = self.object.slug 252 self.log_context['course_slug'] = self.object.slug
@@ -453,6 +454,11 @@ class IndexCatView(LoginRequiredMixin, generic.ListView): @@ -453,6 +454,11 @@ class IndexCatView(LoginRequiredMixin, generic.ListView):
453 context_object_name = 'categories' 454 context_object_name = 'categories'
454 paginate_by = 10 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 class CreateCatView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView): 462 class CreateCatView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView):
457 463
458 allowed_roles = ['professor', 'system_admin'] 464 allowed_roles = ['professor', 'system_admin']
@@ -467,6 +473,12 @@ class CreateCatView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView): @@ -467,6 +473,12 @@ class CreateCatView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView):
467 messages.success(self.request, _('Category "%s" created successfully!')%(objeto)) 473 messages.success(self.request, _('Category "%s" created successfully!')%(objeto))
468 return reverse_lazy('course:manage_cat') 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 class UpdateCatView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView): 482 class UpdateCatView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView):
471 483
472 allowed_roles = ['professor', 'system_admin'] 484 allowed_roles = ['professor', 'system_admin']
@@ -482,6 +494,7 @@ class UpdateCatView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView): @@ -482,6 +494,7 @@ class UpdateCatView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView):
482 messages.success(self.request, _('Category "%s" updated successfully!')%(objeto)) 494 messages.success(self.request, _('Category "%s" updated successfully!')%(objeto))
483 #return reverse_lazy('course:update_cat', kwargs={'slug' : self.object.slug}) 495 #return reverse_lazy('course:update_cat', kwargs={'slug' : self.object.slug})
484 return reverse_lazy('course:manage_cat') 496 return reverse_lazy('course:manage_cat')
  497 +
485 class DeleteCatView(LoginRequiredMixin, HasRoleMixin, generic.DeleteView): 498 class DeleteCatView(LoginRequiredMixin, HasRoleMixin, generic.DeleteView):
486 499
487 allowed_roles = ['professor', 'system_admin'] 500 allowed_roles = ['professor', 'system_admin']
@@ -556,6 +569,7 @@ class SubjectsView(LoginRequiredMixin, LogMixin, generic.ListView): @@ -556,6 +569,7 @@ class SubjectsView(LoginRequiredMixin, LogMixin, generic.ListView):
556 context['subject'] = subject 569 context['subject'] = subject
557 context['topics'] = Topic.objects.filter(subject = subject) 570 context['topics'] = Topic.objects.filter(subject = subject)
558 context['exercise'] = Exercise.objects.filter(topic__subject=subject) 571 context['exercise'] = Exercise.objects.filter(topic__subject=subject)
  572 + context['title'] = subject.name
559 if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'): 573 if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'):
560 context['files'] = TopicFile.objects.filter(professor__name = self.request.user.name) 574 context['files'] = TopicFile.objects.filter(professor__name = self.request.user.name)
561 else: 575 else:
@@ -631,7 +645,7 @@ class TopicsView(LoginRequiredMixin, LogMixin, generic.ListView): @@ -631,7 +645,7 @@ class TopicsView(LoginRequiredMixin, LogMixin, generic.ListView):
631 activitys = Activity.objects.filter(topic__name = topic.name) 645 activitys = Activity.objects.filter(topic__name = topic.name)
632 students_activit = User.objects.filter(activities__in = Activity.objects.all()) 646 students_activit = User.objects.filter(activities__in = Activity.objects.all())
633 materials = Material.objects.filter(topic = topic) 647 materials = Material.objects.filter(topic = topic)
634 - 648 +
635 users = User.objects.filter(subject_student__in = Subject.objects.all()) 649 users = User.objects.filter(subject_student__in = Subject.objects.all())
636 context['users'] = users 650 context['users'] = users
637 exercises = Exercise.objects.filter(Q(students=self.request.user)|Q(professors=self.request.user)) 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,6 +658,7 @@ class TopicsView(LoginRequiredMixin, LogMixin, generic.ListView):
644 context['students_activit'] = students_activit 658 context['students_activit'] = students_activit
645 context['materials'] = materials 659 context['materials'] = materials
646 context['form'] = ActivityForm 660 context['form'] = ActivityForm
  661 + context['title'] = topic.name
647 662
648 return context 663 return context
649 664
@@ -669,6 +684,7 @@ class CreateTopicView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationMi @@ -669,6 +684,7 @@ class CreateTopicView(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationMi
669 context['course'] = subject.course 684 context['course'] = subject.course
670 context['subject'] = subject 685 context['subject'] = subject
671 context['subjects'] = subject.course.subjects.all() 686 context['subjects'] = subject.course.subjects.all()
  687 + context['title'] = _('Create Topic | Amadeus')
672 return context 688 return context
673 689
674 def form_valid(self, form): 690 def form_valid(self, form):
@@ -774,6 +790,7 @@ class CreateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notification @@ -774,6 +790,7 @@ class CreateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notification
774 context['subjects'] = course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user])) 790 context['subjects'] = course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user]))
775 if (has_role(self.request.user,'system_admin')): 791 if (has_role(self.request.user,'system_admin')):
776 context['subjects'] = course.subjects.all() 792 context['subjects'] = course.subjects.all()
  793 + context['title'] = _('Create Subject | Amadeus')
777 return context 794 return context
778 795
779 def form_valid(self, form): 796 def form_valid(self, form):
@@ -848,6 +865,7 @@ class UpdateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.Upda @@ -848,6 +865,7 @@ class UpdateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.Upda
848 context['course'] = self.object.course 865 context['course'] = self.object.course
849 context['subject'] = self.object 866 context['subject'] = self.object
850 context['subjects'] = self.object.course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user])) 867 context['subjects'] = self.object.course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user]))
  868 + context['title'] = self.object.name
851 if (has_role(self.request.user,'system_admin')): 869 if (has_role(self.request.user,'system_admin')):
852 context['subjects'] = self.object.course.subjects.all() 870 context['subjects'] = self.object.course.subjects.all()
853 return context 871 return context
@@ -970,6 +988,35 @@ class FileMaterialView(LoginRequiredMixin, LogMixin, generic.DetailView): @@ -970,6 +988,35 @@ class FileMaterialView(LoginRequiredMixin, LogMixin, generic.DetailView):
970 988
971 return super(FileMaterialView, self).dispatch(*args, **kwargs) 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 #API VIEWS 1021 #API VIEWS
975 class CourseViewSet(viewsets.ModelViewSet): 1022 class CourseViewSet(viewsets.ModelViewSet):
@@ -1011,6 +1058,7 @@ class ReplicateTopicView (LoginRequiredMixin, HasRoleMixin, LogMixin, Notificati @@ -1011,6 +1058,7 @@ class ReplicateTopicView (LoginRequiredMixin, HasRoleMixin, LogMixin, Notificati
1011 context['subject'] = subject 1058 context['subject'] = subject
1012 context['subjects'] = subject.course.subjects.all() 1059 context['subjects'] = subject.course.subjects.all()
1013 context['topic'] = topic 1060 context['topic'] = topic
  1061 + context['title'] = subject.name
1014 return context 1062 return context
1015 1063
1016 def form_valid(self, form): 1064 def form_valid(self, form):
@@ -1065,6 +1113,7 @@ class ReplicateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notificat @@ -1065,6 +1113,7 @@ class ReplicateSubjectView(LoginRequiredMixin, HasRoleMixin, LogMixin, Notificat
1065 context['course'] = course 1113 context['course'] = course
1066 context['subjects'] = course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user])) 1114 context['subjects'] = course.subjects.filter(Q(visible=True) | Q(professors__in=[self.request.user]))
1067 context['subject'] = subject 1115 context['subject'] = subject
  1116 + context['title'] = course.name
1068 if (has_role(self.request.user,'system_admin')): 1117 if (has_role(self.request.user,'system_admin')):
1069 context['subjects'] = course.subjects.all() 1118 context['subjects'] = course.subjects.all()
1070 return context 1119 return context
1 from django.contrib import admin 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 class ExamAdmin(admin.ModelAdmin): 5 class ExamAdmin(admin.ModelAdmin):
6 list_display = ['name', 'slug','begin_date','limit_date'] 6 list_display = ['name', 'slug','begin_date','limit_date']
@@ -17,3 +17,5 @@ class AnswersStudentAdmin(admin.ModelAdmin): @@ -17,3 +17,5 @@ class AnswersStudentAdmin(admin.ModelAdmin):
17 admin.site.register(Exam, ExamAdmin) 17 admin.site.register(Exam, ExamAdmin)
18 admin.site.register(Answer, AnswerAdmin) 18 admin.site.register(Answer, AnswerAdmin)
19 admin.site.register(AnswersStudent, AnswersStudentAdmin) 19 admin.site.register(AnswersStudent, AnswersStudentAdmin)
  20 +admin.site.register(Question)
  21 +admin.site.register(Alternative)
@@ -25,7 +25,7 @@ class ExamForm(forms.ModelForm): @@ -25,7 +25,7 @@ class ExamForm(forms.ModelForm):
25 25
26 class Meta: 26 class Meta:
27 model = Exam 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 widgets = { 30 widgets = {
31 'name': forms.TextInput(attrs={'placeholder': 'Exam?'}), 31 'name': forms.TextInput(attrs={'placeholder': 'Exam?'}),
exam/migrations/0003_auto_20161125_0808.py 0 → 100644
@@ -0,0 +1,28 @@ @@ -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,15 +6,17 @@ from core.models import Resource
6 from courses.models import Activity 6 from courses.models import Activity
7 7
8 class Exam(Activity): 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 class Answer(models.Model): 22 class Answer(models.Model):
@@ -43,3 +45,12 @@ class AnswersStudent(models.Model): @@ -43,3 +45,12 @@ class AnswersStudent(models.Model):
43 45
44 def __str__(self): 46 def __str__(self):
45 return str(self.student) + str("/") + str(self.exam) 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 \ No newline at end of file 57 \ No newline at end of file
exam/static/js/Exam.js
@@ -95,7 +95,7 @@ @@ -95,7 +95,7 @@
95 } 95 }
96 //Bug quando criamos sem ser na ordem 96 //Bug quando criamos sem ser na ordem
97 function functionNewAlternative(Question_Id){ 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 var element = '<div class="radio radio-primary form-group">' + 99 var element = '<div class="radio radio-primary form-group">' +
100 '<label>' + 100 '<label>' +
101 '<input type="radio" name="alternatives" id="alternative_'+alternative+'_'+Question_Id+'"' + 'value="'+alternative+'">' + 101 '<input type="radio" name="alternatives" id="alternative_'+alternative+'_'+Question_Id+'"' + 'value="'+alternative+'">' +
@@ -106,9 +106,9 @@ function functionNewAlternative(Question_Id){ @@ -106,9 +106,9 @@ function functionNewAlternative(Question_Id){
106 $.material.init() //O material deve ser iniciado aqui para funcionar os botoes de radio. 106 $.material.init() //O material deve ser iniciado aqui para funcionar os botoes de radio.
107 } 107 }
108 function functionNewAlternativeTF(Question_Id){ 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 var element = 110 var element =
111 - '<div class="radio form-group">'+ 111 + '<div class="radio radio-primary form-group" value="'+alternative+'">'+
112 '<label class="primary-label-TF" >'+ 112 '<label class="primary-label-TF" >'+
113 '<textarea class="form-control" rows="1" placeholder="Write your alternative"></textarea>'+ 113 '<textarea class="form-control" rows="1" placeholder="Write your alternative"></textarea>'+
114 '</label>'+ 114 '</label>'+
@@ -122,4 +122,9 @@ function functionNewAlternativeTF(Question_Id){ @@ -122,4 +122,9 @@ function functionNewAlternativeTF(Question_Id){
122 $(Question_Id).append(element); 122 $(Question_Id).append(element);
123 $('.primary-label-TF').css('padding-left', '0px'); 123 $('.primary-label-TF').css('padding-left', '0px');
124 $.material.init() //O material deve ser iniciado aqui para funcionar os botoes de radio. 124 $.material.init() //O material deve ser iniciado aqui para funcionar os botoes de radio.
125 -}  
126 \ No newline at end of file 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 \ No newline at end of file 132 \ No newline at end of file
exam/templates/exam/create.html
@@ -13,22 +13,40 @@ @@ -13,22 +13,40 @@
13 <h4 class="panel-title" id="exam-title">{% trans "Create a Exam" %}</h4> 13 <h4 class="panel-title" id="exam-title">{% trans "Create a Exam" %}</h4>
14 </div> 14 </div>
15 <div class="panel-body"> 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 </div> 48 </div>
31 - </div> 49 +
32 <div class="row form-group"> 50 <div class="row form-group">
33 <div class="col-md-10"> 51 <div class="col-md-10">
34 <div class="checkbox"> 52 <div class="checkbox">
@@ -38,6 +56,7 @@ @@ -38,6 +56,7 @@
38 </div> 56 </div>
39 </div> 57 </div>
40 </div> 58 </div>
  59 +
41 <div class="row form-group" id="buttonAddQuestion"> 60 <div class="row form-group" id="buttonAddQuestion">
42 <div class="col-md-10"> 61 <div class="col-md-10">
43 <button id="addQuestion" type="button" class="btn btn-raised btn-default">Add new question buton</button> 62 <button id="addQuestion" type="button" class="btn btn-raised btn-default">Add new question buton</button>
@@ -54,7 +73,6 @@ @@ -54,7 +73,6 @@
54 </div> 73 </div>
55 74
56 {% block javascript %} 75 {% block javascript %}
57 - <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>  
58 <script type="text/javascript"> 76 <script type="text/javascript">
59 //Insert Create select with question type 77 //Insert Create select with question type
60 var idQuestionType = 1; 78 var idQuestionType = 1;
links/image_crawler.py
1 from bs4 import BeautifulSoup 1 from bs4 import BeautifulSoup
2 from urllib.request import urlopen 2 from urllib.request import urlopen
  3 +from urllib.parse import urlparse
3 import urllib.request 4 import urllib.request
4 5
5 def make_soup(url): 6 def make_soup(url):
@@ -20,6 +21,8 @@ def get_images(url,slug): @@ -20,6 +21,8 @@ def get_images(url,slug):
20 return ("Use default image",downloaded) 21 return ("Use default image",downloaded)
21 images = [img for img in soup.findAll('img')] 22 images = [img for img in soup.findAll('img')]
22 image_links = [each.get('src') for each in images] 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 link_slug = slug 26 link_slug = slug
24 filename = '' 27 filename = ''
25 for each in image_links: 28 for each in image_links:
@@ -46,15 +49,25 @@ def get_images(url,slug): @@ -46,15 +49,25 @@ def get_images(url,slug):
46 filename = '.jpeg' 49 filename = '.jpeg'
47 if not booleano: 50 if not booleano:
48 continue 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 caminho = "links/static/images/" 52 caminho = "links/static/images/"
55 try: 53 try:
56 urllib.request.urlretrieve(each,"%s"%(caminho)+str(link_slug)+filename) 54 urllib.request.urlretrieve(each,"%s"%(caminho)+str(link_slug)+filename)
57 downloaded = True 55 downloaded = True
58 except Exception: 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 return filename,downloaded 73 return filename,downloaded
links/templates/links/view_link.html
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 <div class="card-block"> 14 <div class="card-block">
15 <b class="card-title">{{link.name}}</b><p></p> 15 <b class="card-title">{{link.name}}</b><p></p>
16 <p class="card-text"> </p><p>{{link.link_description}}</p> 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 </div> 18 </div>
19 </article> 19 </article>
20 <!-- .end Card --> 20 <!-- .end Card -->
users/locale/pt_BR/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid &quot;&quot; @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 msgstr "" 8 msgstr ""
9 "Project-Id-Version: PACKAGE VERSION\n" 9 "Project-Id-Version: PACKAGE VERSION\n"
10 "Report-Msgid-Bugs-To: \n" 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 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -217,7 +217,7 @@ msgstr &quot;Início&quot; @@ -217,7 +217,7 @@ msgstr &quot;Início&quot;
217 msgid "Manage Users" 217 msgid "Manage Users"
218 msgstr "Gerenciar Usuários" 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 msgid "Add User" 221 msgid "Add User"
222 msgstr "Adicionar usuário" 222 msgstr "Adicionar usuário"
223 223
@@ -313,28 +313,30 @@ msgstr &quot;CPF&quot; @@ -313,28 +313,30 @@ msgstr &quot;CPF&quot;
313 msgid "Birth date:" 313 msgid "Birth date:"
314 msgstr "Data de nascimento:" 314 msgstr "Data de nascimento:"
315 315
316 -#: .\views.py:70 .\views.py:103 316 +#: .\views.py:75 .\views.py:108
317 #, fuzzy 317 #, fuzzy
318 #| msgid "User" 318 #| msgid "User"
319 msgid "User " 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 #, fuzzy 331 #, fuzzy
324 #| msgid "User edited successfully!" 332 #| msgid "User edited successfully!"
325 msgid "User deleted Successfully!" 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 msgid "Profile edited successfully!" 337 msgid "Profile edited successfully!"
330 msgstr "Perfil editado com sucesso!" 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 #~ msgid "Administrador" 340 #~ msgid "Administrador"
339 #~ msgstr "Administrador" 341 #~ msgstr "Administrador"
340 342
users/templates/users/profile.html
@@ -11,12 +11,6 @@ @@ -11,12 +11,6 @@
11 11
12 {% endblock %} 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 {% block content %} 14 {% block content %}
21 {% if messages %} 15 {% if messages %}
22 {% for message in messages %} 16 {% for message in messages %}
users/views.py
@@ -45,6 +45,11 @@ class UsersListView(HasRoleMixin, LoginRequiredMixin, generic.ListView): @@ -45,6 +45,11 @@ class UsersListView(HasRoleMixin, LoginRequiredMixin, generic.ListView):
45 45
46 return users 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 class Create(HasRoleMixin, LoginRequiredMixin, generic.edit.CreateView): 53 class Create(HasRoleMixin, LoginRequiredMixin, generic.edit.CreateView):
49 54
50 allowed_roles = ['system_admin'] 55 allowed_roles = ['system_admin']
@@ -67,12 +72,12 @@ class Create(HasRoleMixin, LoginRequiredMixin, generic.edit.CreateView): @@ -67,12 +72,12 @@ class Create(HasRoleMixin, LoginRequiredMixin, generic.edit.CreateView):
67 72
68 self.object.save() 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 return super(Create, self).form_valid(form) 77 return super(Create, self).form_valid(form)
73 def get_context_data (self, **kwargs): 78 def get_context_data (self, **kwargs):
74 context = super(Create, self).get_context_data(**kwargs) 79 context = super(Create, self).get_context_data(**kwargs)
75 - context['title'] = _("Add User") 80 + context['title'] = "Add User | Amadeus"
76 return context 81 return context
77 82
78 class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView): 83 class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView):
@@ -100,10 +105,15 @@ class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView): @@ -100,10 +105,15 @@ class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView):
100 105
101 self.object.save() 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 return super(Update, self).form_valid(form) 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 class View(LoginRequiredMixin, generic.DetailView): 117 class View(LoginRequiredMixin, generic.DetailView):
108 118
109 login_url = reverse_lazy("core:home") 119 login_url = reverse_lazy("core:home")
@@ -114,6 +124,11 @@ class View(LoginRequiredMixin, generic.DetailView): @@ -114,6 +124,11 @@ class View(LoginRequiredMixin, generic.DetailView):
114 slug_field = 'username' 124 slug_field = 'username'
115 slug_url_kwarg = 'username' 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 def delete_user(request,username): 132 def delete_user(request,username):
118 user = get_object_or_404(User,username = username) 133 user = get_object_or_404(User,username = username)
119 user.delete() 134 user.delete()
@@ -129,9 +144,18 @@ def remove_account(request,username): @@ -129,9 +144,18 @@ def remove_account(request,username):
129 class Change_password(generic.TemplateView): 144 class Change_password(generic.TemplateView):
130 template_name = 'users/change_password.html' 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 class Remove_account(generic.TemplateView): 152 class Remove_account(generic.TemplateView):
133 template_name = 'users/remove_account.html' 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 class UpdateProfile(LoginRequiredMixin, generic.edit.UpdateView): 160 class UpdateProfile(LoginRequiredMixin, generic.edit.UpdateView):
137 login_url = reverse_lazy("core:home") 161 login_url = reverse_lazy("core:home")
@@ -145,6 +169,7 @@ class UpdateProfile(LoginRequiredMixin, generic.edit.UpdateView): @@ -145,6 +169,7 @@ class UpdateProfile(LoginRequiredMixin, generic.edit.UpdateView):
145 169
146 def get_context_data(self, **kwargs): 170 def get_context_data(self, **kwargs):
147 context = super(UpdateProfile, self).get_context_data(**kwargs) 171 context = super(UpdateProfile, self).get_context_data(**kwargs)
  172 + context['title'] = 'Update Profile | Amadeus'
148 if has_role(self.request.user, 'system_admin'): 173 if has_role(self.request.user, 'system_admin'):
149 context['form'] = UpdateProfileFormAdmin(instance = self.object) 174 context['form'] = UpdateProfileFormAdmin(instance = self.object)
150 else: 175 else:
@@ -179,6 +204,12 @@ class Profile(LoginRequiredMixin, generic.DetailView): @@ -179,6 +204,12 @@ class Profile(LoginRequiredMixin, generic.DetailView):
179 def get_object(self): 204 def get_object(self):
180 user = get_object_or_404(User, username = self.request.user.username) 205 user = get_object_or_404(User, username = self.request.user.username)
181 return user 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 class SearchView(LoginRequiredMixin, generic.ListView): 213 class SearchView(LoginRequiredMixin, generic.ListView):
183 214
184 login_url = reverse_lazy("core:home") 215 login_url = reverse_lazy("core:home")