Commit 0838e0cab2f5b9992df3f7e4dc5d3aa8470cee26
1 parent
f7799b4a
Exists in
master
and in
3 other branches
Adding topic creation
Showing
9 changed files
with
229 additions
and
5 deletions
Show diff stats
amadeus/urls.py
... | ... | @@ -27,6 +27,7 @@ urlpatterns = [ |
27 | 27 | url(r'^$', index, name = 'home'), |
28 | 28 | url(r'^categories/', include('categories.urls', namespace = 'categories')), |
29 | 29 | url(r'^subjects/', include('subjects.urls', namespace = 'subjects')), |
30 | + url(r'^topics/', include('topics.urls', namespace = 'topics')), | |
30 | 31 | url(r'^mailsender/', include('mailsender.urls', namespace = 'mailsender')), |
31 | 32 | url(r'^security/', include('security.urls', namespace = 'security')), |
32 | 33 | url(r'^themes/', include('themes.urls', namespace = 'themes')), | ... | ... |
subjects/templates/subjects/view.html
... | ... | @@ -14,6 +14,17 @@ |
14 | 14 | {% endblock %} |
15 | 15 | |
16 | 16 | {% block content %} |
17 | + {% if messages %} | |
18 | + {% for message in messages %} | |
19 | + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert"> | |
20 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
21 | + <span aria-hidden="true">×</span> | |
22 | + </button> | |
23 | + <p>{{ message }}</p> | |
24 | + </div> | |
25 | + {% endfor %} | |
26 | + {% endif %} | |
27 | + | |
17 | 28 | {% if subject.visible %} |
18 | 29 | <div class="panel panel-info subject-panel"> |
19 | 30 | <div class="panel-heading"> |
... | ... | @@ -68,7 +79,7 @@ |
68 | 79 | <p>{{subject.description|safe}}</p> |
69 | 80 | |
70 | 81 | {% if request.user in subject.professor.all or request.user in subject.category.coordinators.all or request.user.is_staff %} |
71 | - <a href="{% url 'subjects:create' subject.category.slug %}"><button class="btn btn-sm btn-primary btn-raised btn-block"> {% trans "Create new topic" %} </button></a> | |
82 | + <a href="{% url 'topics:create' subject.slug %}"><button class="btn btn-sm btn-primary btn-raised btn-block"> {% trans "Create new topic" %} </button></a> | |
72 | 83 | {% endif %} |
73 | 84 | |
74 | 85 | </div> | ... | ... |
... | ... | @@ -0,0 +1,36 @@ |
1 | +# coding=utf-8 | |
2 | +from django import forms | |
3 | +from django.utils.translation import ugettext_lazy as _ | |
4 | + | |
5 | +from subjects.models import Subject | |
6 | + | |
7 | +from .models import Topic | |
8 | + | |
9 | +class TopicForm(forms.ModelForm): | |
10 | + subject = None | |
11 | + | |
12 | + def __init__(self, *args, **kwargs): | |
13 | + super(TopicForm, self).__init__(*args, **kwargs) | |
14 | + | |
15 | + self.subject = kwargs['initial'].get('subject', None) | |
16 | + | |
17 | + def clean_name(self): | |
18 | + name = self.cleaned_data.get('name', '') | |
19 | + repo = self.cleaned_data.get('repository', False) | |
20 | + | |
21 | + if len(self.subject.topic_subject.filter(name = name)) > 0: | |
22 | + if repo: | |
23 | + self._errors['name'] = [_('This subject already has a repository')] | |
24 | + else: | |
25 | + self._errors['name'] = [_('This subject already has a topic with this name')] | |
26 | + | |
27 | + return ValueError | |
28 | + | |
29 | + return name | |
30 | + | |
31 | + class Meta: | |
32 | + model = Topic | |
33 | + fields = ['repository', 'name', 'description', 'visible' ] | |
34 | + widgets = { | |
35 | + 'description': forms.Textarea, | |
36 | + } | |
0 | 37 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10 on 2017-01-16 21:41 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | +import django.db.models.deletion | |
7 | + | |
8 | + | |
9 | +class Migration(migrations.Migration): | |
10 | + | |
11 | + dependencies = [ | |
12 | + ('topics', '0001_initial'), | |
13 | + ] | |
14 | + | |
15 | + operations = [ | |
16 | + migrations.AlterField( | |
17 | + model_name='topic', | |
18 | + name='order', | |
19 | + field=models.PositiveSmallIntegerField(null=True, verbose_name='Order'), | |
20 | + ), | |
21 | + migrations.AlterField( | |
22 | + model_name='topic', | |
23 | + name='subject', | |
24 | + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='topic_subject', to='subjects.Subject', verbose_name='Subject'), | |
25 | + ), | |
26 | + ] | ... | ... |
topics/models.py
... | ... | @@ -10,8 +10,8 @@ class Topic(models.Model): |
10 | 10 | description = models.TextField(_('Description'), blank = True) |
11 | 11 | repository = models.BooleanField(_('Repository'), default = False) |
12 | 12 | visible = models.BooleanField(_('Visible'), default = True) |
13 | - subject = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'topic_subject') | |
14 | - order = models.PositiveSmallIntegerField(_('Order')) | |
13 | + subject = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'topic_subject', null = True) | |
14 | + order = models.PositiveSmallIntegerField(_('Order'), null = True) | |
15 | 15 | create_date = models.DateTimeField(_('Create Date'), auto_now_add = True) |
16 | 16 | last_update = models.DateTimeField(_('Last Update'), auto_now = True) |
17 | 17 | ... | ... |
... | ... | @@ -0,0 +1,68 @@ |
1 | +{% load static i18n %} | |
2 | +{% load widget_tweaks %} | |
3 | + | |
4 | +<form method="post" action="" enctype="multipart/form-data"> | |
5 | + {% csrf_token %} | |
6 | + {% for field in form %} | |
7 | + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput"> | |
8 | + {% if field.auto_id == 'id_description' %} | |
9 | + {% if field.field.required %} | |
10 | + <label for="{{ field.auto_id }}">{{ field.label }} <span>*</span></label> | |
11 | + {% else %} | |
12 | + <label for="{{ field.auto_id }}">{{ field.label }}</label> | |
13 | + {% endif %} | |
14 | + {% render_field field class='form-control text_wysiwyg' %} | |
15 | + {% elif field.auto_id == 'id_repository' or field.auto_id == 'id_visible' %} | |
16 | + <div class="checkbox"> | |
17 | + <label for="{{ field.auto_id }}"> | |
18 | + {% render_field field %} {{field.label}} | |
19 | + </label> | |
20 | + {% if field.auto_id == 'id_repository' %} | |
21 | + <p><small><em>{% trans 'Only one topic per subject can be a repository' %}</em></small></p> | |
22 | + {% endif %} | |
23 | + </div> | |
24 | + {% else %} | |
25 | + {% if field.field.required %} | |
26 | + <label for="{{ field.auto_id }}">{{ field.label }} <span>*</span></label> | |
27 | + {% else %} | |
28 | + <label for="{{ field.auto_id }}">{{ field.label }}</label> | |
29 | + {% endif %} | |
30 | + | |
31 | + {% render_field field class='form-control' %} | |
32 | + {% endif %} | |
33 | + | |
34 | + <span id="helpBlock" class="help-block">{{ field.help_text }}</span> | |
35 | + | |
36 | + {% if field.errors %} | |
37 | + <div class="alert alert-danger alert-dismissible" role="alert"> | |
38 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
39 | + <span aria-hidden="true">×</span> | |
40 | + </button> | |
41 | + <ul> | |
42 | + {% for error in field.errors %} | |
43 | + <li>{{ error }}</li> | |
44 | + {% endfor %} | |
45 | + </ul> | |
46 | + </div> | |
47 | + {% endif %} | |
48 | + </div> | |
49 | + {% endfor %} | |
50 | + <div class="col-md-12 col-lg-12 col-sm-12 col-xs-12"> | |
51 | + <div class="text-center"> | |
52 | + <input type="submit" value="{% trans 'Save' %}" class="btn btn-raised btn-primary" /> | |
53 | + </div> | |
54 | + </div> | |
55 | +</form> | |
56 | + | |
57 | +<script type="text/javascript"> | |
58 | + $("#id_repository").on('change', function(e) { | |
59 | + if ($(this).is(':checked')) { | |
60 | + $("#id_visible").parent().hide(); | |
61 | + $("#id_name").val('Repositório'); | |
62 | + $("#id_name").prop('readonly', true); | |
63 | + } else { | |
64 | + $("#id_visible").parent().show(); | |
65 | + $("#id_name").prop('readonly', false); | |
66 | + } | |
67 | + }); | |
68 | +</script> | |
0 | 69 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +{% extends 'subjects/view.html' %} | |
2 | + | |
3 | +{% load django_bootstrap_breadcrumbs %} | |
4 | + | |
5 | +{% block breadcrumbs %} | |
6 | + {{ block.super }} | |
7 | + {% breadcrumb 'Create Topic' 'topics:create' subject.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/views.py
1 | -from django.shortcuts import render | |
1 | +from django.shortcuts import get_object_or_404, redirect, render | |
2 | +from django.views import generic | |
3 | +from django.contrib import messages | |
4 | +from django.core.urlresolvers import reverse, reverse_lazy | |
5 | +from django.utils.translation import ugettext_lazy as _ | |
6 | +from django.contrib.auth.mixins import LoginRequiredMixin | |
2 | 7 | |
3 | -# Create your views here. | |
8 | +from subjects.models import Subject | |
9 | + | |
10 | +from .models import Topic | |
11 | +from .forms import TopicForm | |
12 | + | |
13 | +class CreateView(LoginRequiredMixin, generic.edit.CreateView): | |
14 | + login_url = reverse_lazy("users:login") | |
15 | + redirect_field_name = 'next' | |
16 | + | |
17 | + template_name = 'topics/create.html' | |
18 | + form_class = TopicForm | |
19 | + | |
20 | + def get_initial(self): | |
21 | + initial = super(CreateView, self).get_initial() | |
22 | + | |
23 | + slug = self.kwargs.get('slug', '') | |
24 | + | |
25 | + initial['subject'] = get_object_or_404(Subject, slug = slug) | |
26 | + | |
27 | + return initial | |
28 | + | |
29 | + def form_valid(self, form): | |
30 | + self.object = form.save(commit = False) | |
31 | + | |
32 | + slug = self.kwargs.get('slug', '') | |
33 | + subject = get_object_or_404(Subject, slug = slug) | |
34 | + | |
35 | + self.object.subject = subject | |
36 | + self.object.order = subject.topic_subject.count() + 1 | |
37 | + | |
38 | + self.object.save() | |
39 | + | |
40 | + return super(CreateView, self).form_valid(form) | |
41 | + | |
42 | + def get_context_data(self, **kwargs): | |
43 | + context = super(CreateView, self).get_context_data(**kwargs) | |
44 | + | |
45 | + context['title'] = _('Create Topic') | |
46 | + | |
47 | + slug = self.kwargs.get('slug', '') | |
48 | + subject = get_object_or_404(Subject, slug = slug) | |
49 | + | |
50 | + context['subject'] = subject | |
51 | + | |
52 | + return context | |
53 | + | |
54 | + def get_success_url(self): | |
55 | + messages.success(self.request, _('Topic "%s" was created on virtual enviroment "%s" successfully!')%(self.object.name, self.object.subject.name)) | |
56 | + | |
57 | + return reverse_lazy('subjects:view', kwargs = {'slug': self.object.subject.slug}) | ... | ... |