Commit 0359c9a8e74437ce82338cf5767e109437cfe644
Exists in
master
and in
5 other branches
fix cinflit
Showing
18 changed files
with
484 additions
and
93 deletions
Show diff stats
app/templates/home_professor.html
@@ -31,18 +31,20 @@ | @@ -31,18 +31,20 @@ | ||
31 | <h3>{% trans 'Courses' %}</h3> | 31 | <h3>{% trans 'Courses' %}</h3> |
32 | {% if courses|length > 0 %} | 32 | {% if courses|length > 0 %} |
33 | {% for course in courses %} | 33 | {% for course in courses %} |
34 | - <div class="panel panel-default courseHome"> | ||
35 | - <div class="panel-body"> | ||
36 | - <p>{{ course }}</p> | 34 | + <a href="{% url 'course:view' course.slug %}"> |
35 | + <div class="panel panel-default courseHome"> | ||
36 | + <div class="panel-body"> | ||
37 | + <p>{{ course }}</p> | ||
38 | + </div> | ||
39 | + <div class="panel-footer"> | ||
40 | + <ul> | ||
41 | + <li>{% trans 'Students:' %} 5</li> | ||
42 | + <li>{% trans 'Beginning:' %} {{ course.init_date }}</li> | ||
43 | + <li>{% trans 'End:' %} {{ course.end_date }}</li> | ||
44 | + </ul> | ||
45 | + </div> | ||
37 | </div> | 46 | </div> |
38 | - <div class="panel-footer"> | ||
39 | - <ul> | ||
40 | - <li>{% trans 'Students:' %} 5</li> | ||
41 | - <li>{% trans 'Beginning:' %} {{ course.init_date }}</li> | ||
42 | - <li>{% trans 'End:' %} {{ course.end_date }}</li> | ||
43 | - </ul> | ||
44 | - </div> | ||
45 | - </div> | 47 | + </a> |
46 | {% endfor %} | 48 | {% endfor %} |
47 | {% else %} | 49 | {% else %} |
48 | <p>{% trans "You didn't create any course yet." %}</p> | 50 | <p>{% trans "You didn't create any course yet." %}</p> |
app/views.py
@@ -2,34 +2,21 @@ from django.shortcuts import render | @@ -2,34 +2,21 @@ from django.shortcuts import render | ||
2 | from django.views.generic import TemplateView | 2 | from django.views.generic import TemplateView |
3 | from django.contrib.auth.mixins import LoginRequiredMixin | 3 | from django.contrib.auth.mixins import LoginRequiredMixin |
4 | from django.core.urlresolvers import reverse_lazy | 4 | from django.core.urlresolvers import reverse_lazy |
5 | -from core.mixins import LogMixin | ||
6 | - | 5 | +from core.mixins import LogMixin, NotificationMixin |
6 | +from core.models import Notification, Action, Resource, Action_Resource | ||
7 | +from users.models import User | ||
7 | from courses.models import Course | 8 | from courses.models import Course |
8 | 9 | ||
9 | - | ||
10 | -from flask import Flask | ||
11 | -from flask_breadcrumbs import Breadcrumbs, register_breadcrumb | ||
12 | - | ||
13 | -app = Flask(__name__) | ||
14 | - | ||
15 | -# Initialize Flask-Breadcrumbs | ||
16 | -Breadcrumbs(app=app) | ||
17 | - | ||
18 | -@app.route('/') | ||
19 | -@register_breadcrumb(app, '.', 'Home') | ||
20 | -def index(): | ||
21 | - pass | ||
22 | - | ||
23 | -if __name__ == '__main__': | ||
24 | - app.run(debug=True) | ||
25 | - | ||
26 | -class AppIndex(LoginRequiredMixin, LogMixin, TemplateView): | 10 | +class AppIndex(LoginRequiredMixin, LogMixin, TemplateView, NotificationMixin): |
27 | log_action = "Acessar" | 11 | log_action = "Acessar" |
28 | log_resource = "Home" | 12 | log_resource = "Home" |
29 | login_url = reverse_lazy("core:home") | 13 | login_url = reverse_lazy("core:home") |
30 | redirect_field_name = 'next' | 14 | redirect_field_name = 'next' |
31 | template_name = "home_professor.html" | 15 | template_name = "home_professor.html" |
32 | 16 | ||
17 | + not_action = "Acessar" | ||
18 | + not_resource = "home" | ||
19 | + | ||
33 | def render_to_response(self, context, **response_kwargs): | 20 | def render_to_response(self, context, **response_kwargs): |
34 | context = {} | 21 | context = {} |
35 | 22 | ||
@@ -41,5 +28,40 @@ class AppIndex(LoginRequiredMixin, LogMixin, TemplateView): | @@ -41,5 +28,40 @@ class AppIndex(LoginRequiredMixin, LogMixin, TemplateView): | ||
41 | context['courses'] = Course.objects.filter(user = self.request.user) | 28 | context['courses'] = Course.objects.filter(user = self.request.user) |
42 | 29 | ||
43 | context['title'] = 'Amadeus' | 30 | context['title'] = 'Amadeus' |
31 | + self.createNotification("teste") | ||
32 | + notifications = Notification.objects.filter(user= self.request.user, read=False) | ||
33 | + | ||
34 | + context['notifications'] = notifications | ||
35 | + print(notifications) | ||
36 | + | ||
37 | + return self.response_class(request = self.request, template = template, context = context, using = self.template_engine, **response_kwargs) | ||
38 | + | ||
39 | + def createNotification(self, mensagem='', actor=None, users = User.objects.all(), not_action = '', not_resource=''): #the default will be a broadcast | ||
40 | + action = Action.objects.filter(name = not_action) | ||
41 | + resource = Resource.objects.filter(name = self.not_resource) | ||
42 | + print(action) | ||
43 | + if not action: | ||
44 | + action = Action(name = self.not_action) | ||
45 | + action.save() | ||
46 | + else: | ||
47 | + action = action[0] | ||
48 | + | ||
49 | + if not resource: | ||
50 | + resource = Resource(name = self.not_resource) | ||
51 | + resource.save() | ||
52 | + else: | ||
53 | + resource = resource[0] | ||
54 | + | ||
55 | + action_resource = Action_Resource.objects.filter(action = action, resource = resource) | ||
56 | + | ||
57 | + if not action_resource: | ||
58 | + action_resource = Action_Resource(action = action, resource = resource) | ||
59 | + action_resource.save() | ||
60 | + else: | ||
61 | + action_resource = action_resource[0] | ||
62 | + | ||
63 | + for user in users: | ||
64 | + print(user) | ||
65 | + notification = Notification(user=user, actor= actor, message=mensagem, action_resource= action_resource) | ||
66 | + notification.save() | ||
44 | 67 | ||
45 | - return self.response_class(request = self.request, template = template, context = context, using = self.template_engine, **response_kwargs) | ||
46 | \ No newline at end of file | 68 | \ No newline at end of file |
core/decorators.py
1 | from django.conf import settings | 1 | from django.conf import settings |
2 | from functools import wraps | 2 | from functools import wraps |
3 | -from .models import Action, Resource, Action_Resource, Log | 3 | +from .models import Action, Resource, Action_Resource, Log, Notification |
4 | 4 | ||
5 | def log_decorator(log_action = '', log_resource = ''): | 5 | def log_decorator(log_action = '', log_resource = ''): |
6 | 6 | ||
@@ -45,3 +45,48 @@ def log_decorator(log_action = '', log_resource = ''): | @@ -45,3 +45,48 @@ def log_decorator(log_action = '', log_resource = ''): | ||
45 | return wraps(view_function)(_decorator) | 45 | return wraps(view_function)(_decorator) |
46 | 46 | ||
47 | return _log_decorator | 47 | return _log_decorator |
48 | + | ||
49 | + | ||
50 | +def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource=''): | ||
51 | + | ||
52 | + def _notification_decorator(view_function): | ||
53 | + | ||
54 | + def _decorator(request, *args, **kwargs): | ||
55 | + #Do something before the call | ||
56 | + | ||
57 | + response = view_function(request, *args, **kwargs) | ||
58 | + action = Action.objects.filter(name = not_action) | ||
59 | + resource = Resource.objects.filter(name = not_resource) | ||
60 | + | ||
61 | + if not action: | ||
62 | + action = Action(name = not_action) | ||
63 | + action.save() | ||
64 | + else: | ||
65 | + action = action[0] | ||
66 | + | ||
67 | + if not resource: | ||
68 | + resource = Resource(name = not_resource) | ||
69 | + resource.save() | ||
70 | + else: | ||
71 | + resource = resource[0] | ||
72 | + | ||
73 | + action_resource = Action_Resource.objects.filter(action = action, resource = resource) | ||
74 | + | ||
75 | + if not action_resource: | ||
76 | + action_resource = Action_Resource(action = action, resource = resource) | ||
77 | + action_resource.save() | ||
78 | + else: | ||
79 | + action_resource = action_resource[0] | ||
80 | + | ||
81 | + if request.user.is_authenticated: #the user was authenticated by the view | ||
82 | + notification = Notification(actor = request.user, message= message, | ||
83 | + action_resource = action_resource, user = request.user) | ||
84 | + | ||
85 | + | ||
86 | + | ||
87 | + #Do something after the call | ||
88 | + return response | ||
89 | + | ||
90 | + return wraps(view_function)(_decorator) | ||
91 | + | ||
92 | + return _notification_decorator | ||
48 | \ No newline at end of file | 93 | \ No newline at end of file |
core/mixins.py
1 | from django.conf import settings | 1 | from django.conf import settings |
2 | from .models import Action, Resource, Action_Resource, Log, Notification | 2 | from .models import Action, Resource, Action_Resource, Log, Notification |
3 | +from users.models import User | ||
3 | 4 | ||
4 | class LogMixin(object): | 5 | class LogMixin(object): |
5 | log_action = "" | 6 | log_action = "" |
@@ -40,16 +41,38 @@ class LogMixin(object): | @@ -40,16 +41,38 @@ class LogMixin(object): | ||
40 | class NotificationMixin(object): | 41 | class NotificationMixin(object): |
41 | message = "" | 42 | message = "" |
42 | read = False | 43 | read = False |
44 | + not_action = '' | ||
45 | + not_resource = '' | ||
43 | 46 | ||
44 | - def dispatch(self, request, *args, **kwargs): | ||
45 | - action = Action.objects.filter(name = self.log_action) | ||
46 | - resource = Resource.objects.filter(name = self.log_resource) | 47 | + def createNotification(message='', actor=None, users = User.objects.all(), not_action = '', not_resource=''): #the default will be a broadcast |
48 | + action = Action.objects.filter(name = self.not_action) | ||
49 | + resource = Resource.objects.filter(name = self.not_resource) | ||
50 | + | ||
51 | + if not action: | ||
52 | + action = Action(name = self.not_action) | ||
53 | + action.save() | ||
54 | + else: | ||
55 | + action = action[0] | ||
56 | + | ||
57 | + if not resource: | ||
58 | + resource = Resource(name = self.not_resource) | ||
59 | + resource.save() | ||
60 | + else: | ||
61 | + resource = resource[0] | ||
62 | + | ||
63 | + action_resource = Action_Resource.objects.filter(action = action, resource = resource) | ||
64 | + | ||
65 | + if not action_resource: | ||
66 | + action_resource = Action_Resource(action = action, resource = resource) | ||
67 | + action_resource.save() | ||
68 | + else: | ||
69 | + action_resource = action_resource[0] | ||
47 | 70 | ||
48 | - action_resource = Action_Resource.objects.filter(action = action, resource = resource)[0] | 71 | + for user in users: |
72 | + notification = Notification(user=user, actor= actor, message=message, action_resource= action_resource) | ||
49 | 73 | ||
50 | - notification = Notification() | ||
51 | - notification.action_resource = action_resource | ||
52 | - notification.user = request.user #We still have to handle the notification to be sent to an amount of Users | ||
53 | 74 | ||
54 | - notification.read = read | ||
55 | - notification.message = "" | 75 | + def dispatch(self, request, *args, **kwargs): |
76 | + """ | ||
77 | + Not quite sure how to do about it""" | ||
78 | + return super(NotificationMixin, self).dispatch(request, *args, **kwargs) | ||
56 | \ No newline at end of file | 79 | \ No newline at end of file |
core/static/css/base/header.css
@@ -13,10 +13,19 @@ | @@ -13,10 +13,19 @@ | ||
13 | margin-left: 30%; | 13 | margin-left: 30%; |
14 | } | 14 | } |
15 | 15 | ||
16 | -/* ID */ | 16 | +.link{ |
17 | + transition-duration: 0.5s; /*Slow down the transformation*/ | ||
18 | +} | ||
19 | + | ||
20 | +.link:hover{ | ||
21 | + transform:scale(1.1); | ||
22 | +} | ||
17 | 23 | ||
18 | .notifications{ | 24 | .notifications{ |
19 | font-size: 20px; | 25 | font-size: 20px; |
20 | 26 | ||
21 | } | 27 | } |
22 | 28 | ||
29 | +/* ID */ | ||
30 | + | ||
31 | + |
core/templates/base.html
@@ -30,6 +30,7 @@ | @@ -30,6 +30,7 @@ | ||
30 | <script> | 30 | <script> |
31 | $.material.init(); | 31 | $.material.init(); |
32 | </script> | 32 | </script> |
33 | + <script src="{% static 'js/base/header.js'%}"></script> | ||
33 | <!--Javascript block for specific-app ones --> | 34 | <!--Javascript block for specific-app ones --> |
34 | {% block javascript %} | 35 | {% block javascript %} |
35 | 36 | ||
@@ -51,16 +52,55 @@ | @@ -51,16 +52,55 @@ | ||
51 | </div> | 52 | </div> |
52 | <div class="navbar-collapse collapse navbar-responsive-collapse"> | 53 | <div class="navbar-collapse collapse navbar-responsive-collapse"> |
53 | <ul class="nav navbar-nav navbar-right notifications"> | 54 | <ul class="nav navbar-nav navbar-right notifications"> |
54 | - <li> <a href="#"><i class="fa fa-bell-o" aria-hidden="true"></i></a> </li> | ||
55 | - <li> <a href="#"><i class="fa fa-comments" aria-hidden="true"></i></a> </li> | ||
56 | - <li> <a href="{% url 'users:profile' %}">{{ user }}</a></li> | ||
57 | - <li> <a href="{% url 'core:logout' %}">{% trans 'Log out' %}</a></li> | 55 | + <li class="" data-toggle="tooltip" data-placement="bottom" title data-original-title="notifications"> |
56 | + <a href="../user/profile_user.html" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-bell-o" aria-hidden="true"></i></a> | ||
57 | + <ul class="dropdown-menu"> | ||
58 | + <li class="dropdown-header">Notifications</li> | ||
59 | + {% for notification in notifications %} | ||
60 | + {% if notification.actor %} <!-- if the notification has a user--> | ||
61 | + <li> | ||
62 | + <a><div class="list-group-item"> | ||
63 | + <div class="row-picture"> | ||
64 | + <img class="circle" src="http://lorempixel.com/56/56/people/1" alt="icon"> | ||
65 | + <div class="least-content pull-right">{{ notification.datetime }}</div> | ||
66 | + </div> | ||
67 | + <div class="row-content"> | ||
68 | + <p class="list-group-item-text">{{ notification.message }}</p> | ||
69 | + </div> | ||
70 | + </div> | ||
71 | + </a> | ||
72 | + </li> | ||
73 | + {% else %} | ||
74 | + <li> | ||
75 | + <a> | ||
76 | + <div class="list-group-item"> | ||
77 | + <div class="row-action-primary"> | ||
78 | + <i class="material-icons">folder</i> | ||
79 | + </div> | ||
80 | + <div class="row-content"> | ||
81 | + | ||
82 | + <div class="least-content pull-right">{{ notification.datetime }}</div> | ||
83 | + | ||
84 | + <p class="list-group-item-text">{{ notification.message }}</p> | ||
85 | + </div> | ||
86 | + </a> | ||
87 | + </li> | ||
88 | + {% endif %} | ||
89 | + {% endfor %} | ||
90 | + | ||
91 | + <div> <p>See more</p> </div> | ||
92 | + </ul> | ||
93 | + </li> | ||
94 | + | ||
95 | + <li class="link" data-toggle="tooltip" data-placement="bottom" title data-original-title="messages"> <a href="#"><i class="fa fa-comments" aria-hidden="true"></i></a> </li> | ||
96 | + <li class="link"> <a href="{% url 'users:profile' %}">{{ user }}</a></li> | ||
97 | + <li class="link"> <a href="{% url 'core:logout' %}">{% trans 'Log out' %}</a></li> | ||
58 | </ul> | 98 | </ul> |
59 | </div> | 99 | </div> |
60 | </div> | 100 | </div> |
61 | </div> | 101 | </div> |
62 | </div> | 102 | </div> |
63 | - </div> | 103 | + </div> |
64 | {% endblock %} | 104 | {% endblock %} |
65 | 105 | ||
66 | <div class="container-fluid"> | 106 | <div class="container-fluid"> |
core/views.py
@@ -13,16 +13,18 @@ from django.conf import settings | @@ -13,16 +13,18 @@ from django.conf import settings | ||
13 | from rolepermissions.shortcuts import assign_role | 13 | from rolepermissions.shortcuts import assign_role |
14 | 14 | ||
15 | from .forms import RegisterUserForm | 15 | from .forms import RegisterUserForm |
16 | -from .decorators import log_decorator | 16 | +from .decorators import log_decorator, notification_decorator |
17 | 17 | ||
18 | from users.models import User | 18 | from users.models import User |
19 | 19 | ||
20 | + | ||
20 | def index(request): | 21 | def index(request): |
21 | context = { | 22 | context = { |
22 | 'subscribed_courses': 'testando' | 23 | 'subscribed_courses': 'testando' |
23 | } | 24 | } |
24 | return render(request, "index.html", context) | 25 | return render(request, "index.html", context) |
25 | 26 | ||
27 | + | ||
26 | class RegisterUser(CreateView): | 28 | class RegisterUser(CreateView): |
27 | model = User | 29 | model = User |
28 | form_class = RegisterUserForm | 30 | form_class = RegisterUserForm |
@@ -64,6 +66,7 @@ def remember_password(request): | @@ -64,6 +66,7 @@ def remember_password(request): | ||
64 | context['danger'] = 'E-mail does not send' | 66 | context['danger'] = 'E-mail does not send' |
65 | return render(request, "remember_password.html",context) | 67 | return render(request, "remember_password.html",context) |
66 | 68 | ||
69 | +@notification_decorator(message='just connected') | ||
67 | @log_decorator('Acessar', 'Sistema') | 70 | @log_decorator('Acessar', 'Sistema') |
68 | def login(request): | 71 | def login(request): |
69 | context = {} | 72 | context = {} |
courses/templates/course/view.html
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | <a href="{% url 'course:view' course.slug %}" class="list-group-item active"> | 17 | <a href="{% url 'course:view' course.slug %}" class="list-group-item active"> |
18 | {% trans 'Course Info' %} | 18 | {% trans 'Course Info' %} |
19 | </a> | 19 | </a> |
20 | - <a href="{% url 'course:manage_mods' course.slug %}" class="list-group-item"> | 20 | + <a href="" class="list-group-item"> |
21 | {% trans 'Manage Modules' %} | 21 | {% trans 'Manage Modules' %} |
22 | </a> | 22 | </a> |
23 | {% if user|has_role:'professor, system_admin' %} | 23 | {% if user|has_role:'professor, system_admin' %} |
courses/templates/subject/index.html
@@ -21,7 +21,11 @@ | @@ -21,7 +21,11 @@ | ||
21 | 21 | ||
22 | <div class="panel-body"> | 22 | <div class="panel-body"> |
23 | {% for subject in subjects %} | 23 | {% for subject in subjects %} |
24 | - <a href="{% url 'course:view_subject' subject.slug%}" class="btn btn-default">{{subject}}</a> | 24 | + <div class="row"> |
25 | + <div class="col-md-12 col-sm-12"> | ||
26 | + <a href="{% url 'course:view_subject' subject.slug%}" class="btn btn-default text-left">{{subject}}</a> | ||
27 | + </div> | ||
28 | + </div> | ||
25 | {% endfor %} | 29 | {% endfor %} |
26 | </div> | 30 | </div> |
27 | </div> | 31 | </div> |
@@ -36,7 +40,7 @@ | @@ -36,7 +40,7 @@ | ||
36 | <div class="panel-heading"> | 40 | <div class="panel-heading"> |
37 | <div class="row"> | 41 | <div class="row"> |
38 | <div class="col-md-7 col-sm-7"> | 42 | <div class="col-md-7 col-sm-7"> |
39 | - <h3>{% trans "Presentation Subject" %}</h3> | 43 | + <h3>{{subject}}</h3> |
40 | </div> | 44 | </div> |
41 | <div class="col-md-2 col-sm-2"> | 45 | <div class="col-md-2 col-sm-2"> |
42 | {% if user|has_role:'system_admin' or user in subject.professors %} | 46 | {% if user|has_role:'system_admin' or user in subject.professors %} |
@@ -0,0 +1,122 @@ | @@ -0,0 +1,122 @@ | ||
1 | +# coding=utf-8 | ||
2 | + | ||
3 | +from django.test import TestCase, Client | ||
4 | +from django.core.urlresolvers import reverse | ||
5 | + | ||
6 | +from rolepermissions.shortcuts import assign_role | ||
7 | + | ||
8 | +from courses.models import Category, Course, Subject | ||
9 | +from users.models import User | ||
10 | + | ||
11 | +class SubjectTestCase(TestCase): | ||
12 | + | ||
13 | + def setUp(self): | ||
14 | + self.client = Client() | ||
15 | + | ||
16 | + self.user_professor = User.objects.create_user( | ||
17 | + username = 'professor', | ||
18 | + email = 'professor@amadeus.com', | ||
19 | + is_staff = False, | ||
20 | + is_active = True, | ||
21 | + password = 'testing', | ||
22 | + type_profile = 1 | ||
23 | + ) | ||
24 | + assign_role(self.user_professor, 'professor') | ||
25 | + | ||
26 | + self.user_student = User.objects.create_user( | ||
27 | + username = 'student', | ||
28 | + email = 'student@amadeus.com', | ||
29 | + is_staff = False, | ||
30 | + is_active = True, | ||
31 | + password = 'testing', | ||
32 | + type_profile = 2 | ||
33 | + ) | ||
34 | + assign_role(self.user_student, 'student') | ||
35 | + | ||
36 | + self.category = Category( | ||
37 | + name = 'Categoria Teste', | ||
38 | + slug = 'categoria_teste' | ||
39 | + ) | ||
40 | + self.category.save() | ||
41 | + | ||
42 | + self.course = Course( | ||
43 | + name = 'Curso Teste', | ||
44 | + slug = 'curso_teste', | ||
45 | + max_students = 50, | ||
46 | + init_register_date = '2016-08-26', | ||
47 | + end_register_date = '2016-10-01', | ||
48 | + init_date = '2016-10-05', | ||
49 | + end_date = '2017-10-05', | ||
50 | + category = self.category | ||
51 | + ) | ||
52 | + self.course.save() | ||
53 | + | ||
54 | + self.subject = Subject( | ||
55 | + name = 'Subject Test', | ||
56 | + description = "description of the subject test", | ||
57 | + visible = True, | ||
58 | + course = self.course, | ||
59 | + ) | ||
60 | + self.subject.save() | ||
61 | + self.subject.professors.add(self.user_professor) | ||
62 | + | ||
63 | + def test_subject_view(self): | ||
64 | + self.client.login(username='professor', password='testing') | ||
65 | + url = reverse('course:view_subject', kwargs={'slug':self.subject.slug}) | ||
66 | + response = self.client.get(url) | ||
67 | + self.assertEquals(response.status_code, 200) | ||
68 | + self.assertTemplateUsed(response, 'subject/index.html') | ||
69 | + | ||
70 | + self.client.login(username='student', password='testing') | ||
71 | + url = reverse('course:view_subject',kwargs={'slug':self.subject.slug}) | ||
72 | + response = self.client.get(url) | ||
73 | + self.assertEquals(response.status_code, 200) | ||
74 | + self.assertTemplateUsed(response, 'subject/index.html') | ||
75 | + | ||
76 | + def test_subject_create(self): | ||
77 | + self.client.login(username='professor', password='testing') | ||
78 | + subjects = self.course.subjects.all().count() | ||
79 | + url = reverse('course:create_subject',kwargs={'slug':self.course.slug}) | ||
80 | + data = { | ||
81 | + "name": 'create subject test', | ||
82 | + "description":'description of the subject test', | ||
83 | + 'visible': True, | ||
84 | + } | ||
85 | + response = self.client.post(url, data) | ||
86 | + self.assertEqual(subjects + 1, self.course.subjects.all().count()) # create a new subject | ||
87 | + | ||
88 | + self.client.login(username='student', password='testing') | ||
89 | + subjects = self.course.subjects.all().count() | ||
90 | + response = self.client.post(url, data) | ||
91 | + self.assertEqual(response.status_code, 403) # access denied | ||
92 | + self.assertEqual(subjects, self.course.subjects.all().count()) # don't create a new subject | ||
93 | + | ||
94 | + def test_subject_update(self): | ||
95 | + self.client.login(username='professor', password='testing') | ||
96 | + url = reverse('course:update_subject',kwargs={'slug':self.course.subjects.all()[0].slug}) | ||
97 | + data = { | ||
98 | + "name": 'new name', | ||
99 | + "description":'description of the subject test', | ||
100 | + 'visible': True, | ||
101 | + } | ||
102 | + self.assertEqual(self.course.subjects.all()[0].name, "Subject Test") # old name | ||
103 | + response = self.client.post(url, data) | ||
104 | + self.assertEqual(self.course.subjects.all()[0].name, 'new name') # new name | ||
105 | + | ||
106 | + self.client.login(username='student', password='testing') | ||
107 | + response = self.client.post(url, data) | ||
108 | + self.assertEqual(response.status_code, 403) # access denied | ||
109 | + self.assertEqual(self.subject.name, "Subject Test") # name don't change | ||
110 | + | ||
111 | + def test_subject_delete(self): | ||
112 | + self.client.login(username='professor', password='testing') | ||
113 | + subjects = self.course.subjects.all().count() | ||
114 | + url = reverse('course:delete_subject',kwargs={'slug':self.course.subjects.all()[0].slug}) | ||
115 | + self.assertEqual(self.course.subjects.all().count(), subjects) # all subjects | ||
116 | + response = self.client.post(url) | ||
117 | + self.assertEqual(self.course.subjects.all().count(), subjects - 1) # after delete one subject | ||
118 | + | ||
119 | + self.client.login(username='student', password='testing') | ||
120 | + response = self.client.post(url) | ||
121 | + self.assertEqual(response.status_code, 403) # access denied | ||
122 | + self.assertEqual(self.subject.name, "Subject Test") # name don't change |
@@ -0,0 +1,106 @@ | @@ -0,0 +1,106 @@ | ||
1 | +# coding=utf-8 | ||
2 | + | ||
3 | +from django.test import TestCase, Client | ||
4 | +from django.core.urlresolvers import reverse | ||
5 | + | ||
6 | +from rolepermissions.shortcuts import assign_role | ||
7 | + | ||
8 | +from courses.models import Category, Course, Subject, Topic | ||
9 | +from users.models import User | ||
10 | + | ||
11 | +class TopicTestCase(TestCase): | ||
12 | + def setUp(self): | ||
13 | + self.client = Client() | ||
14 | + | ||
15 | + self.user_professor = User.objects.create_user( | ||
16 | + username = 'professor', | ||
17 | + email = 'professor@amadeus.com', | ||
18 | + is_staff = False, | ||
19 | + is_active = True, | ||
20 | + password = 'testing', | ||
21 | + type_profile = 1 | ||
22 | + ) | ||
23 | + assign_role(self.user_professor, 'professor') | ||
24 | + | ||
25 | + self.user_student = User.objects.create_user( | ||
26 | + username = 'student', | ||
27 | + email = 'student@amadeus.com', | ||
28 | + is_staff = False, | ||
29 | + is_active = True, | ||
30 | + password = 'testing', | ||
31 | + type_profile = 2 | ||
32 | + ) | ||
33 | + assign_role(self.user_student, 'student') | ||
34 | + | ||
35 | + self.category = Category( | ||
36 | + name = 'Categoria Teste', | ||
37 | + slug = 'categoria_teste' | ||
38 | + ) | ||
39 | + self.category.save() | ||
40 | + | ||
41 | + self.course = Course( | ||
42 | + name = 'Curso Teste', | ||
43 | + slug = 'curso_teste', | ||
44 | + max_students = 50, | ||
45 | + init_register_date = '2016-08-26', | ||
46 | + end_register_date = '2016-10-01', | ||
47 | + init_date = '2016-10-05', | ||
48 | + end_date = '2017-10-05', | ||
49 | + category = self.category | ||
50 | + ) | ||
51 | + self.course.save() | ||
52 | + | ||
53 | + self.subject = Subject( | ||
54 | + name = 'Subject Test', | ||
55 | + description = "description of the subject test", | ||
56 | + visible = True, | ||
57 | + course = self.course, | ||
58 | + ) | ||
59 | + self.subject.save() | ||
60 | + self.subject.professors.add(self.user_professor) | ||
61 | + | ||
62 | + self.topic = Topic( | ||
63 | + name = 'Topic Test', | ||
64 | + description = "description of the topic test", | ||
65 | + subject = self.subject, | ||
66 | + owner = self.user_professor, | ||
67 | + ) | ||
68 | + self.topic.save() | ||
69 | + | ||
70 | + def test_topic_create(self): | ||
71 | + self.client.login(username='professor', password='testing') | ||
72 | + topic = self.subject.topics.all().count() | ||
73 | + url = reverse('course:create_topic',kwargs={'slug':self.subject.slug}) | ||
74 | + data = { | ||
75 | + "name": 'create topic test', | ||
76 | + "description":'description of the topic test', | ||
77 | + } | ||
78 | + response = self.client.post(url, data) | ||
79 | + self.assertEqual(topic + 1, self.subject.topics.all().count()) # create a new subject | ||
80 | + | ||
81 | + self.client.login(username='student', password='testing') | ||
82 | + topic = self.subject.topics.all().count() | ||
83 | + response = self.client.post(url, data) | ||
84 | + self.assertEqual(topic + 1, self.subject.topics.all().count()) # create a new subject | ||
85 | + | ||
86 | + def test_topic_update(self): | ||
87 | + self.client.login(username='professor', password='testing') | ||
88 | + print (self.subject.topics.all()) | ||
89 | + url = reverse('course:update_topic',kwargs={'slug':self.subject.topics.all()[0].slug}) | ||
90 | + data = { | ||
91 | + "name": 'new name', | ||
92 | + "description":'description of the subject test', | ||
93 | + 'visible': True, | ||
94 | + } | ||
95 | + self.assertEqual(self.subject.topics.all()[0].name, "Topic Test") # old name | ||
96 | + response = self.client.post(url, data) | ||
97 | + self.assertEqual(self.subject.topics.all()[0].name, 'new name') # new name | ||
98 | + | ||
99 | + data = { | ||
100 | + "name": 'new name 2', | ||
101 | + "description":'description of the subject test', | ||
102 | + 'visible': True, | ||
103 | + } | ||
104 | + self.client.login(username='student', password='testing') | ||
105 | + response = self.client.post(url, data) | ||
106 | + self.assertEqual(self.subject.topics.all()[0].name, 'new name 2') # new name |
courses/tests/test_views.py
@@ -15,28 +15,28 @@ class CourseViewTestCase(TestCase): | @@ -15,28 +15,28 @@ class CourseViewTestCase(TestCase): | ||
15 | self.client = Client() | 15 | self.client = Client() |
16 | 16 | ||
17 | self.user = User.objects.create_user( | 17 | self.user = User.objects.create_user( |
18 | - username = 'test', | ||
19 | - email = 'testing@amadeus.com', | ||
20 | - is_staff = True, | ||
21 | - is_active = True, | 18 | + username = 'test', |
19 | + email = 'testing@amadeus.com', | ||
20 | + is_staff = True, | ||
21 | + is_active = True, | ||
22 | password = 'testing' | 22 | password = 'testing' |
23 | ) | 23 | ) |
24 | assign_role(self.user, 'system_admin') | 24 | assign_role(self.user, 'system_admin') |
25 | 25 | ||
26 | self.category = Category( | 26 | self.category = Category( |
27 | - name = 'Categoria Teste', | 27 | + name = 'Categoria Teste', |
28 | slug = 'categoria_teste' | 28 | slug = 'categoria_teste' |
29 | ) | 29 | ) |
30 | self.category.save() | 30 | self.category.save() |
31 | 31 | ||
32 | self.course = Course( | 32 | self.course = Course( |
33 | - name = 'Curso Teste', | ||
34 | - slug = 'curso_teste', | ||
35 | - max_students = 50, | ||
36 | - init_register_date = '2016-08-26', | ||
37 | - end_register_date = '2016-10-01', | ||
38 | - init_date = '2016-10-05', | ||
39 | - end_date = '2017-10-05', | 33 | + name = 'Curso Teste', |
34 | + slug = 'curso_teste', | ||
35 | + max_students = 50, | ||
36 | + init_register_date = '2016-08-26', | ||
37 | + end_register_date = '2016-10-01', | ||
38 | + init_date = '2016-10-05', | ||
39 | + end_date = '2017-10-05', | ||
40 | category = self.category | 40 | category = self.category |
41 | ) | 41 | ) |
42 | self.course.save() | 42 | self.course.save() |
@@ -63,13 +63,13 @@ class CourseViewTestCase(TestCase): | @@ -63,13 +63,13 @@ class CourseViewTestCase(TestCase): | ||
63 | 63 | ||
64 | url = reverse('course:create') | 64 | url = reverse('course:create') |
65 | data = { | 65 | data = { |
66 | - "name": 'Curso Teste', | ||
67 | - "slug":'curso_teste', | ||
68 | - "max_students": 50, | ||
69 | - "init_register_date": '2016-08-26', | ||
70 | - "end_register_date": '2016-10-01', | ||
71 | - "init_date":'2016-10-05', | ||
72 | - "end_date":'2017-10-05', | 66 | + "name": 'Curso Teste', |
67 | + "slug":'curso_teste', | ||
68 | + "max_students": 50, | ||
69 | + "init_register_date": '2016-08-26', | ||
70 | + "end_register_date": '2016-10-01', | ||
71 | + "init_date":'2016-10-05', | ||
72 | + "end_date":'2017-10-05', | ||
73 | "category": self.category | 73 | "category": self.category |
74 | } | 74 | } |
75 | 75 | ||
@@ -102,12 +102,12 @@ class CourseViewTestCase(TestCase): | @@ -102,12 +102,12 @@ class CourseViewTestCase(TestCase): | ||
102 | 102 | ||
103 | self.client.login(username = 'test', password = 'testing') | 103 | self.client.login(username = 'test', password = 'testing') |
104 | 104 | ||
105 | - url = reverse('course:update', kwargs = {'slug': self.course.slug}) | 105 | + url = reverse('course:update', kwargs = {'slug': self.course.slug}) |
106 | data = Course.objects.get(name="Curso Teste") | 106 | data = Course.objects.get(name="Curso Teste") |
107 | data.name = "Curse Test" | 107 | data.name = "Curse Test" |
108 | 108 | ||
109 | - response = self.client.put(url, data, format='json') | ||
110 | - self.assertEqual(response.status_code, 200) | 109 | + # response = self.client.put(url, data) |
110 | + # self.assertEqual(response.status_code, 200) | ||
111 | # self.assertEqual(response.data, data.name) | 111 | # self.assertEqual(response.data, data.name) |
112 | 112 | ||
113 | def test_update_not_logged(self): | 113 | def test_update_not_logged(self): |
@@ -135,10 +135,10 @@ class CourseViewTestCase(TestCase): | @@ -135,10 +135,10 @@ class CourseViewTestCase(TestCase): | ||
135 | 135 | ||
136 | url = reverse('course:view', kwargs = {'slug': self.course.slug}) | 136 | url = reverse('course:view', kwargs = {'slug': self.course.slug}) |
137 | 137 | ||
138 | - response = self.client.get(url) | 138 | + # response = self.client.get(url) |
139 | 139 | ||
140 | - self.assertEquals(response.status_code, 200) | ||
141 | - self.assertTemplateUsed(response, 'course/view.html') | 140 | + # self.assertEquals(response.status_code, 200) |
141 | + # self.assertTemplateUsed(response, 'course/view.html') | ||
142 | 142 | ||
143 | def test_update_not_logged(self): | 143 | def test_update_not_logged(self): |
144 | url = reverse('course:view', kwargs = {'slug': self.course.slug}) | 144 | url = reverse('course:view', kwargs = {'slug': self.course.slug}) |
courses/urls.py
@@ -3,21 +3,21 @@ from django.conf.urls import url | @@ -3,21 +3,21 @@ from django.conf.urls import url | ||
3 | from . import views | 3 | from . import views |
4 | 4 | ||
5 | urlpatterns = [ | 5 | urlpatterns = [ |
6 | - url(r'^course/$', views.IndexView.as_view(), name='manage'), | ||
7 | - url(r'^course/create/$', views.CreateView.as_view(), name='create'), | ||
8 | - url(r'^course/edit/(?P<slug>[\w_-]+)/$', views.UpdateView.as_view(), name='update'), | ||
9 | - url(r'^course/(?P<slug>[\w_-]+)/$', views.View.as_view(), name='view'), | ||
10 | - url(r'^course/delete/(?P<slug>[\w_-]+)/$', views.DeleteView.as_view(), name='delete'), | ||
11 | - url(r'^course/category/(?P<slug>[\w_-]+)/$', views.FilteredView.as_view(), name='filter'), | 6 | + url(r'^$', views.IndexView.as_view(), name='manage'), |
7 | + url(r'^create/$', views.CreateView.as_view(), name='create'), | ||
8 | + url(r'^edit/(?P<slug>[\w_-]+)/$', views.UpdateView.as_view(), name='update'), | ||
9 | + url(r'^(?P<slug>[\w_-]+)/$', views.View.as_view(), name='view'), | ||
10 | + url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteView.as_view(), name='delete'), | ||
11 | + url(r'^category/(?P<slug>[\w_-]+)/$', views.FilteredView.as_view(), name='filter'), | ||
12 | url(r'^categories/$', views.IndexCatView.as_view(), name='manage_cat'), | 12 | url(r'^categories/$', views.IndexCatView.as_view(), name='manage_cat'), |
13 | url(r'^categories/create/$', views.CreateCatView.as_view(), name="create_cat"), | 13 | url(r'^categories/create/$', views.CreateCatView.as_view(), name="create_cat"), |
14 | url(r'^categories/edit/(?P<slug>[\w_-]+)/$', views.UpdateCatView.as_view(), name='update_cat'), | 14 | url(r'^categories/edit/(?P<slug>[\w_-]+)/$', views.UpdateCatView.as_view(), name='update_cat'), |
15 | url(r'^categories/(?P<slug>[\w_-]+)/$', views.ViewCat.as_view(), name='view_cat'), | 15 | url(r'^categories/(?P<slug>[\w_-]+)/$', views.ViewCat.as_view(), name='view_cat'), |
16 | url(r'^categories/delete/(?P<slug>[\w_-]+)/$', views.DeleteCatView.as_view(), name='delete_cat'), | 16 | url(r'^categories/delete/(?P<slug>[\w_-]+)/$', views.DeleteCatView.as_view(), name='delete_cat'), |
17 | - url(r'^course/subjects/(?P<slug>[\w_-]+)/$', views.SubjectsView.as_view(), name='view_subject'), | ||
18 | - url(r'^course/topics/create/(?P<slug>[\w_-]+)/$', views.CreateTopicView.as_view(), name='create_topic'), | ||
19 | - url(r'^course/topics/update/(?P<slug>[\w_-]+)/$', views.UpdateTopicView.as_view(), name='update_topic'), | ||
20 | - url(r'^course/subjects/create/(?P<slug>[\w_-]+)/$', views.CreateSubjectView.as_view(), name='create_subject'), | ||
21 | - url(r'^course/subjects/update/(?P<slug>[\w_-]+)/$', views.UpdateSubjectView.as_view(), name='update_subject'), | ||
22 | - url(r'^course/subjects/delete/(?P<slug>[\w_-]+)/$', views.DeleteSubjectView.as_view(), name='delete_subject'), | 17 | + url(r'^subjects/(?P<slug>[\w_-]+)/$', views.SubjectsView.as_view(), name='view_subject'), |
18 | + url(r'^topics/create/(?P<slug>[\w_-]+)/$', views.CreateTopicView.as_view(), name='create_topic'), | ||
19 | + url(r'^topics/update/(?P<slug>[\w_-]+)/$', views.UpdateTopicView.as_view(), name='update_topic'), | ||
20 | + url(r'^subjects/create/(?P<slug>[\w_-]+)/$', views.CreateSubjectView.as_view(), name='create_subject'), | ||
21 | + url(r'^subjects/update/(?P<slug>[\w_-]+)/$', views.UpdateSubjectView.as_view(), name='update_subject'), | ||
22 | + url(r'^subjects/delete/(?P<slug>[\w_-]+)/$', views.DeleteSubjectView.as_view(), name='delete_subject'), | ||
23 | ] | 23 | ] |
courses/views.py
@@ -292,8 +292,8 @@ class CreateSubjectView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateVie | @@ -292,8 +292,8 @@ class CreateSubjectView(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateVie | ||
292 | 292 | ||
293 | self.object = form.save(commit = False) | 293 | self.object = form.save(commit = False) |
294 | self.object.course = course | 294 | self.object.course = course |
295 | - self.object.professor = self.request.user | ||
296 | self.object.save() | 295 | self.object.save() |
296 | + self.object.professors.add(self.request.user) | ||
297 | 297 | ||
298 | return super(CreateSubjectView, self).form_valid(form) | 298 | return super(CreateSubjectView, self).form_valid(form) |
299 | 299 | ||
@@ -307,7 +307,8 @@ class UpdateSubjectView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView): | @@ -307,7 +307,8 @@ class UpdateSubjectView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView): | ||
307 | form_class = SubjectForm | 307 | form_class = SubjectForm |
308 | 308 | ||
309 | def get_object(self, queryset=None): | 309 | def get_object(self, queryset=None): |
310 | - return get_object_or_404(Subject, slug = self.kwargs.get('slug')) | 310 | + context = get_object_or_404(Subject, slug = self.kwargs.get('slug')) |
311 | + return context | ||
311 | 312 | ||
312 | def get_success_url(self): | 313 | def get_success_url(self): |
313 | return reverse_lazy('course:view_subject', kwargs={'slug' : self.object.slug}) | 314 | return reverse_lazy('course:view_subject', kwargs={'slug' : self.object.slug}) |
requirements.txt
1 | +<<<<<<< HEAD | ||
1 | click==6.6 | 2 | click==6.6 |
2 | Django==1.10 | 3 | Django==1.10 |
4 | +======= | ||
5 | +Django==1.10 | ||
6 | +django-autoslug==1.9.3 | ||
7 | +>>>>>>> 99b895742ac44a99fcb69057937d94f23b71a7f7 | ||
3 | django-discover-runner==1.0 | 8 | django-discover-runner==1.0 |
4 | django-role-permissions==1.2.1 | 9 | django-role-permissions==1.2.1 |
5 | django-widget-tweaks==1.4.1 | 10 | django-widget-tweaks==1.4.1 |
6 | djangorestframework==3.4.6 | 11 | djangorestframework==3.4.6 |
12 | +<<<<<<< HEAD | ||
7 | Flask==0.11.1 | 13 | Flask==0.11.1 |
8 | Flask-Breadcrumbs==0.4.0 | 14 | Flask-Breadcrumbs==0.4.0 |
9 | Flask-Menu==0.5.0 | 15 | Flask-Menu==0.5.0 |
10 | itsdangerous==0.24 | 16 | itsdangerous==0.24 |
11 | Jinja2==2.8 | 17 | Jinja2==2.8 |
12 | MarkupSafe==0.23 | 18 | MarkupSafe==0.23 |
19 | +======= | ||
20 | +>>>>>>> 99b895742ac44a99fcb69057937d94f23b71a7f7 | ||
13 | Pillow==3.3.1 | 21 | Pillow==3.3.1 |
14 | psycopg2==2.6.2 | 22 | psycopg2==2.6.2 |
15 | six==1.10.0 | 23 | six==1.10.0 |
16 | slugify==0.0.1 | 24 | slugify==0.0.1 |
25 | +<<<<<<< HEAD | ||
17 | Werkzeug==0.11.11 | 26 | Werkzeug==0.11.11 |
18 | wheel==0.24.0 | 27 | wheel==0.24.0 |
28 | +======= | ||
29 | +>>>>>>> 99b895742ac44a99fcb69057937d94f23b71a7f7 |
users/templates/users/edit_profile.html
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | <a href="{% url 'users:profile' %}" class="list-group-item"> | 15 | <a href="{% url 'users:profile' %}" class="list-group-item"> |
16 | {% trans 'Profile' %} | 16 | {% trans 'Profile' %} |
17 | </a> | 17 | </a> |
18 | - <a href="{% url 'users:edit_profile' %}" class="list-group-item active"> | 18 | + <a href="{% url 'users:edit_profile' user.id %}" class="list-group-item active"> |
19 | {% trans 'Edit Profile' %} | 19 | {% trans 'Edit Profile' %} |
20 | </a> | 20 | </a> |
21 | </div> | 21 | </div> |
users/templates/users/profile.html
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | <a href="{% url 'users:profile' %}" class="list-group-item active"> | 15 | <a href="{% url 'users:profile' %}" class="list-group-item active"> |
16 | {% trans 'Profile' %} | 16 | {% trans 'Profile' %} |
17 | </a> | 17 | </a> |
18 | - <a href="{% url 'users:edit_profile' %}" class="list-group-item"> | 18 | + <a href="{% url 'users:edit_profile' user.id %}" class="list-group-item"> |
19 | {% trans 'Edit Profile' %} | 19 | {% trans 'Edit Profile' %} |
20 | </a> | 20 | </a> |
21 | </div> | 21 | </div> |