diff --git a/amadeus/settings.py b/amadeus/settings.py
index 0448ebf..1e5825c 100644
--- a/amadeus/settings.py
+++ b/amadeus/settings.py
@@ -60,6 +60,8 @@ INSTALLED_APPS = [
'subjects',
'students_group',
'topics',
+ 'pendencies',
+ 'webpage',
'mailsender',
'security',
'themes'
diff --git a/amadeus/static/js/jquery.formset.js b/amadeus/static/js/jquery.formset.js
new file mode 100644
index 0000000..1e167fe
--- /dev/null
+++ b/amadeus/static/js/jquery.formset.js
@@ -0,0 +1,170 @@
+/**
+ * jQuery Formset 1.2
+ * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
+ * @requires jQuery 1.2.6 or later
+ *
+ * Copyright (c) 2009, Stanislaus Madueke
+ * All rights reserved.
+ *
+ * Licensed under the New BSD License
+ * See: http://www.opensource.org/licenses/bsd-license.php
+ */
+;(function($) {
+ $.fn.formset = function(opts)
+ {
+ var options = $.extend({}, $.fn.formset.defaults, opts),
+ flatExtraClasses = options.extraClasses.join(' '),
+ $$ = $(this),
+
+ applyExtraClasses = function(row, ndx) {
+ if (options.extraClasses) {
+ row.removeClass(flatExtraClasses);
+ row.addClass(options.extraClasses[ndx % options.extraClasses.length]);
+ }
+ },
+
+ updateElementIndex = function(elem, prefix, ndx) {
+ var idRegex = new RegExp('(' + prefix + '-\\d+-)|(^)'),
+ replacement = prefix + '-' + ndx + '-';
+ if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
+ if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
+ if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
+ },
+
+ hasChildElements = function(row) {
+ return row.find('input,select,textarea,label').length > 0;
+ },
+
+ insertDeleteLink = function(row) {
+ if (row.is('TR')) {
+ // If the forms are laid out in table rows, insert
+ // the remove button into the last table cell:
+ row.children(':last').append('' + options.deleteText + ' ');
+ } else if (row.is('UL') || row.is('OL')) {
+ // If they're laid out as an ordered/unordered list,
+ // insert an
after the last list item:
+ row.append(' ' + options.deleteText +' ');
+ } else {
+ // Otherwise, just insert the remove button as the
+ // last child element of the form's container:
+ row.append('' + options.deleteText +' ');
+ }
+ row.find('a.' + options.deleteCssClass).click(function() {
+ var row = $(this).parents('.' + options.formCssClass),
+ del = row.find('input:hidden[id $= "-DELETE"]');
+ if (del.length) {
+ // We're dealing with an inline formset; rather than remove
+ // this form from the DOM, we'll mark it as deleted and hide
+ // it, then let Django handle the deleting:
+ del.val('on');
+ row.hide();
+ } else {
+ row.remove();
+ // Update the TOTAL_FORMS form count.
+ // Also update names and IDs for all remaining form controls so they remain in sequence:
+ var forms = $('.' + options.formCssClass).not('.formset-custom-template');
+ $('#id_' + options.prefix + '-TOTAL_FORMS').val(forms.length);
+ for (var i=0, formCount=forms.length; i ');
+ del.remove();
+ }
+ if (hasChildElements(row)) {
+ insertDeleteLink(row);
+ row.addClass(options.formCssClass);
+ applyExtraClasses(row, i);
+ }
+ });
+
+ if ($$.length) {
+ var addButton, template;
+ if (options.formTemplate) {
+ // If a form template was specified, we'll clone it to generate new form instances:
+ template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
+ template.removeAttr('id').addClass(options.formCssClass).addClass('formset-custom-template');
+ template.find('input,select,textarea,label').each(function() {
+ updateElementIndex($(this), options.prefix, 2012);
+ });
+ insertDeleteLink(template);
+ } else {
+ // Otherwise, use the last form in the formset; this works much better if you've got
+ // extra (>= 1) forms (thnaks to justhamade for pointing this out):
+ template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
+ template.find('input:hidden[id $= "-DELETE"]').remove();
+ template.find('input,select,textarea,label').each(function() {
+ var elem = $(this);
+ // If this is a checkbox or radiobutton, uncheck it.
+ // This fixes Issue 1, reported by Wilson.Andrew.J:
+ if (elem.is('input:checkbox') || elem.is('input:radio')) {
+ elem.attr('checked', false);
+ } else {
+ elem.val('');
+ }
+ });
+ }
+ // FIXME: Perhaps using $.data would be a better idea?
+ options.formTemplate = template;
+
+ if ($$.attr('tagName') == 'TR') {
+ // If forms are laid out as table rows, insert the
+ // "add" button in a new table row:
+ var numCols = $$.eq(0).children().length;
+ $$.parent().append('' + options.addText + ' ');
+ addButton = $$.parent().find('tr:last a');
+ addButton.parents('tr').addClass(options.formCssClass + '-add');
+ } else {
+ // Otherwise, insert it immediately after the last form:
+ $$.filter(':last').after('' + options.addText + ' ');
+ addButton = $$.filter(':last').next();
+ }
+ addButton.click(function() {
+ var formCount = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val()),
+ row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
+ buttonRow = $(this).parents('tr.' + options.formCssClass + '-add').get(0) || this;
+ applyExtraClasses(row, formCount);
+ row.insertBefore($(buttonRow)).show();
+ row.find('input,select,textarea,label').each(function() {
+ updateElementIndex($(this), options.prefix, formCount);
+ });
+ $('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount + 1);
+ // If a post-add callback was supplied, call it with the added form:
+ if (options.added) options.added(row);
+ return false;
+ });
+ }
+
+ return $$;
+ }
+
+ /* Setup plugin defaults */
+ $.fn.formset.defaults = {
+ prefix: 'form', // The form prefix for your django formset
+ formTemplate: null, // The jQuery selection cloned to generate new form instances
+ addText: 'add another', // Text for the add link
+ deleteText: 'remove', // Text for the delete link
+ addCssClass: 'add-row', // CSS class applied to the add link
+ deleteCssClass: 'delete-row', // CSS class applied to the delete link
+ formCssClass: 'dynamic-form', // CSS class applied to each form in a formset
+ extraClasses: [], // Additional CSS classes, which will be applied to each form in turn
+ added: null, // Function called each time a new form is added
+ removed: null // Function called each time a form is deleted
+ };
+})(jQuery)
diff --git a/amadeus/static/js/topics.js b/amadeus/static/js/topics.js
index de8650d..deede6f 100644
--- a/amadeus/static/js/topics.js
+++ b/amadeus/static/js/topics.js
@@ -73,4 +73,12 @@ function delete_topic(url) {
$('.modal').modal('show');
});
-}
\ No newline at end of file
+}
+
+$(".add_resource").on('show.bs.dropdown', function () {
+ $(this).find('i').switchClass("fa-angle-right", "fa-angle-down", 250, "easeInOutQuad");
+});
+
+$(".add_resource").on('hide.bs.dropdown', function () {
+ $(this).find('i').switchClass("fa-angle-down", "fa-angle-right", 250, "easeInOutQuad");
+});
\ No newline at end of file
diff --git a/amadeus/urls.py b/amadeus/urls.py
index 3a2a335..5e34b67 100644
--- a/amadeus/urls.py
+++ b/amadeus/urls.py
@@ -29,6 +29,7 @@ urlpatterns = [
url(r'^subjects/', include('subjects.urls', namespace = 'subjects')),
url(r'^groups/', include('students_group.urls', namespace = 'groups')),
url(r'^topics/', include('topics.urls', namespace = 'topics')),
+ url(r'^webpages/', include('webpage.urls', namespace = 'webpages')),
url(r'^mailsender/', include('mailsender.urls', namespace = 'mailsender')),
url(r'^security/', include('security.urls', namespace = 'security')),
url(r'^themes/', include('themes.urls', namespace = 'themes')),
diff --git a/pendencies/__init__.py b/pendencies/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pendencies/__init__.py
diff --git a/pendencies/admin.py b/pendencies/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/pendencies/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/pendencies/apps.py b/pendencies/apps.py
new file mode 100644
index 0000000..b17dffb
--- /dev/null
+++ b/pendencies/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class PendenciesConfig(AppConfig):
+ name = 'pendencies'
diff --git a/pendencies/forms.py b/pendencies/forms.py
new file mode 100644
index 0000000..a29c78c
--- /dev/null
+++ b/pendencies/forms.py
@@ -0,0 +1,10 @@
+# coding=utf-8
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+from .models import Pendencies
+
+class PendenciesForm(forms.ModelForm):
+ class Meta:
+ model = Pendencies
+ fields = ['action', 'begin_date', 'end_date']
\ No newline at end of file
diff --git a/pendencies/migrations/0001_initial.py b/pendencies/migrations/0001_initial.py
new file mode 100644
index 0000000..ad68e90
--- /dev/null
+++ b/pendencies/migrations/0001_initial.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2017-01-19 21:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Pendencies',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('action', models.CharField(choices=[('view', 'Visualize'), ('create', 'Create'), ('answer', 'Answer'), ('access', 'Access')], max_length=100, verbose_name='Action')),
+ ('begin_date', models.DateTimeField(blank=True, null=True, verbose_name='Begin Date')),
+ ('end_date', models.DateTimeField(blank=True, null=True, verbose_name='End Date')),
+ ],
+ ),
+ ]
diff --git a/pendencies/migrations/0002_pendencies_resource.py b/pendencies/migrations/0002_pendencies_resource.py
new file mode 100644
index 0000000..ed760ce
--- /dev/null
+++ b/pendencies/migrations/0002_pendencies_resource.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2017-01-19 21:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('topics', '0005_resource'),
+ ('pendencies', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='pendencies',
+ name='resource',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='pendencies_resource', to='topics.Resource', verbose_name='Resource'),
+ ),
+ ]
diff --git a/pendencies/migrations/__init__.py b/pendencies/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pendencies/migrations/__init__.py
diff --git a/pendencies/models.py b/pendencies/models.py
new file mode 100644
index 0000000..a93268c
--- /dev/null
+++ b/pendencies/models.py
@@ -0,0 +1,11 @@
+from django.db import models
+from autoslug.fields import AutoSlugField
+from django.utils.translation import ugettext_lazy as _
+
+from topics.models import Resource
+
+class Pendencies(models.Model):
+ action = models.CharField(_('Action'), max_length = 100, choices = (("view", _("Visualize")), ("create", _("Create")), ("answer", _("Answer")), ("access", _("Access"))))
+ begin_date = models.DateTimeField(_('Begin Date'), null = True, blank = True)
+ end_date = models.DateTimeField(_('End Date'), null = True, blank = True)
+ resource = models.ForeignKey(Resource, verbose_name = _('Resource'), related_name = 'pendencies_resource', null = True)
\ No newline at end of file
diff --git a/pendencies/tests.py b/pendencies/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/pendencies/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/pendencies/views.py b/pendencies/views.py
new file mode 100644
index 0000000..91ea44a
--- /dev/null
+++ b/pendencies/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/students_group/migrations/0003_auto_20170119_1543.py b/students_group/migrations/0003_auto_20170119_1543.py
new file mode 100644
index 0000000..c8c0711
--- /dev/null
+++ b/students_group/migrations/0003_auto_20170119_1543.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2017-01-19 18:43
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('students_group', '0002_auto_20170118_1800'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='studentsgroup',
+ options={'ordering': ['name'], 'verbose_name': 'Students Group', 'verbose_name_plural': 'Students Groups'},
+ ),
+ ]
diff --git a/topics/migrations/0005_resource.py b/topics/migrations/0005_resource.py
new file mode 100644
index 0000000..026f902
--- /dev/null
+++ b/topics/migrations/0005_resource.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2017-01-19 21:09
+from __future__ import unicode_literals
+
+import autoslug.fields
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('subjects', '0012_auto_20170112_1408'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('students_group', '0003_auto_20170119_1543'),
+ ('topics', '0004_auto_20170118_1711'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Resource',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200, verbose_name='Name')),
+ ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
+ ('brief_description', models.TextField(blank=True, verbose_name='Brief Description')),
+ ('show_window', models.BooleanField(default=False, verbose_name='Show in new window')),
+ ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
+ ('visible', models.BooleanField(default=True, verbose_name='Visible')),
+ ('order', models.PositiveSmallIntegerField(null=True, verbose_name='Order')),
+ ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Create Date')),
+ ('last_update', models.DateTimeField(auto_now=True, verbose_name='Last Update')),
+ ('groups', models.ManyToManyField(blank=True, related_name='resource_groups', to='students_group.StudentsGroup', verbose_name='Groups')),
+ ('students', models.ManyToManyField(blank=True, related_name='resource_students', to=settings.AUTH_USER_MODEL, verbose_name='Students')),
+ ('tags', models.ManyToManyField(blank=True, related_name='resource_tags', to='subjects.Tag', verbose_name='Markers')),
+ ('topic', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='resource_topic', to='topics.Topic', verbose_name='Topic')),
+ ],
+ options={
+ 'verbose_name': 'Resource',
+ 'verbose_name_plural': 'Resources',
+ },
+ ),
+ ]
diff --git a/topics/models.py b/topics/models.py
index 7ea8447..dee5f03 100644
--- a/topics/models.py
+++ b/topics/models.py
@@ -2,7 +2,9 @@ from django.db import models
from autoslug.fields import AutoSlugField
from django.utils.translation import ugettext_lazy as _
-from subjects.models import Subject
+from subjects.models import Subject, Tag
+from students_group.models import StudentsGroup
+from users.models import User
class Topic(models.Model):
name = models.CharField(_('Name'), max_length = 200)
@@ -21,4 +23,26 @@ class Topic(models.Model):
ordering = ['order']
def __str__(self):
- return self.name
\ No newline at end of file
+ return self.name
+
+class Resource(models.Model):
+ name = models.CharField(_('Name'), max_length = 200)
+ slug = AutoSlugField(_("Slug"), populate_from = 'name', unique = True)
+ brief_description = models.TextField(_('Brief Description'), blank = True)
+ show_window = models.BooleanField(_('Show in new window'), default = False)
+ all_students = models.BooleanField(_('All Students'), default = False)
+ visible = models.BooleanField(_('Visible'), default = True)
+ order = models.PositiveSmallIntegerField(_('Order'), null = True)
+ topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name = "resource_topic", null = True)
+ students = models.ManyToManyField(User, verbose_name = _('Students'), related_name = 'resource_students', blank = True)
+ groups = models.ManyToManyField(StudentsGroup, verbose_name = _('Groups'), related_name = 'resource_groups', blank = True)
+ tags = models.ManyToManyField(Tag, verbose_name = _('Markers'), related_name = 'resource_tags', blank = True)
+ create_date = models.DateTimeField(_('Create Date'), auto_now_add = True)
+ last_update = models.DateTimeField(_('Last Update'), auto_now = True)
+
+ class Meta:
+ verbose_name = _('Resource')
+ verbose_name_plural = _('Resources')
+
+ def __str__(self):
+ return self.name
diff --git a/topics/templates/topics/list.html b/topics/templates/topics/list.html
index 47b5825..6548fac 100644
--- a/topics/templates/topics/list.html
+++ b/topics/templates/topics/list.html
@@ -41,6 +41,23 @@
{% autoescape off %}
{{ topic.description }}
{% endautoescape %}
+
+ {% if has_subject_permissions %}
+
+
+
+ {% trans 'Add Resource' %}
+
+
+
+
+ {% endif %}
{% endif %}
diff --git a/webpage/__init__.py b/webpage/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webpage/__init__.py
diff --git a/webpage/admin.py b/webpage/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/webpage/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/webpage/apps.py b/webpage/apps.py
new file mode 100644
index 0000000..97c31da
--- /dev/null
+++ b/webpage/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class WebpageConfig(AppConfig):
+ name = 'webpage'
diff --git a/webpage/forms.py b/webpage/forms.py
new file mode 100644
index 0000000..8c1d995
--- /dev/null
+++ b/webpage/forms.py
@@ -0,0 +1,24 @@
+# coding=utf-8
+from django import forms
+from django.forms.models import inlineformset_factory
+from django.utils.translation import ugettext_lazy as _
+
+from pendencies.forms import PendenciesForm
+from pendencies.models import Pendencies
+
+from .models import Webpage
+
+class WebpageForm(forms.ModelForm):
+ tags = forms.CharField(label = _('Tags'), required = False)
+
+ class Meta:
+ model = Webpage
+ fields = ['name', 'content', 'brief_description', 'all_students', 'students', 'groups', 'show_window', 'visible']
+ widgets = {
+ 'content': forms.Textarea,
+ 'brief_description': forms.Textarea,
+ 'students': forms.SelectMultiple,
+ 'groups': forms.SelectMultiple,
+ }
+
+InlinePendenciesFormset = inlineformset_factory(Webpage, Pendencies, form = PendenciesForm, extra = 1, can_delete = True)
\ No newline at end of file
diff --git a/webpage/migrations/0001_initial.py b/webpage/migrations/0001_initial.py
new file mode 100644
index 0000000..722a15a
--- /dev/null
+++ b/webpage/migrations/0001_initial.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2017-01-19 21:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('topics', '0005_resource'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Webpage',
+ fields=[
+ ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='topics.Resource')),
+ ('content', models.TextField(verbose_name='HTML Page Content')),
+ ],
+ options={
+ 'verbose_name': 'WebPage',
+ 'verbose_name_plural': 'WebPages',
+ },
+ bases=('topics.resource',),
+ ),
+ ]
diff --git a/webpage/migrations/__init__.py b/webpage/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webpage/migrations/__init__.py
diff --git a/webpage/models.py b/webpage/models.py
new file mode 100644
index 0000000..3adaae2
--- /dev/null
+++ b/webpage/models.py
@@ -0,0 +1,15 @@
+from django.db import models
+from autoslug.fields import AutoSlugField
+from django.utils.translation import ugettext_lazy as _
+
+from topics.models import Resource
+
+class Webpage(Resource):
+ content = models.TextField(_('HTML Page Content'))
+
+ class Meta:
+ verbose_name = _('WebPage')
+ verbose_name_plural = _('WebPages')
+
+ def __str__(self):
+ return self.name
\ No newline at end of file
diff --git a/webpage/templates/webpages/_form.html b/webpage/templates/webpages/_form.html
new file mode 100644
index 0000000..bdf04f7
--- /dev/null
+++ b/webpage/templates/webpages/_form.html
@@ -0,0 +1,224 @@
+{% load static i18n %}
+{% load widget_tweaks %}
+
+
+
\ No newline at end of file
diff --git a/webpage/templates/webpages/create.html b/webpage/templates/webpages/create.html
new file mode 100644
index 0000000..bdcaaeb
--- /dev/null
+++ b/webpage/templates/webpages/create.html
@@ -0,0 +1,35 @@
+{% extends 'subjects/view.html' %}
+
+{% load static i18n django_bootstrap_breadcrumbs %}
+
+{% block style %}
+ {{block.super}}
+
+{% endblock %}
+
+{% block javascript %}
+ {{block.super}}
+
+
+{% endblock %}
+
+{% block breadcrumbs %}
+ {{ block.super }}
+
+ {% breadcrumb topic 'subjects:view' topic.subject.slug %}
+
+ {% trans 'Create Webpage' as bread %}
+ {% breadcrumb bread 'webpages:create' topic.slug %}
+{% endblock %}
+
+{% block content %}
+
+
+
+ {% include 'webpages/_form.html' %}
+
+
+
+
+
+{% endblock %}
diff --git a/webpage/tests.py b/webpage/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/webpage/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/webpage/urls.py b/webpage/urls.py
new file mode 100644
index 0000000..67e6698
--- /dev/null
+++ b/webpage/urls.py
@@ -0,0 +1,8 @@
+from django.conf.urls import url
+from django.contrib.auth import views as auth_views
+
+from . import views
+
+urlpatterns = [
+ url(r'^create/(?P[\w_-]+)/$', views.CreateView.as_view(), name = 'create'),
+]
diff --git a/webpage/views.py b/webpage/views.py
new file mode 100644
index 0000000..9411b5d
--- /dev/null
+++ b/webpage/views.py
@@ -0,0 +1,56 @@
+from django.shortcuts import get_object_or_404, redirect, render
+from django.views import generic
+from django.contrib import messages
+from django.core.urlresolvers import reverse, reverse_lazy
+from django.utils.translation import ugettext_lazy as _
+from django.contrib.auth.mixins import LoginRequiredMixin
+
+from amadeus.permissions import has_subject_permissions
+
+from topics.models import Topic
+
+from .forms import WebpageForm, InlinePendenciesFormset
+from .models import Webpage
+
+class CreateView(LoginRequiredMixin, generic.edit.CreateView):
+ login_url = reverse_lazy("users:login")
+ redirect_field_name = 'next'
+
+ template_name = 'webpages/create.html'
+ form_class = WebpageForm
+
+ def dispatch(self, request, *args, **kwargs):
+ slug = self.kwargs.get('slug', '')
+ topic = get_object_or_404(Topic, slug = slug)
+
+ if not has_subject_permissions(request.user, topic.subject):
+ return redirect(reverse_lazy('subjects:home'))
+
+ return super(CreateView, self).dispatch(request, *args, **kwargs)
+
+ def get(self, request, *args, **kwargs):
+ self.object = None
+
+ form_class = self.get_form_class()
+ form = self.get_form(form_class)
+ pendencies_form = InlinePendenciesFormset()
+
+ return self.render_to_response(self.get_context_data(form = form,pendencies_form = pendencies_form))
+
+ def get_context_data(self, **kwargs):
+ context = super(CreateView, self).get_context_data(**kwargs)
+
+ context['title'] = _('Create Webpage')
+
+ slug = self.kwargs.get('slug', '')
+ topic = get_object_or_404(Topic, slug = slug)
+
+ context['topic'] = topic
+ context['subject'] = topic.subject
+
+ return context
+
+ def get_success_url(self):
+ messages.success(self.request, _('Topic "%s" was created successfully!')%(self.object.name))
+
+ return reverse_lazy('subjects:view', kwargs = {'slug': self.object.topic.subject.slug})
\ No newline at end of file
--
libgit2 0.21.2