Commit c42f7077a3b25f47d982ecebaf1917a891b12731

Authored by Felipe Henrique de Almeida Bormann
2 parents 9d6a4c6e 3afceffb

Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring

amadeus/permissions.py
... ... @@ -10,10 +10,10 @@ def has_subject_permissions(user, subject):
10 10 if user.is_staff:
11 11 return True
12 12  
13   - if user in subject.professor.all():
  13 + if subject.professor.filter(id = user.id).exists():
14 14 return True
15 15  
16   - if user in subject.category.coordinators.all():
  16 + if subject.category.coordinators.filter(id = user.id).exists():
17 17 return True
18 18  
19 19 return False
... ...
amadeus/static/css/themes/green.css
... ... @@ -63,6 +63,10 @@ a, a:focus, a:hover {
63 63 background-color: #7BA5B9 !important;
64 64 }
65 65  
  66 +.topic-panel > .category-panel-content, .topic-panel-invisible > .category-panel-content {
  67 + background: #FFFFFF;
  68 +}
  69 +
66 70 .topic-panel-invisible > .panel-heading {
67 71 background-color: #BDBDBD !important;
68 72 color: #F5F5F5;
... ...
amadeus/static/js/topics.js 0 → 100644
... ... @@ -0,0 +1,76 @@
  1 +// Update breadcrumb with topic's name
  2 +$('.collapse').on('shown.bs.collapse', function (e) {
  3 + if($(this).is(e.target)){
  4 + var li = $(".breadcrumb").find('li:last-child');
  5 + var li_text = $(li).html();
  6 + var url = $(".subs_url").val();
  7 + var new_li = $(li).clone();
  8 +
  9 + new_li.html($(this).parent().find('.panel-title').text());
  10 +
  11 + $(li).html("<a href='" + url + "'>" + li_text + "</a>");
  12 + $(li).append("<span class='divider'>/</span>");
  13 +
  14 + new_li.appendTo('.breadcrumb');
  15 + }
  16 +});
  17 +
  18 +// Reset breadcrumb to it's normal state
  19 +$('.collapse').on('hide.bs.collapse', function (e) {
  20 + if($(this).is(e.target)){
  21 + $(".breadcrumb").find('li:last-child').remove();
  22 +
  23 + var li = $(".breadcrumb").find('li:last-child');
  24 + var text = $(li).find('a').text();
  25 +
  26 + $(li).html(text);
  27 + }
  28 +});
  29 +
  30 +// utilizado para fazer a re-organização dos tópicos
  31 +$("#topics-accordion").sortable({
  32 + delay: 100,
  33 + distance: 5,
  34 + handle: 'i.fa-arrows',
  35 + update: function( event, ui ) {
  36 + var cont = 1;
  37 + var data = [];
  38 +
  39 + $("#topics-accordion").find('.order_inp').each(function () {
  40 + $(this).val(cont++);
  41 +
  42 + data.push({
  43 + 'topic_id': $(this).parent().find('.id_inp').val(),
  44 + 'topic_order': $(this).val()
  45 + });
  46 + });
  47 +
  48 + data = JSON.stringify(data);
  49 +
  50 + sendUpdate(data);
  51 + },
  52 +});
  53 +
  54 +function sendUpdate(data) {
  55 + $.ajax({
  56 + url: $('.url_order').val(),
  57 + dataType: 'json',
  58 + data: {'data': data},
  59 + success: function(response) {
  60 + console.log(response);
  61 + },
  62 + error: function(response) {
  63 + console.log(response);
  64 + }
  65 + });
  66 +}
  67 +
  68 +function delete_topic(url) {
  69 + $('.modal').remove();
  70 +
  71 + $.get(url, function (modal) {
  72 + $("#topics-accordion").after(modal);
  73 +
  74 + $('.modal').modal('show');
  75 + });
  76 +}
0 77 \ No newline at end of file
... ...
subjects/utils.py
... ... @@ -6,14 +6,14 @@ from django.db.models import Q
6 6  
7 7 def has_student_profile(user, category):
8 8 for subject in category.subject_category.all():
9   - if user in subject.students.all() and subject.visible:
  9 + if subject.students.filter(id = user.id).exists() and subject.visible:
10 10 return True
11 11  
12 12 return False
13 13  
14 14 def has_professor_profile(user, category):
15 15 for subject in category.subject_category.all():
16   - if user in subject.professor.all() and subject.visible:
  16 + if subject.professor.filter(id = user.id).exists() and subject.visible:
17 17 return True
18 18  
19 19 return False
... ... @@ -30,7 +30,8 @@ def count_subjects( user, all_subs = True):
30 30 else:
31 31 total += category.subject_category.count()"""
32 32 if all_subs:
33   - total += Category.objects.filter(Q(coordinators__pk = pk) | Q(visible=True) ).distinct().count()
  33 + #total += Category.objects.filter(Q(coordinators__pk = pk) | Q(visible=True) ).distinct().count()
  34 + total = Subject.objects.filter(Q(students__pk=pk) | Q(professor__pk=pk) | Q(category__coordinators__pk=pk) | Q(visible = True)).distinct().count()
34 35 else:
35 36  
36 37 total = Subject.objects.filter(Q(students__pk=pk) | Q(professor__pk=pk) | Q(category__coordinators__pk=pk)).distinct().count()
... ...
subjects/views.py
... ... @@ -74,7 +74,7 @@ class IndexView(LoginRequiredMixin, ListView):
74 74 else:
75 75 pk = self.request.user.pk
76 76  
77   - categories = Category.objects.filter(Q(coordinators__pk = pk) | Q(visible=True) ).order_by('name')
  77 + categories = Category.objects.filter(Q(coordinators__pk = pk) | Q(visible=True) ).distinct().order_by('name')
78 78  
79 79 self.totals['all_subjects'] = count_subjects(self.request.user)
80 80  
... ...
topics/forms.py
... ... @@ -18,7 +18,10 @@ class TopicForm(forms.ModelForm):
18 18 name = self.cleaned_data.get('name', '')
19 19 repo = self.cleaned_data.get('repository', False)
20 20  
21   - same_name = len(self.subject.topic_subject.filter(name__unaccent__iexact = name))
  21 + if self.instance.id:
  22 + same_name = len(self.subject.topic_subject.filter(name__unaccent__iexact = name).exclude(id = self.instance.id))
  23 + else:
  24 + same_name = len(self.subject.topic_subject.filter(name__unaccent__iexact = name))
22 25  
23 26 if same_name > 0:
24 27 if repo:
... ...
topics/templates/topics/delete.html 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +{% load i18n %}
  2 +
  3 +<div class="modal fade" id="topic" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  4 + <div class="modal-dialog" role="document">
  5 + <div class="modal-content">
  6 + <div class="modal-body">
  7 + <form id="delete_form" action="{% url 'topics:delete' topic.slug %}" method="post">
  8 + {% csrf_token %}
  9 + <h4>{% trans 'Are you sure you want delete the topic' %}: {{ topic }}?</h4>
  10 + <p>{% trans 'All data will be lost and havent how recover it.' %}</p>
  11 + </form>
  12 + </div>
  13 + <div class="modal-footer">
  14 + <div class="pull-right">
  15 + <button type="button" class="btn btn-default btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  16 + </div>
  17 + <div class="pull-left">
  18 + <button type="submit" form="delete_form" class="btn btn-success btn-raised">{% trans "Delete" %}</button>
  19 + </div>
  20 + </div>
  21 + </div>
  22 + </div>
  23 +</div>
0 24 \ No newline at end of file
... ...
topics/templates/topics/list.html
... ... @@ -4,9 +4,12 @@
4 4 {% subject_permissions request.user subject as has_subject_permissions %}
5 5  
6 6 <div class="panel-group subject-group" id="topics-accordion" role="tablist" aria-multiselectable="true">
  7 + <input type="hidden" class="url_order" value="{% url 'topics:update_order' %}" />
  8 + <input type="hidden" class="subs_url" value="{% url 'subjects:view' subject.slug %}" />
  9 +
7 10 {% for topic in subject.topic_subject.all %}
8 11 {% if not topic.repository and topic.visible or has_subject_permissions %}
9   - <div class="panel panel-info {% if not topic.visible or topic.repository %} topic-panel-invisible {% else %} topic-panel {% endif %} topic-panel">
  12 + <div class="panel panel-info {% if not topic.visible or topic.repository %} topic-panel-invisible {% else %} topic-panel {% endif %}">
10 13 <div class="panel-heading">
11 14 <div class="row">
12 15 <div class="col-md-12 category-header">
... ... @@ -22,9 +25,8 @@
22 25 <i class="fa fa-ellipsis-v" aria-hidden="true"></i>
23 26 </a>
24 27 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions">
25   - <li><a href="{% url 'subjects:replicate' subject.slug %}"><i class="fa fa-files-o fa-fw" aria-hidden="true"></i>{% trans 'Replicate' %}</a></li>
26   - <li><a href="{% url 'subjects:update' subject.slug %}"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>{% trans 'Edit' %}</a></li>
27   - <li><a href="javascript:delete_subject.get('{% url 'subjects:delete' subject.slug %}?view=index','#subject','#modal_subject')"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp;{% trans 'Remove' %}</a></li>
  28 + <li><a href="{% url 'topics:update' subject.slug topic.slug %}"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>{% trans 'Edit' %}</a></li>
  29 + <li><a href="javascript:delete_topic('{% url 'topics:delete' topic.slug %}')"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp;{% trans 'Remove' %}</a></li>
28 30 </ul>
29 31 <a href="" ><i class="fa fa-arrows" aria-hidden="true"></i></a>
30 32 </div>
... ... @@ -35,47 +37,15 @@
35 37 <div id="{{topic.slug}}" class="panel-collapse collapse category-panel-content">
36 38 <input type="hidden" class="id_inp" name="id" value="{{ topic.id }}" />
37 39 <input type="hidden" class="order_inp" name="order" value="{{ topic.order }}" />
  40 +
  41 + {% autoescape off %}
  42 + {{ topic.description }}
  43 + {% endautoescape %}
38 44 </div>
39 45 </div>
40 46 {% endif %}
41 47 {% endfor %}
42 48 </div>
43 49  
44   -<script type="text/javascript">
45   - $("#topics-accordion").sortable({ // utilizado para fazer a re-organização dos tópicos
46   - delay: 100,
47   - distance: 5,
48   - handler: 'i.fa-arrows',
49   - update: function( event, ui ) {
50   - var cont = 1;
51   - var data = [];
52   -
53   - $("#topics-accordion").find('.order_inp').each(function () {
54   - $(this).val(cont++);
55   -
56   - data.push({
57   - 'topic_id': $(this).parent().find('.id_inp').val(),
58   - 'topic_order': $(this).val()
59   - });
60   - });
61   -
62   - data = JSON.stringify(data);
63   -
64   - sendUpdate(data);
65   - },
66   - });
67   -
68   - function sendUpdate(data) {
69   - $.ajax({
70   - url: '{% url "topics:update_order" %}',
71   - dataType: 'json',
72   - data: {'data': data},
73   - success: function(response) {
74   - console.log(response);
75   - },
76   - error: function(response) {
77   - console.log(response);
78   - }
79   - });
80   - }
81   -</script>
82 50 \ No newline at end of file
  51 +<script type="text/javascript" src="{% static 'js/topics.js' %}"></script>
  52 +<script type="text/javascript" src="{% static 'js/course.js' %}"></script>
83 53 \ No newline at end of file
... ...
topics/templates/topics/update.html 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +{% extends 'subjects/view.html' %}
  2 +
  3 +{% load django_bootstrap_breadcrumbs %}
  4 +
  5 +{% block breadcrumbs %}
  6 + {{ block.super }}
  7 + {% breadcrumb 'Update Topic' 'topics:update' subject.slug topic.slug %}
  8 +{% endblock %}
  9 +
  10 +{% block content %}
  11 + <div class="card">
  12 + <div class="card-content">
  13 + <div class="card-body">
  14 + {% include 'topics/_form.html' %}
  15 + </div>
  16 + </div>
  17 + </div>
  18 + <br clear="all" />
  19 + <br clear="all" />
  20 +{% endblock %}
... ...
topics/urls.py
... ... @@ -5,5 +5,7 @@ from . import views
5 5  
6 6 urlpatterns = [
7 7 url(r'^create/(?P<slug>[\w_-]+)/$', views.CreateView.as_view(), name = 'create'),
  8 + url(r'^update/(?P<sub_slug>[\w_-]+)/(?P<slug>[\w_-]+)/$', views.UpdateView.as_view(), name = 'update'),
  9 + url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteView.as_view(), name = 'delete'),
8 10 url(r'^update_order/$', views.update_order, name = 'update_order'),
9 11 ]
... ...
topics/views.py
... ... @@ -70,6 +70,72 @@ class CreateView(LoginRequiredMixin, generic.edit.CreateView):
70 70  
71 71 return reverse_lazy('subjects:view', kwargs = {'slug': self.object.subject.slug})
72 72  
  73 +class UpdateView(LoginRequiredMixin, generic.UpdateView):
  74 + login_url = reverse_lazy("users:login")
  75 + redirect_field_name = 'next'
  76 +
  77 + template_name = 'topics/update.html'
  78 + form_class = TopicForm
  79 + model = Topic
  80 + context_object_name = 'topic'
  81 +
  82 + def dispatch(self, request, *args, **kwargs):
  83 + slug = self.kwargs.get('sub_slug', '')
  84 + subject = get_object_or_404(Subject, slug = slug)
  85 +
  86 + if not has_subject_permissions(request.user, subject):
  87 + return redirect(reverse_lazy('subjects:home'))
  88 +
  89 + return super(UpdateView, self).dispatch(request, *args, **kwargs)
  90 +
  91 + def get_initial(self):
  92 + initial = super(UpdateView, self).get_initial()
  93 +
  94 + slug = self.kwargs.get('sub_slug', '')
  95 +
  96 + initial['subject'] = get_object_or_404(Subject, slug = slug)
  97 +
  98 + return initial
  99 +
  100 + def get_context_data(self, **kwargs):
  101 + context = super(UpdateView, self).get_context_data(**kwargs)
  102 +
  103 + context['title'] = _('Update Topic')
  104 +
  105 + slug = self.kwargs.get('sub_slug', '')
  106 + subject = get_object_or_404(Subject, slug = slug)
  107 +
  108 + context['subject'] = subject
  109 +
  110 + return context
  111 +
  112 + def get_success_url(self):
  113 + messages.success(self.request, _('Topic "%s" was updated on virtual enviroment "%s" successfully!')%(self.object.name, self.object.subject.name))
  114 +
  115 + return reverse_lazy('subjects:view', kwargs = {'slug': self.object.subject.slug})
  116 +
  117 +class DeleteView(LoginRequiredMixin, generic.DeleteView):
  118 + login_url = reverse_lazy("users:login")
  119 + redirect_field_name = 'next'
  120 +
  121 + template_name = 'topics/delete.html'
  122 + model = Topic
  123 + context_object_name = 'topic'
  124 +
  125 + def dispatch(self, request, *args, **kwargs):
  126 + slug = self.kwargs.get('slug', '')
  127 + topic = get_object_or_404(Topic, slug = slug)
  128 +
  129 + if not has_subject_permissions(request.user, topic.subject):
  130 + return redirect(reverse_lazy('subjects:home'))
  131 +
  132 + return super(DeleteView, self).dispatch(request, *args, **kwargs)
  133 +
  134 + def get_success_url(self):
  135 + messages.success(self.request, _('Topic "%s" was removed from virtual enviroment "%s" successfully!')%(self.object.name, self.object.subject.name))
  136 +
  137 + return reverse_lazy('subjects:view', kwargs = {'slug': self.object.subject.slug})
  138 +
73 139 def update_order(request):
74 140 data = request.GET.get('data', None)
75 141  
... ...