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,6 +27,7 @@ urlpatterns = [ | ||
27 | url(r'^$', index, name = 'home'), | 27 | url(r'^$', index, name = 'home'), |
28 | url(r'^categories/', include('categories.urls', namespace = 'categories')), | 28 | url(r'^categories/', include('categories.urls', namespace = 'categories')), |
29 | url(r'^subjects/', include('subjects.urls', namespace = 'subjects')), | 29 | url(r'^subjects/', include('subjects.urls', namespace = 'subjects')), |
30 | + url(r'^topics/', include('topics.urls', namespace = 'topics')), | ||
30 | url(r'^mailsender/', include('mailsender.urls', namespace = 'mailsender')), | 31 | url(r'^mailsender/', include('mailsender.urls', namespace = 'mailsender')), |
31 | url(r'^security/', include('security.urls', namespace = 'security')), | 32 | url(r'^security/', include('security.urls', namespace = 'security')), |
32 | url(r'^themes/', include('themes.urls', namespace = 'themes')), | 33 | url(r'^themes/', include('themes.urls', namespace = 'themes')), |
subjects/templates/subjects/view.html
@@ -14,6 +14,17 @@ | @@ -14,6 +14,17 @@ | ||
14 | {% endblock %} | 14 | {% endblock %} |
15 | 15 | ||
16 | {% block content %} | 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 | {% if subject.visible %} | 28 | {% if subject.visible %} |
18 | <div class="panel panel-info subject-panel"> | 29 | <div class="panel panel-info subject-panel"> |
19 | <div class="panel-heading"> | 30 | <div class="panel-heading"> |
@@ -68,7 +79,7 @@ | @@ -68,7 +79,7 @@ | ||
68 | <p>{{subject.description|safe}}</p> | 79 | <p>{{subject.description|safe}}</p> |
69 | 80 | ||
70 | {% if request.user in subject.professor.all or request.user in subject.category.coordinators.all or request.user.is_staff %} | 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 | {% endif %} | 83 | {% endif %} |
73 | 84 | ||
74 | </div> | 85 | </div> |
@@ -0,0 +1,36 @@ | @@ -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 | \ No newline at end of file | 37 | \ No newline at end of file |
@@ -0,0 +1,26 @@ | @@ -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,8 +10,8 @@ class Topic(models.Model): | ||
10 | description = models.TextField(_('Description'), blank = True) | 10 | description = models.TextField(_('Description'), blank = True) |
11 | repository = models.BooleanField(_('Repository'), default = False) | 11 | repository = models.BooleanField(_('Repository'), default = False) |
12 | visible = models.BooleanField(_('Visible'), default = True) | 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 | create_date = models.DateTimeField(_('Create Date'), auto_now_add = True) | 15 | create_date = models.DateTimeField(_('Create Date'), auto_now_add = True) |
16 | last_update = models.DateTimeField(_('Last Update'), auto_now = True) | 16 | last_update = models.DateTimeField(_('Last Update'), auto_now = True) |
17 | 17 |
@@ -0,0 +1,68 @@ | @@ -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 | \ No newline at end of file | 69 | \ No newline at end of file |
@@ -0,0 +1,20 @@ | @@ -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}) |