Quellcode durchsuchen

Document template actions are wrking!

Marcos Dumay de Medeiros vor 9 Jahren
Ursprung
Commit
d2cc9cc63d

+ 3 - 0
.gitignore

@@ -52,3 +52,6 @@ ENV/
 #manage.py migrate
 #manage.py createsuperuser
 testproject/db.sqlite3
+
+#Uploaded files of test project
+testproject/media/

+ 39 - 20
src/rapid/forms.py

@@ -1,20 +1,39 @@
-# -*- coding: utf-8 -*-
-
-__author__ = 'marcos.medeiros'
-
-from django import forms
-
-from rapid.models import Profile, Application
-from rapid.wrappers import FieldData
-from rapid.widgets import RapidReadOnly, RapidRelationReadOnly, RapidSelector, rapidAlternativesWidget
-
-class ManageUsers(forms.ModelForm):
-    class Meta:
-        model = Profile
-        fields = '__all__'
-        widgets = {
-            'application': RapidRelationReadOnly(Application),
-            'name': RapidReadOnly(),
-            'description': RapidReadOnly,
-            'users': RapidSelector(FieldData.from_model(Profile, 'users'))
-        }
+# -*- coding: utf-8 -*-
+from django.contrib.contenttypes.models import ContentType
+
+__author__ = 'marcos.medeiros'
+
+from django import forms
+
+from rapid.models import Profile, Application, DocumentTemplate
+from rapid.wrappers import FieldData
+from rapid.widgets import RapidReadOnly, RapidRelationReadOnly, RapidSelector, rapidAlternativesWidget
+
+
+class ManageUsers(forms.ModelForm):
+    class Meta:
+        model = Profile
+        fields = '__all__'
+        widgets = {
+            'application': RapidRelationReadOnly(Application),
+            'name': RapidReadOnly(),
+            'description': RapidReadOnly,
+            'users': RapidSelector(FieldData.from_model(Profile, 'users'))
+        }
+
+
+def getDocumentTemplateForm(model):
+    class AddDocumentTemplate(forms.ModelForm):
+        def save(self, commit=True):
+            obj = super(AddDocumentTemplate, self).save(commit=False)
+            obj.model = ContentType.objects.get_for_model(model)
+            if commit:
+                obj.save()
+                self.save_m2m()
+            return obj
+
+        class Meta(object):
+            model = DocumentTemplate
+            fields = ('name', 'template')
+
+    return AddDocumentTemplate

+ 28 - 0
src/rapid/migrations/0003_documenttemplate.py

@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        ('rapid', '0002_auto_20150918_1921'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='DocumentTemplate',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(max_length=60, verbose_name='nome')),
+                ('template', models.FileField(upload_to=b'rapid/document_templates')),
+                ('model', models.ForeignKey(to='contenttypes.ContentType')),
+            ],
+            options={
+                'verbose_name': 'template de documento',
+                'verbose_name_plural': 'templates de documento',
+            },
+        ),
+    ]

+ 18 - 3
src/rapid/models.py

@@ -1,12 +1,14 @@
 # -*- coding: utf-8 -*-
+from django.contrib.contenttypes.models import ContentType
 
 from django.db import models
 from django.contrib.auth.models import User
 
+
 class Application(models.Model):
     name = models.CharField(max_length=60, unique=True, verbose_name=u"nome")
     python_name = models.CharField(max_length=255, unique=True, verbose_name=u"Nome no Python")
-    managers = models.ManyToManyField(User, verbose_name=u"gestores", related_name='managed_applications')
+    managers = models.ManyToManyField(User, verbose_name=u'gestores', related_name='managed_applications')
     enabled = models.BooleanField(default=True, verbose_name=u"ativa")
 
     def __unicode__(self):
@@ -14,7 +16,7 @@ class Application(models.Model):
 
     url_name = 'aplicacao'
 
-    class Meta:
+    class Meta(object):
         verbose_name = u'aplicação'
         verbose_name_plural = u'aplicações'
 
@@ -29,6 +31,19 @@ class Profile(models.Model):
     def __unicode__(self):
         return self.name
 
-    class Meta:
+    class Meta(object):
         verbose_name = u'perfil'
         verbose_name_plural = u'perfis'
+
+
+class DocumentTemplate(models.Model):
+    name = models.CharField(max_length=60, verbose_name=u'nome')
+    model = models.ForeignKey(ContentType)
+    template = models.FileField(upload_to='rapid/document_templates')
+
+    def __unicode__(self):
+        return self.name
+
+    class Meta(object):
+        verbose_name = u'template de documento'
+        verbose_name_plural = u'templates de documento'

+ 1 - 1
src/rapid/officedocs/rtf.py

@@ -55,7 +55,7 @@ class RtfTemplate(object):
                 elif c == ']':
                     self.brackets -= 1
                     if self.brackets == 0:
-                        ret += ('{'+self.pattern+'}').format(**self.context)
+                        ret += ('{'+self.pattern.strip()+'}').format(**self.context)
                         self.pattern = ''
                     else:
                         self.pattern += c

+ 3 - 2
src/rapid/rapidfields.py

@@ -28,7 +28,7 @@ class AlternativeDataTables(models.ForeignKey):
     Use an AlternativeDataTables model field on AlternativeData represetntations, instead of
     a ForeignKey with ContentTypes.
     """
-    def __init__(self, alternatives, **kwargs):
+    def __init__(self, alternatives=[], **kwargs):
         """
         Receives the same named parameters of a ForeignKey, but instead of a target table,
         receives a list of the tables that may keep the alternative data.
@@ -42,5 +42,6 @@ class AlternativeDataTables(models.ForeignKey):
             #Querying ContentType within a content type is an issue at migrations
             pass
         kwargs['limit_choices_to'] = {'pk__in': pks}
-        super(AlternativeDataTables, self).__init__(ContentType, **kwargs)
+        kwargs['to'] = ContentType
+        super(AlternativeDataTables, self).__init__(**kwargs)
         self.alternatives = alternatives

+ 55 - 11
src/rapid/register.py

@@ -1,20 +1,32 @@
+# coding=utf-8
+
 __author__ = 'marcos'
 
+from django.contrib.contenttypes.models import ContentType
+from rapid.forms import getDocumentTemplateForm
+from rapid.models import DocumentTemplate
 from rapid.views import bare_or_main, ListView, ReadView, UpdateView, CreateView, SelectView, DeleteView,\
-    update_form_class
-from rapid import permissions
+    update_form_class, RenderDocumentView, add_form_class, get_delete_document_template_view
 from rapid.registry import Action, MenuEntry, registry
 
 
 def _rvw(view_class, action_name):
     view_class.action_name = action_name
 
+    # noinspection PyShadowingNames
     def vw(model):
         return bare_or_main(view_class.as_view(model=model))
     return vw
 
 
-_default_actions = [
+def _un_none(v):
+    if v is None:
+        return []
+    else:
+        return [v]
+
+
+_crud_actions = [
     (False, Action("list", "", [], _rvw(ListView, 'list'), "listar", "fa-list")),
     (False, Action("view", "(?P<pk>[0-9]+)", ['pk'], _rvw(ReadView, 'view'), "ver", "fa-eye")),
     (True, Action("edit", "(?P<pk>[0-9]+)", ['pk'], _rvw(UpdateView, 'edit'), "editar", "fa-pencil")),
@@ -24,11 +36,12 @@ _default_actions = [
 ]
 
 
-def model(model, read_set, write_set, actions=None, url_name=None, can_erase=False):
+# noinspection PyShadowingNames
+def crud(model, read_set, write_set, actions=None, url_name=None, can_erase=False):
     if actions:
-        actions = [(edt, a) for edt, a in _default_actions if a.name in actions]
+        actions = [(edt, a) for edt, a in _crud_actions if a.name in actions]
     else:
-        actions = _default_actions
+        actions = _crud_actions
     ret = []
     for edt, a in actions:
         if edt:
@@ -36,24 +49,55 @@ def model(model, read_set, write_set, actions=None, url_name=None, can_erase=Fal
         else:
             ret.append(registry.register_action(a, MenuEntry(model, read_set, url_name=url_name)))
     if can_erase:
-        a =  Action("delete", "(?P<pk>[0-9]+)", ['pk'], _rvw(DeleteView, 'delete'), "apagar", "fa-trash-o")
+        a = Action("delete", "(?P<pk>[0-9]+)", ['pk'], _rvw(DeleteView, 'delete'), "apagar", "fa-trash-o")
         ret.append(registry.register_action(a, MenuEntry(model, write_set, url_name=url_name)))
     return [u for u in ret if u]
 
-
-def instance_form(model, action_name, entry_name, form, permission_set, url_name=None, icon=None, visibility=None):
+# noinspection PyShadowingNames
+def instance_form(model, action_name, entry_name, form, permission_set,
+                  url_name=None, icon=None, visibility=None):
     if not icon:
         icon = ''
     a = Action(action_name, "(?P<pk>[0-9]+)", ['pk'], _rvw(update_form_class(form), action_name),
                entry_name, icon, visibility)
     u = registry.register_action(a, MenuEntry(model, permission_set, url_name=url_name))
-    return [u] if u else []
+    return _un_none(u)
 
 
+# noinspection PyShadowingNames
 def select(model, visible_fields, permission_set, url_name=None):
     class Vw(SelectView):
         fields = visible_fields
     a = Action("select", "", [], _rvw(Vw, 'select'), "selecionar", "fa-hand-o-up",
                visibility=Action.Visibility.hidden)
     u = registry.register_action(a, MenuEntry(model, permission_set, url_name=url_name))
-    return [u] if u else []
+    return _un_none(u)
+
+
+# noinspection PyShadowingNames
+def custom_action(model, action, permission, url_name=None):
+    u = registry.register_action(action, MenuEntry(model, permission, url_name))
+    return _un_none(u)
+
+
+# noinspection PyShadowingNames
+def document_templates(model, templates_permission, render_permission, url_name=None,
+                       render_visibility=Action.Visibility.details):
+    ct_model = ContentType.objects.get_for_model(model)
+    template_generator = lambda n: lambda: ((d.name, [(n, d.pk),],) for
+                                  d in DocumentTemplate.objects.filter(model=ct_model))
+    model_class = model  # renamimg because of clash with the next function argument
+    add_act = Action("add-template", "", (), _rvw(add_form_class(getDocumentTemplateForm(model)), 'add-template'),
+                     "Novo Template", "fa-upload")
+    del_act = Action("del-template", "(?P<pk>[0-9]+)", (),
+                     _rvw(get_delete_document_template_view(model), 'del-template'), "Excluir Template",
+                     'fa-trash-o', pick_generator=template_generator('pk'))
+    render_act = Action("render-template", "(?P<pk>[0-9]+)/(?P<template>[0-9]+)", ('pk',),
+                        RenderDocumentView.as_view,
+                        "Gerar Documento", 'fa-file-word-o', render_visibility,
+                        pick_generator=template_generator('template'),
+                        overlay=Action.Overlay.clear_overlays)
+    add_r = registry.register_action(add_act, MenuEntry(model, templates_permission, url_name=url_name))
+    del_r = registry.register_action(del_act, MenuEntry(model, templates_permission, url_name=url_name))
+    render_r = registry.register_action(render_act, MenuEntry(model, render_permission, url_name=url_name))
+    return _un_none(add_r) + _un_none(del_r) + _un_none(render_r)

+ 17 - 4
src/rapid/registry.py

@@ -43,6 +43,9 @@ class MenuEntry:
 
     def get_url(self, instance=None):
         ats = [(x, getattr(instance, x)) for x in self.action.query_parameters]
+        if self.action.pick_generator:
+            return [(n, reverse(self.url, kwargs=dict(ats + p))) for
+                    n, p in self.action.pick_generator()]
         return reverse(self.url, kwargs=dict(ats))
 
     def __unicode__(self):
@@ -69,7 +72,8 @@ class Action:
     those are defined at the views module.
     """
     def __init__(self, name, url_parameters, query_parameters, view_factory,
-                 verbose_name=None, icon=None, visibility=None):
+                 verbose_name=None, icon=None, visibility=None, pick_generator=None,
+                 overlay=None):
         self.name = name
         self.url_parameters = url_parameters
         self.query_parameters = query_parameters
@@ -77,6 +81,8 @@ class Action:
         self.verbose_name = verbose_name if verbose_name else name
         self.icon = icon
         self.visibility = self.Visibility.details if visibility is None else visibility
+        self.pick_generator = pick_generator
+        self.overlay = overlay if overlay else self.Overlay.better_in_overlay
 
     def __unicode__(self):
         return u"Action: " + self.name
@@ -84,11 +90,16 @@ class Action:
     def __str__(self):
         return str(unicode(self))
 
-    class Visibility:
+    class Visibility(object):
         hidden = 1
         details = 2
         list = 3
 
+    class Overlay(object):
+        better_in_overlay = 'better-in-overlay'
+        this_overlay = ''
+        clear_overlays = 'clear-overlays'
+
 
 class _Registry:
     """
@@ -152,8 +163,10 @@ class _Registry:
             raise Exception("Action " + action.name + " already registered for model " + str(model))
         model_actions[action.name] = entry
         self._models[model] = model_actions
-        return url(r'^%s/%s/%s$' % (entry.url_name, action.name, action.url_parameters),
-                   action.view_factory(model=entry.model, **kwargs), name=entry_url)
+        url_path = r'^%s/%s' % (entry.url_name, action.name)
+        if action.url_parameters:
+            url_path += '/%s' % action.url_parameters
+        return url(url_path+'/?$', action.view_factory(model=entry.model, **kwargs), name=entry_url)
 
 
     def get_url_of_action(self, model, action_name, **kwargs):

+ 54 - 54
src/rapid/templates/rapid/bare/list.html

@@ -1,54 +1,54 @@
-{% load rapid_list %}<span class="must_reload"></span>
-<style scoped>
-    table.object_list > thead > tr > td{
-        padding-left: 0.5em;
-        padding-right: 0.5em;
-        padding-top: 0.5em;
-        padding-bottom: 0.5em;
-        vertical-align: middle;
-    }
-    table.object_list > tbody > tr > td{
-        padding-left: 0.5em;
-        padding-right: 0.5em;
-        vertical-align: middle;
-    }
-    td.list-icons > *{
-        margin-right: 1em;
-    }
-</style>
-<h2>{{model.model_name_plural.title}}</h2>
-<p>{% for a, u in model.actions %}
-	{% if a.action.name != 'list' %}
-		<a href="{{ u }}" class="better-in-overlay btn btn-default"><span class="fa {{ a.action.icon }}">{{ a.action.verbose_name.capitalize }}</span></a>
-	{% endif %}
-{% endfor %}</p>
-{% load rapid_filters %}
-{% model_filters model %}
-<table class="object_list table table-striped">
-    <thead><tr>
-        {% for f in view.fields %}
-        {% field_header f %}
-        {% endfor %}
-        <td><!--Actions-->&nbsp;</td>
-    </tr></thead>
-    <tbody>
-    {% for o in view.values %}
-    <tr>
-        {% for v, iter in o.values %}
-        {% if iter %}
-            <td>
-            {% for val, val_data in v %}
-                {% show_value val val_data %}
-                {% if not forloop.last %}<br>{% endif %}
-            {% endfor %}
-            </td>
-        {% else %}
-            <td>{% show_value v.0 v.1 %}</td>
-        {% endif %}
-        {% endfor %}
-        {% instance_actions o %}
-    </tr>
-    </tbody>
-    {% endfor %}
-</table>
-{% pagination %}
+{% load rapid_list %}{% load rapid_basics %}<span class="must_reload"></span>
+<style scoped>
+    table.object_list > thead > tr > td{
+        padding-left: 0.5em;
+        padding-right: 0.5em;
+        padding-top: 0.5em;
+        padding-bottom: 0.5em;
+        vertical-align: middle;
+    }
+    table.object_list > tbody > tr > td{
+        padding-left: 0.5em;
+        padding-right: 0.5em;
+        vertical-align: middle;
+    }
+    td.list-icons > *{
+        margin-right: 1em;
+    }
+</style>
+<h2>{{model.model_name_plural.title}}</h2>
+<p>{% for a, u in model.actions %}
+    {% if a.action.name != 'list' %}
+        {% show_action a u %}
+    {% endif %}
+{% endfor %}</p>
+{% load rapid_filters %}
+{% model_filters model %}
+<table class="object_list table table-striped">
+    <thead><tr>
+        {% for f in view.fields %}
+        {% field_header f %}
+        {% endfor %}
+        <td><!--Actions-->&nbsp;</td>
+    </tr></thead>
+    <tbody>
+    {% for o in view.values %}
+    <tr>
+        {% for v, iter in o.values %}
+        {% if iter %}
+            <td>
+            {% for val, val_data in v %}
+                {% show_value val val_data %}
+                {% if not forloop.last %}<br>{% endif %}
+            {% endfor %}
+            </td>
+        {% else %}
+            <td>{% show_value v.0 v.1 %}</td>
+        {% endif %}
+        {% endfor %}
+        {% instance_actions o %}
+    </tr>
+    </tbody>
+    {% endfor %}
+</table>
+{% pagination %}

+ 3 - 0
src/rapid/templates/rapid/basics/btn_action.html

@@ -0,0 +1,3 @@
+<a href="{{ link }}" class="{{ action.overlay }} btn btn-default">
+        <span class="fa {{ action.icon }}"></span> {{ action.verbose_name.capitalize }}
+</a>

+ 12 - 0
src/rapid/templates/rapid/basics/pick_action.html

@@ -0,0 +1,12 @@
+<div class="dropdown">
+    <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
+        <span class="fa {{ action.icon }}"></span>
+        {{ action.verbose_name.capitalize }}
+        <span class="caret"></span>
+    </button>
+    <ul class="dropdown-menu" role="menu">
+        {% for n, u in options %}
+        <li><a href="{{ u }}" class="{{ action.overlay }}">{{ n }}</a></li>
+        {% endfor %}
+    </ul>
+</div>

+ 6 - 5
src/rapid/templates/rapid/list/instance_actions.html

@@ -1,5 +1,6 @@
-<td class="list-icons">
-    {% for a, u in o.instance_actions %}
-        <a href="{{ u }}" class="better-in-overlay"><span class="fa {{ a.action.icon }}">{{ a.action.verbose_name.capitalize }}</span></a>
-    {% endfor %}
-</td>
+{% load rapid_basics %}
+<td class="list-icons">
+    {% for a, u in o.instance_actions %}
+        {% show_action a u %}
+    {% endfor %}
+</td>

+ 114 - 112
src/rapid/templates/rapid/overlay/register.html

@@ -1,112 +1,114 @@
-<script>
-    function position_overlay(target){
-        var win_w = $(window).width();
-        var w = target.width();
-        if(w < win_w){
-            var expected_left = (win_w - w) / 2;
-            var ofs = new Object();
-            ofs.left = expected_left;
-            ofs.top = 50;
-            target.offset(ofs);
-        }else{
-            var ofs = new Object();
-            ofs.left = 5;
-            ofs.top = 30;
-            target.offset(ofs);
-        }
-    }
-    function load_overlay(target, url, on_load, on_commit){
-        $.get(url, {}, function(data){
-            target.html(data);
-            overlay_actions(target, url, on_commit);
-            on_load(target);
-            position_overlay(target.closest("div.overlay"));
-        });
-    }
-    function overlay_actions(obj, target_url, on_commit){
-        var overlay = obj.closest(".overlay");
-        var parent_div = overlay.parent();
-        overlay.find(".overlay-close").click(function(event){
-            event.preventDefault();
-            remove_overlay(parent_div);
-        });
-        overlay.find(".overlay-commit").click(function(event){
-            if(on_commit){
-                on_commit(obj);
-                event.preventDefault();
-                remove_overlay(parent_div);
-            }else{
-                remove_overlay(parent_div);
-            }
-        });
-        obj.find("form").each(function(){
-            var ac = $(this).attr("action");
-            if (!ac){
-                $(this).attr("action", target_url);
-            }
-        });
-        if(on_commit){
-            obj.find('form[method="post"]').submit(function(event){
-                event.preventDefault();
-                on_commit(obj);
-				remove_overlay(parent_div);
-            });
-            obj.find('form:not([method="post"])').ajaxForm(function(data){
-                if(data){
-                    obj.html(data);
-					overlay_actions(obj, target_url, on_commit);
-                }else{
-                    remove_overlay(parent_div);
-                }
-            });
-        }else{
-            obj.find("form").ajaxForm(function(data){
-                if(data){
-                    obj.html(data);
-                }else{
-                    remove_overlay(parent_div);
-                }
-            });
-        }
-    }
-    function remove_overlay(obj){
-        var dt_div = obj.parent().closest("div.data");
-        if(dt_div.children("div").children(".must_reload").length > 0){
-            var reload_url = dt_div.children("a.reload").attr("href");
-            $.get(reload_url, function(data){
-                var o = dt_div.children("div.reload-here");
-                o.html(data);
-                overlay_actions(o, reload_url, false);
-                obj.remove();
-            });
-        }else{
-            obj.remove();
-        }
-    }
-    function show_overlay(target_url, source, on_commit){
-        var overlay_text = "{{ overlay_text }}";
-        var o = $("<div/>").html(overlay_text);
-        load_overlay(o.find(".overlay-data"), target_url, function(){
-            source.closest("div.data").append(o);
-        }, on_commit);
-    }
-    $(document).ready(function(){
-        $("body").on("click", "a.better-in-overlay", function(event){
-            if (!event.isDefaultPrevented()){
-                event.preventDefault();
-                var href=$(this).attr("href");
-                show_overlay(href, $(this), false);
-            }
-        });
-        $("body").on("click", "a:not(.better-in-overlay):not(.overlay-close):not(.overlay-commit):not(.interaction)", function(event){
-            if (!event.isDefaultPrevented()){
-                var href=$(this).attr("href");
-                var p = $(this).closest("div.reload-here")
-                if (p.length > 0){
-                    event.preventDefault();
-                    load_overlay(p, href, function(){}, false);
-                }
-            }
-        });
-    });
-</script>
+<script>
+    function position_overlay(target){
+        var win_w = $(window).width();
+        var w = target.width();
+        if(w < win_w){
+            var expected_left = (win_w - w) / 2;
+            var ofs = new Object();
+            ofs.left = expected_left;
+            ofs.top = 50;
+            target.offset(ofs);
+        }else{
+            var ofs = new Object();
+            ofs.left = 5;
+            ofs.top = 30;
+            target.offset(ofs);
+        }
+    }
+    function load_overlay(target, url, on_load, on_commit){
+        $.get(url, {}, function(data){
+            target.html(data);
+            overlay_actions(target, url, on_commit);
+            on_load(target);
+            position_overlay(target.closest("div.overlay"));
+        });
+    }
+    function overlay_actions(obj, target_url, on_commit){
+        var overlay = obj.closest(".overlay");
+        var parent_div = overlay.parent();
+        overlay.find(".overlay-close").click(function(event){
+            event.preventDefault();
+            remove_overlay(parent_div);
+        });
+        overlay.find(".overlay-commit").click(function(event){
+            if(on_commit){
+                on_commit(obj);
+                event.preventDefault();
+                remove_overlay(parent_div);
+            }else{
+                remove_overlay(parent_div);
+            }
+        });
+        obj.find("form").each(function(){
+            var ac = $(this).attr("action");
+            if (!ac){
+                $(this).attr("action", target_url);
+            }
+        });
+        if(on_commit){
+            obj.find('form[method="post"]').submit(function(event){
+                event.preventDefault();
+                on_commit(obj);
+                remove_overlay(parent_div);
+            });
+            obj.find('form:not([method="post"])').ajaxForm(function(data){
+                if(data){
+                    obj.html(data);
+                    overlay_actions(obj, target_url, on_commit);
+                }else{
+                    remove_overlay(parent_div);
+                }
+            });
+        }else{
+            obj.find("form").ajaxForm(function(data){
+                if(data){
+                    obj.html(data);
+                }else{
+                    remove_overlay(parent_div);
+                }
+            });
+        }
+    }
+    function remove_overlay(obj){
+        var dt_div = obj.parent().closest("div.data");
+        if(dt_div.children("div").children(".must_reload").length > 0){
+            var reload_url = dt_div.children("a.reload").attr("href");
+            $.get(reload_url, function(data){
+                var o = dt_div.children("div.reload-here");
+                o.html(data);
+                overlay_actions(o, reload_url, false);
+                obj.remove();
+            });
+        }else{
+            obj.remove();
+        }
+    }
+    function show_overlay(target_url, source, on_commit){
+        var overlay_text = "{{ overlay_text }}";
+        var o = $("<div/>").html(overlay_text);
+        load_overlay(o.find(".overlay-data"), target_url, function(){
+            source.closest("div.data").append(o);
+        }, on_commit);
+    }
+    $(document).ready(function(){
+        $("body").on("click", "a.better-in-overlay", function(event){
+            if (!event.isDefaultPrevented()){
+                event.preventDefault();
+                var href=$(this).attr("href");
+                show_overlay(href, $(this), false);
+            }
+        });
+        $("body").on("click", "a.clear-overlays", function(event){
+        });
+        $("body").on("click", "a:not(.better-in-overlay):not(.overlay-close):not(.overlay-commit):not(.interaction):not(.clear-overlays)", function(event){
+            if (!event.isDefaultPrevented()){
+                var href=$(this).attr("href");
+                var p = $(this).closest("div.reload-here")
+                if (p.length > 0){
+                    event.preventDefault();
+                    load_overlay(p, href, function(){}, false);
+                }
+            }
+        });
+    });
+</script>

+ 6 - 1
src/rapid/templates/rapid/widgets/alternativeForms.html

@@ -21,6 +21,11 @@
         $("div.{{ name }}").addClass("hidden");
         $("div.{{ name }}."+pk).removeClass("hidden");
     });
-    $("div.{{ name }}."+($("#id_{{ selector }}").val())).removeClass("hidden");
+    var sel = $("#id_{{ selector }}").val()
+    $("div.{{ name }}").each(function(){
+        if($(this).hasClass(sel)){
+            $(this).removeClass("hidden");
+        }
+    });
 </script>
 </div>

+ 33 - 0
src/rapid/templatetags/rapid_basics.py

@@ -0,0 +1,33 @@
+# coding=utf-8
+
+__author__ = 'marcos.medeiros'
+
+from django import template
+from django.template import loader, Context
+import random
+from django.utils.safestring import mark_safe
+
+register = template.Library()
+
+_templates_path = 'rapid/basics/'
+
+
+@register.simple_tag
+def show_action(entry, url):
+    action = entry.action
+    if action.pick_generator:
+        t = loader.get_template(_templates_path+'pick_action.html')
+        c = Context({
+            'options': url,
+            'action': action,
+            'entry': entry,
+        })
+        return mark_safe(t.render(c))
+    else:
+        t = loader.get_template(_templates_path+'btn_action.html')
+        c = Context({
+            'link': url,
+            'action': action,
+            'entry': entry,
+        })
+        return mark_safe(t.render(c))

+ 34 - 33
src/rapid/urls.py

@@ -1,33 +1,34 @@
-# -*- coding: utf-8 -*-
-
-__author__ = 'marcos.medeiros'
-
-from django.contrib.auth.models import User
-
-from rapid.registry import Action
-from rapid.models import Application, Profile
-from rapid.forms import ManageUsers
-
-from rapid import register
-from rapid import permissions
-
-def _can_manage_users(request):
-    if not request.user.is_authenticated:
-        return []
-    p = []
-    for a in request.user.managed_applications.all():
-        p.extend(a.profile_set.all())
-    return p
-
-_manage_users_permistion = permissions.Permission(
-    lambda r: False,
-    _can_manage_users
-)
-
-urlpatterns = register.model(Application, write_set=permissions.to_superusers(), read_set=permissions.to_all()) +\
-    register.model(Profile, write_set=permissions.to_superusers(), read_set=permissions.to_staff()) +\
-    register.instance_form(Profile, 'manage_users', u'Gerenciar Usuários',
-                            ManageUsers, _manage_users_permistion, icon="fa-users",
-                            visibility=Action.Visibility.list) +\
-    register.select(User, ['username'], permissions.to_staff(), 'usuario')
-
+# -*- coding: utf-8 -*-
+
+__author__ = 'marcos.medeiros'
+
+from django.contrib.auth.models import User
+
+from rapid.registry import Action
+from rapid.models import Application, Profile
+from rapid.forms import ManageUsers
+
+from rapid import register
+from rapid import permissions
+
+
+def _can_manage_users(request):
+    if not request.user.is_authenticated:
+        return []
+    p = []
+    for a in request.user.managed_applications.all():
+        p.extend(a.profile_set.all())
+    return p
+
+_manage_users_permistion = permissions.Permission(
+    lambda r: False,
+    _can_manage_users
+)
+
+urlpatterns = register.crud(Application, write_set=permissions.to_superusers(), read_set=permissions.to_all()) +\
+    register.crud(Profile, write_set=permissions.to_superusers(), read_set=permissions.to_staff()) +\
+    register.instance_form(Profile, 'manage_users', u'Gerenciar Usuários',
+                            ManageUsers, _manage_users_permistion, icon="fa-users",
+                            visibility=Action.Visibility.list) +\
+    register.select(User, ['username'], permissions.to_staff(), 'usuario')
+

+ 52 - 9
src/rapid/views.py

@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from django.conf import settings
+from django.contrib.contenttypes.models import ContentType
 
 from django.shortcuts import get_object_or_404, redirect
 from django.views import generic
@@ -7,11 +9,14 @@ from django.template import RequestContext
 from django.utils.http import urlquote_plus
 from django.template import loader
 from django.http import HttpResponse
+from rapid.models import DocumentTemplate
+from rapid.officedocs.rtf import RtfTemplate
 from rapid.wrappers import InstanceData, ModelData
 from rapid.filters import FilterSet
 from rapidforms import for_model
-import math
 
+import math
+from os import path
 
 def _build_uri(request, params):
     param_string = "&".join(["%s=%s" % (urlquote_plus(k), urlquote_plus(params[k])) for k in params.keys()])
@@ -48,7 +53,7 @@ class ListView(generic.list.ListView):
     number_of_middle_pages = 5
     fields = None
 
-    class Pagination:
+    class Pagination(object):
         def __init__(self, request, page, number_of_edge_pages, number_of_middle_pages,
                      registers_per_page, total_pages):
             self.request = request
@@ -136,7 +141,7 @@ class ListView(generic.list.ListView):
         def get_page(self, queryset):
             return queryset[self.registers_per_page*(self.page-1):self.registers_per_page*self.page]
 
-    class View:
+    class View(object):
         order_param = 'order'
 
         def __init__(self, request, action_name, model, queryset, fields, pagination):
@@ -173,7 +178,7 @@ class ListView(generic.list.ListView):
             order_param = self.order_param
             request = self.request
 
-            class FieldParams:
+            class FieldParams(object):
                 def __init__(self, field):
                     self.field = field
 
@@ -193,8 +198,8 @@ class ListView(generic.list.ListView):
                 yield f
 
     def get(self, request, **kwargs):
-        mdata = ModelData(self.model, request)
-        if not mdata.has_permission(request, self.action_name):
+        mdt = ModelData(self.model, request)
+        if not mdt.has_permission(request, self.action_name):
             raise PermissionDenied
         object_list = self.get_queryset()
 
@@ -358,15 +363,18 @@ class DeleteView(generic.edit.DeleteView):
     def get_object(self, queryset=None):
         return get_object_or_404(self.model, pk=self.kwargs['pk'])
 
+    def has_permission(self, request, instance):
+        return instance.has_permission(request, self.action_name)
+
     def get(self, request, *args, **kwargs):
         obj = InstanceData(self.get_object())
-        if not obj.has_permission(request, self.action_name):
+        if not self.has_permission(request, obj):
             raise PermissionDenied
         return super(DeleteView, self).get(request, *args, **kwargs)
 
     def post(self, request, *args, **kwargs):
         obj = InstanceData(self.get_object())
-        if not obj.has_permission(request, self.action_name):
+        if not self.has_permission(request, obj):
             raise PermissionDenied
         return super(DeleteView, self).post(request, *args, **kwargs)
 
@@ -393,7 +401,8 @@ def bare_or_main(view):
                 ret['X-FORM-STATUS:'] = 'success'
                 return ret
         if not bare and resp.status_code == 200 and request.method != "HEAD":
-            resp.render()
+            if hasattr(resp, 'render'):
+                resp.render()
             body = resp.content
             main_win = loader.get_template(main_window_template)
             context = RequestContext(request)
@@ -408,3 +417,37 @@ def update_form_class(form):
         def request_form(self, request):
             return form
     return F
+
+
+def add_form_class(form):
+    class F(CreateView):
+        def request_form(self, request):
+            return form
+    return F
+
+
+class RenderDocumentView(generic.View):
+    model = None
+    action_name = None
+
+    # noinspection PyUnusedLocal
+    def get(self, request, pk, template):
+        inst = get_object_or_404(self.model, pk=pk)
+        ctx = inst.__dict__
+        tm = get_object_or_404(DocumentTemplate, model=ContentType.objects.get_for_model(self.model), pk=template)
+        f = path.join(settings.MEDIA_ROOT, tm.template.name)
+        t = RtfTemplate(f, ctx)
+        return HttpResponse(t.read(), content_type='application/rtf')
+
+
+def get_delete_document_template_view(model):
+    class DeleteDocumentTemplateView(DeleteView):
+        def get_object(self, queryset=None):
+            return get_object_or_404(DocumentTemplate, pk=self.kwargs['pk'])
+
+        def has_permission(self, request, instance):
+            if not ModelData(model).has_permission(request, self.action_name):
+                return False
+            return instance.instance.model == ContentType.objects.get_for_model(model)
+
+    return DeleteDocumentTemplateView

+ 2 - 0
testproject/testproject/settings.py

@@ -103,3 +103,5 @@ USE_TZ = True
 # https://docs.djangoproject.com/en/1.8/howto/static-files/
 
 STATIC_URL = '/static/'
+
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 1
testproject/testproject/static/js/jquery.js


+ 3 - 1
testproject/testproject/urls.py

@@ -18,4 +18,6 @@ urlpatterns = [
 ]
 
 for m in (models.Test1, models.AltData1, models.AltData2):
-    urlpatterns += register.model(m, permissions.to_all(), permissions.to_all())
+    urlpatterns += register.crud(m, permissions.to_all(), permissions.to_all())
+
+urlpatterns += register.document_templates(models.Test1, permissions.to_all(), permissions.to_all())

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.