Commit 0359c9a8e74437ce82338cf5767e109437cfe644

Authored by Ailson da Cruz
2 parents 0e455143 99b89574

fix cinflit

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>
@@ -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 = &#39;&#39;, log_resource = &#39;&#39;): @@ -45,3 +45,48 @@ def log_decorator(log_action = &#39;&#39;, log_resource = &#39;&#39;):
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/static/js/base/header.js 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +$(document).ready(function(){
  2 + $('[data-toggle="tooltip"]').tooltip(); //activate tooltip on all elements that has attribute data-toggle
  3 +});
0 \ No newline at end of file 4 \ No newline at end of file
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">
@@ -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 %}
courses/tests/test_subject.py 0 → 100644
@@ -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
courses/tests/test_topic.py 0 → 100644
@@ -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>