summaryrefslogtreecommitdiff
path: root/gstudio/admin
diff options
context:
space:
mode:
authorgnowgi <nagarjun@gnowledge.org>2012-03-15 16:19:20 +0530
committergnowgi <nagarjun@gnowledge.org>2012-03-15 16:19:20 +0530
commit7a4f561e851fdc7246d804c3abb6748b8a4199a6 (patch)
treed2afc3463fd49625a9be482012f5c3bfcf7c42b9 /gstudio/admin
downloadgnowsys-7a4f561e851fdc7246d804c3abb6748b8a4199a6.tar.gz
master trunk of gnowsys-studio
Diffstat (limited to 'gstudio/admin')
-rw-r--r--gstudio/admin/__init__.py118
-rw-r--r--gstudio/admin/attribute.py20
-rw-r--r--gstudio/admin/attribute_bigintegerfield.py9
-rw-r--r--gstudio/admin/attribute_booleanfield.py9
-rw-r--r--gstudio/admin/attribute_charfield.py10
-rw-r--r--gstudio/admin/attribute_commaseparatedintegerfield.py9
-rw-r--r--gstudio/admin/attribute_datefield.py9
-rw-r--r--gstudio/admin/attribute_datetimefield.py9
-rw-r--r--gstudio/admin/attribute_decimalfield.py9
-rw-r--r--gstudio/admin/attribute_emailfield.py9
-rw-r--r--gstudio/admin/attribute_filefield.py9
-rw-r--r--gstudio/admin/attribute_filepathfield.py9
-rw-r--r--gstudio/admin/attribute_floatfield.py9
-rw-r--r--gstudio/admin/attribute_imagefield.py9
-rw-r--r--gstudio/admin/attribute_integerfield.py9
-rw-r--r--gstudio/admin/attribute_ipaddressfield.py9
-rw-r--r--gstudio/admin/attribute_nullbooleanfield.py9
-rw-r--r--gstudio/admin/attribute_positiveintegerfield.py9
-rw-r--r--gstudio/admin/attribute_textfield.py9
-rw-r--r--gstudio/admin/attribute_timefield.py9
-rw-r--r--gstudio/admin/attribute_urlfield.py9
-rw-r--r--gstudio/admin/attributespecification.py10
-rw-r--r--gstudio/admin/attributetype.py352
-rw-r--r--gstudio/admin/complement.py9
-rw-r--r--gstudio/admin/expression.py13
-rw-r--r--gstudio/admin/forms.py505
-rw-r--r--gstudio/admin/intersection.py9
-rw-r--r--gstudio/admin/metatype.py30
-rw-r--r--gstudio/admin/nodespecification.py9
-rw-r--r--gstudio/admin/objecttype.py345
-rw-r--r--gstudio/admin/processtype.py349
-rw-r--r--gstudio/admin/relation.py13
-rw-r--r--gstudio/admin/relationspecification.py9
-rw-r--r--gstudio/admin/relationtype.py362
-rw-r--r--gstudio/admin/systemtype.py352
-rw-r--r--gstudio/admin/union.py9
-rw-r--r--gstudio/admin/widgets.py107
37 files changed, 2793 insertions, 0 deletions
diff --git a/gstudio/admin/__init__.py b/gstudio/admin/__init__.py
new file mode 100644
index 0000000..030e056
--- /dev/null
+++ b/gstudio/admin/__init__.py
@@ -0,0 +1,118 @@
+"""Admin of Gstudio"""
+from django.contrib import admin
+
+#Models import
+from gstudio.models import Objecttype
+from gstudio.models import Metatype
+from gstudio.models import Relation
+from gstudio.models import Relationtype
+from gstudio.models import Attribute
+from gstudio.models import Attributetype
+from gstudio.models import Systemtype
+from gstudio.models import Processtype
+from gstudio.models import AttributeSpecification
+from gstudio.models import RelationSpecification
+from gstudio.models import NodeSpecification
+from gstudio.models import Union
+from gstudio.models import Complement
+from gstudio.models import Intersection
+from gstudio.models import Expression
+from gstudio.models import AttributeCharField
+from gstudio.models import AttributeTextField
+from gstudio.models import AttributeIntegerField
+from gstudio.models import AttributeCommaSeparatedIntegerField
+from gstudio.models import AttributeBigIntegerField
+from gstudio.models import AttributePositiveIntegerField
+from gstudio.models import AttributeDecimalField
+from gstudio.models import AttributeFloatField
+from gstudio.models import AttributeBooleanField
+from gstudio.models import AttributeNullBooleanField
+from gstudio.models import AttributeDateField
+from gstudio.models import AttributeDateTimeField
+from gstudio.models import AttributeTimeField
+from gstudio.models import AttributeEmailField
+from gstudio.models import AttributeFileField
+from gstudio.models import AttributeFilePathField
+from gstudio.models import AttributeImageField
+from gstudio.models import AttributeURLField
+from gstudio.models import AttributeIPAddressField
+
+#Admin imports
+
+from gstudio.admin.objecttype import ObjecttypeAdmin
+from gstudio.admin.metatype import MetatypeAdmin
+from gstudio.admin.relationtype import RelationtypeAdmin
+from gstudio.admin.relation import RelationAdmin
+from gstudio.admin.attribute import AttributeAdmin
+from gstudio.admin.attributetype import AttributetypeAdmin
+from gstudio.admin.attributespecification import AttributeSpecificationAdmin
+from gstudio.admin.relationspecification import RelationSpecificationAdmin
+from gstudio.admin.nodespecification import NodeSpecificationAdmin
+from gstudio.admin.union import UnionAdmin
+from gstudio.admin.complement import ComplementAdmin
+from gstudio.admin.intersection import IntersectionAdmin
+from gstudio.admin.expression import ExpressionAdmin
+from gstudio.admin.systemtype import SystemtypeAdmin
+from gstudio.admin.processtype import ProcesstypeAdmin
+
+from gstudio.admin.attribute_charfield import AttributeCharFieldAdmin
+from gstudio.admin.attribute_textfield import AttributeTextFieldAdmin
+from gstudio.admin.attribute_integerfield import AttributeIntegerFieldAdmin
+from gstudio.admin.attribute_commaseparatedintegerfield import AttributeCommaSeparatedIntegerFieldAdmin
+from gstudio.admin.attribute_bigintegerfield import AttributeBigIntegerFieldAdmin
+from gstudio.admin.attribute_positiveintegerfield import AttributePositiveIntegerFieldAdmin
+from gstudio.admin.attribute_decimalfield import AttributeDecimalFieldAdmin
+from gstudio.admin.attribute_floatfield import AttributeFloatFieldAdmin
+from gstudio.admin.attribute_booleanfield import AttributeBooleanFieldAdmin
+from gstudio.admin.attribute_nullbooleanfield import AttributeNullBooleanFieldAdmin
+from gstudio.admin.attribute_datefield import AttributeDateFieldAdmin
+from gstudio.admin.attribute_datetimefield import AttributeDateTimeFieldAdmin
+from gstudio.admin.attribute_timefield import AttributeTimeFieldAdmin
+from gstudio.admin.attribute_emailfield import AttributeEmailFieldAdmin
+from gstudio.admin.attribute_filefield import AttributeFileFieldAdmin
+from gstudio.admin.attribute_filepathfield import AttributeFilePathFieldAdmin
+from gstudio.admin.attribute_imagefield import AttributeImageFieldAdmin
+from gstudio.admin.attribute_urlfield import AttributeURLFieldAdmin
+from gstudio.admin.attribute_ipaddressfield import AttributeIPAddressFieldAdmin
+
+
+
+
+
+admin.site.register(Objecttype, ObjecttypeAdmin)
+admin.site.register(Metatype, MetatypeAdmin)
+admin.site.register(Relationtype, RelationtypeAdmin)
+admin.site.register(Relation, RelationAdmin)
+admin.site.register(Attribute, AttributeAdmin)
+admin.site.register(Attributetype, AttributetypeAdmin)
+
+admin.site.register(Systemtype, SystemtypeAdmin)
+admin.site.register(Processtype, ProcesstypeAdmin)
+admin.site.register(AttributeSpecification, AttributeSpecificationAdmin)
+admin.site.register(RelationSpecification, RelationSpecificationAdmin)
+admin.site.register(NodeSpecification, NodeSpecificationAdmin)
+admin.site.register(Union, UnionAdmin)
+admin.site.register(Complement, ComplementAdmin)
+admin.site.register(Intersection, IntersectionAdmin)
+admin.site.register(Expression, ExpressionAdmin)
+
+admin.site.register(AttributeCharField, AttributeCharFieldAdmin)
+admin.site.register(AttributeTextField, AttributeTextFieldAdmin)
+admin.site.register(AttributeIntegerField, AttributeIntegerFieldAdmin)
+admin.site.register(AttributeCommaSeparatedIntegerField, AttributeCommaSeparatedIntegerFieldAdmin)
+admin.site.register(AttributeBigIntegerField,AttributeBigIntegerFieldAdmin)
+admin.site.register(AttributePositiveIntegerField, AttributePositiveIntegerFieldAdmin)
+admin.site.register(AttributeDecimalField, AttributeDecimalFieldAdmin)
+admin.site.register(AttributeFloatField, AttributeFloatFieldAdmin)
+admin.site.register(AttributeBooleanField, AttributeBooleanFieldAdmin)
+admin.site.register(AttributeNullBooleanField, AttributeNullBooleanFieldAdmin)
+admin.site.register(AttributeDateField, AttributeDateFieldAdmin)
+admin.site.register(AttributeDateTimeField, AttributeDateTimeFieldAdmin)
+admin.site.register(AttributeTimeField,AttributeTimeFieldAdmin)
+admin.site.register(AttributeEmailField, AttributeEmailFieldAdmin)
+admin.site.register(AttributeFileField, AttributeFileFieldAdmin)
+admin.site.register(AttributeFilePathField, AttributeFilePathFieldAdmin)
+admin.site.register(AttributeImageField, AttributeImageFieldAdmin)
+admin.site.register(AttributeURLField, AttributeURLFieldAdmin)
+admin.site.register(AttributeIPAddressField, AttributeIPAddressFieldAdmin)
+
diff --git a/gstudio/admin/attribute.py b/gstudio/admin/attribute.py
new file mode 100644
index 0000000..336509e
--- /dev/null
+++ b/gstudio/admin/attribute.py
@@ -0,0 +1,20 @@
+"""MetatypeAdmin for Gstudio"""
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+from django.utils.html import escape
+from gstudio.admin.forms import AttributeAdminForm
+from gstudio.models import *
+import reversion
+
+class AttributeAdmin(reversion.VersionAdmin):
+ class Media:
+ js = ("gstudio/js/gstudiojs.js",)
+
+ def save_model(self, request, attribute, form, change):
+ attribute.title = attribute.composed_attribution
+ attribute.save()
+
+
+
+
diff --git a/gstudio/admin/attribute_bigintegerfield.py b/gstudio/admin/attribute_bigintegerfield.py
new file mode 100644
index 0000000..53085fb
--- /dev/null
+++ b/gstudio/admin/attribute_bigintegerfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeBigIntegerFieldAdminForm
+import reversion
+
+class AttributeBigIntegerFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_booleanfield.py b/gstudio/admin/attribute_booleanfield.py
new file mode 100644
index 0000000..e6ce41f
--- /dev/null
+++ b/gstudio/admin/attribute_booleanfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeBooleanFieldAdminForm
+import reversion
+
+class AttributeBooleanFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_charfield.py b/gstudio/admin/attribute_charfield.py
new file mode 100644
index 0000000..138d89d
--- /dev/null
+++ b/gstudio/admin/attribute_charfield.py
@@ -0,0 +1,10 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeCharFieldAdminForm
+import reversion
+
+class AttributeCharFieldAdmin(reversion.VersionAdmin):
+ pass
+
diff --git a/gstudio/admin/attribute_commaseparatedintegerfield.py b/gstudio/admin/attribute_commaseparatedintegerfield.py
new file mode 100644
index 0000000..4202f61
--- /dev/null
+++ b/gstudio/admin/attribute_commaseparatedintegerfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeCommaSeparatedIntegerFieldAdminForm
+import reversion
+
+class AttributeCommaSeparatedIntegerFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_datefield.py b/gstudio/admin/attribute_datefield.py
new file mode 100644
index 0000000..9619547
--- /dev/null
+++ b/gstudio/admin/attribute_datefield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeDateFieldAdminForm
+import reversion
+
+class AttributeDateFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_datetimefield.py b/gstudio/admin/attribute_datetimefield.py
new file mode 100644
index 0000000..bdbdfa5
--- /dev/null
+++ b/gstudio/admin/attribute_datetimefield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeDateTimeFieldAdminForm
+import reversion
+
+class AttributeDateTimeFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_decimalfield.py b/gstudio/admin/attribute_decimalfield.py
new file mode 100644
index 0000000..168ad06
--- /dev/null
+++ b/gstudio/admin/attribute_decimalfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeDecimalFieldAdminForm
+import reversion
+
+class AttributeDecimalFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_emailfield.py b/gstudio/admin/attribute_emailfield.py
new file mode 100644
index 0000000..8173f2c
--- /dev/null
+++ b/gstudio/admin/attribute_emailfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeEmailFieldAdminForm
+import reversion
+
+class AttributeEmailFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_filefield.py b/gstudio/admin/attribute_filefield.py
new file mode 100644
index 0000000..a2553c6
--- /dev/null
+++ b/gstudio/admin/attribute_filefield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeFileFieldAdminForm
+import reversion
+
+class AttributeFileFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_filepathfield.py b/gstudio/admin/attribute_filepathfield.py
new file mode 100644
index 0000000..76d483d
--- /dev/null
+++ b/gstudio/admin/attribute_filepathfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeFilePathFieldAdminForm
+import reversion
+
+class AttributeFilePathFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_floatfield.py b/gstudio/admin/attribute_floatfield.py
new file mode 100644
index 0000000..0f97b7c
--- /dev/null
+++ b/gstudio/admin/attribute_floatfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeFloatFieldAdminForm
+import reversion
+
+class AttributeFloatFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_imagefield.py b/gstudio/admin/attribute_imagefield.py
new file mode 100644
index 0000000..80515a6
--- /dev/null
+++ b/gstudio/admin/attribute_imagefield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeImageFieldAdminForm
+import reversion
+
+class AttributeImageFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_integerfield.py b/gstudio/admin/attribute_integerfield.py
new file mode 100644
index 0000000..a170c95
--- /dev/null
+++ b/gstudio/admin/attribute_integerfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeIntegerFieldAdminForm
+import reversion
+
+class AttributeIntegerFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_ipaddressfield.py b/gstudio/admin/attribute_ipaddressfield.py
new file mode 100644
index 0000000..1fa9a1b
--- /dev/null
+++ b/gstudio/admin/attribute_ipaddressfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeIPAddressFieldAdminForm
+import reversion
+
+class AttributeIPAddressFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_nullbooleanfield.py b/gstudio/admin/attribute_nullbooleanfield.py
new file mode 100644
index 0000000..fba5208
--- /dev/null
+++ b/gstudio/admin/attribute_nullbooleanfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeNullBooleanFieldAdminForm
+import reversion
+
+class AttributeNullBooleanFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_positiveintegerfield.py b/gstudio/admin/attribute_positiveintegerfield.py
new file mode 100644
index 0000000..1404449
--- /dev/null
+++ b/gstudio/admin/attribute_positiveintegerfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributePositiveIntegerFieldAdminForm
+import reversion
+
+class AttributePositiveIntegerFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_textfield.py b/gstudio/admin/attribute_textfield.py
new file mode 100644
index 0000000..7786af1
--- /dev/null
+++ b/gstudio/admin/attribute_textfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeTextFieldAdminForm
+import reversion
+
+class AttributeTextFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_timefield.py b/gstudio/admin/attribute_timefield.py
new file mode 100644
index 0000000..929b028
--- /dev/null
+++ b/gstudio/admin/attribute_timefield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeTimeFieldAdminForm
+import reversion
+
+class AttributeTimeFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attribute_urlfield.py b/gstudio/admin/attribute_urlfield.py
new file mode 100644
index 0000000..952beec
--- /dev/null
+++ b/gstudio/admin/attribute_urlfield.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeURLFieldAdminForm
+import reversion
+
+class AttributeURLFieldAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attributespecification.py b/gstudio/admin/attributespecification.py
new file mode 100644
index 0000000..3e7f6e1
--- /dev/null
+++ b/gstudio/admin/attributespecification.py
@@ -0,0 +1,10 @@
+
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import AttributeSpecificationAdminForm
+import reversion
+
+class AttributeSpecificationAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/attributetype.py b/gstudio/admin/attributetype.py
new file mode 100644
index 0000000..c1f03d9
--- /dev/null
+++ b/gstudio/admin/attributetype.py
@@ -0,0 +1,352 @@
+"""AttributetypeAdmin for Gstudio"""
+from datetime import datetime
+
+from django.forms import Media
+from django.contrib import admin
+from django.contrib.auth.models import User
+from django.utils.html import strip_tags
+from django.utils.text import truncate_words
+from django.conf.urls.defaults import url
+from django.conf.urls.defaults import patterns
+from django.conf import settings as project_settings
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse, NoReverseMatch
+
+from tagging.models import Tag
+
+import reversion
+from gstudio import settings
+from gstudio.managers import HIDDEN
+from gstudio.managers import PUBLISHED
+from gstudio.ping import DirectoryPinger
+from gstudio.admin.forms import AttributetypeAdminForm
+
+
+
+
+class AttributetypeAdmin(reversion.VersionAdmin):
+ """Admin for Attributetype model"""
+ form = AttributetypeAdminForm
+ date_hierarchy = 'creation_date'
+ fieldsets = ((_('Attribute Definiton'), {'fields': ('title','altnames','subjecttype','applicable_node\
+types','dataType','verbose_name','null','blank','help_text','max_digits','decimal_places','auto_now','auto_now_add','upload_to','path','verify_exists','parent','slug','status') }),
+
+ (_('Content'), {'fields': ('content', 'image',),
+ 'classes': ('collapse', 'collapse-closed')}),
+
+
+ (_('Dependency'), {'fields': ('prior_nodes', 'posterior_nodes',),
+
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Options'), {'fields': ('featured', 'excerpt', 'template',
+ 'authors',
+ 'creation_date',
+ 'start_publication',
+ 'end_publication'),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Privacy'), {'fields': ('password', 'login_required',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Publication'), {'fields': ('tags',
+ 'sites')}))
+
+
+ list_filter = ('parent','metatypes', 'authors', 'status', 'featured',
+ 'login_required', 'comment_enabled', 'pingback_enabled',
+ 'creation_date', 'start_publication',
+ 'end_publication', 'sites')
+ list_display = ('get_title', 'get_authors', 'get_metatypes',
+ 'get_tags', 'get_sites',
+ 'get_comments_are_open', 'pingback_enabled',
+ 'get_is_actual', 'get_is_visible', 'get_link',
+ 'get_short_url', 'creation_date')
+ radio_fields = {'template': admin.VERTICAL}
+ filter_horizontal = ('metatypes', 'authors')
+ prepopulated_fields = {'slug': ('title', )}
+ search_fields = ('title', 'excerpt', 'content', 'tags')
+ actions = ['make_mine', 'make_published', 'make_hidden',
+ 'close_comments', 'close_pingbacks',
+ 'ping_directories', 'make_tweet', 'put_on_top']
+ actions_on_top = True
+ actions_on_bottom = True
+
+ def __init__(self, model, admin_site):
+ self.form.admin_site = admin_site
+ super(AttributetypeAdmin, self).__init__(model, admin_site)
+
+ # Custom Display
+ def get_title(self, attributetype):
+ """Return the title with word count and number of comments"""
+ title = _('%(title)s (%(word_count)i words)') % \
+ {'title': attributetype.title, 'word_count': attributetype.word_count}
+ comments = attributetype.comments.count()
+ if comments:
+ return _('%(title)s (%(comments)i comments)') % \
+ {'title': title, 'comments': comments}
+ return title
+ get_title.short_description = _('title')
+
+ def get_authors(self, attributetype):
+ """Return the authors in HTML"""
+ try:
+ authors = ['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_author_detail',
+ args=[author.username]),
+ author.username) for author in attributetype.authors.all()]
+ except NoReverseMatch:
+ authors = [author.username for author in attributetype.authors.all()]
+ return ', '.join(authors)
+ get_authors.allow_tags = True
+ get_authors.short_description = _('author(s)')
+
+ def get_metatypes(self, attributetype):
+ """Return the metatypes linked in HTML"""
+ try:
+ metatypes = ['<a href="%s" target="blank">%s</a>' %
+ (metatype.get_absolute_url(), metatype.title)
+ for metatype in attributetype.metatypes.all()]
+ except NoReverseMatch:
+ metatypes = [metatype.title for metatype in
+ attributetype.metatypes.all()]
+ return ', '.join(metatypes)
+ get_metatypes.allow_tags = True
+ get_metatypes.short_description = _('metatype(s)')
+
+ def get_tags(self, attributetype):
+ """Return the tags linked in HTML"""
+ try:
+ return ', '.join(['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_tag_detail',
+ args=[tag.name]), tag.name)
+ for tag in Tag.attributes.get_for_attribute(attributetype)])
+ except NoReverseMatch:
+ return attributetype.tags
+ get_tags.allow_tags = True
+ get_tags.short_description = _('tag(s)')
+
+ def get_sites(self, attributetype):
+ """Return the sites linked in HTML"""
+ return ', '.join(
+ ['<a href="http://%(domain)s" target="blank">%(name)s</a>' %
+ site.__dict__ for site in attributetype.sites.all()])
+ get_sites.allow_tags = True
+ get_sites.short_description = _('site(s)')
+
+ def get_comments_are_open(self, attributetype):
+ """Admin wrapper for attributetype.comments_are_open"""
+ return attributetype.comments_are_open
+ get_comments_are_open.boolean = True
+ get_comments_are_open.short_description = _('comment enabled')
+
+ def get_is_actual(self, attributetype):
+ """Admin wrapper for attributetype.is_actual"""
+ return attributetype.is_actual
+ get_is_actual.boolean = True
+ get_is_actual.short_description = _('is actual')
+
+ def get_is_visible(self, attributetype):
+ """Admin wrapper for attributetype.is_visible"""
+ return attributetype.is_visible
+ get_is_visible.boolean = True
+ get_is_visible.short_description = _('is visible')
+
+ def get_link(self, attributetype):
+ """Return a formated link to the attributetype"""
+ return u'<a href="%s" target="blank">%s</a>' % (
+ attributetype.get_absolute_url(), _('View'))
+ get_link.allow_tags = True
+ get_link.short_description = _('View on site')
+
+ def get_short_url(self, attributetype):
+ """Return the short url in HTML"""
+ short_url = attributetype.short_url
+ if not short_url:
+ return _('Unavailable')
+ return '<a href="%(url)s" target="blank">%(url)s</a>' % \
+ {'url': short_url}
+ get_short_url.allow_tags = True
+ get_short_url.short_description = _('short url')
+
+ # Custom Methods
+ def save_model(self, request, attributetype, form, change):
+ """Save the authors, update time, make an excerpt"""
+ if not form.cleaned_data.get('excerpt') and attributetype.status == PUBLISHED:
+ attributetype.excerpt = truncate_words(strip_tags(attributetype.content), 50)
+
+ if attributetype.pk and not request.user.has_perm('gstudio.can_change_author'):
+ form.cleaned_data['authors'] = attributetype.authors.all()
+
+ if not form.cleaned_data.get('authors'):
+ form.cleaned_data['authors'].append(request.user)
+
+ attributetype.last_update = datetime.now()
+ attributetype.save()
+
+ def queryset(self, request):
+ """Make special filtering by user permissions"""
+ queryset = super(AttributetypeAdmin, self).queryset(request)
+ if request.user.has_perm('gstudio.can_view_all'):
+ return queryset
+ return request.user.attributetypes.all()
+
+ def formfield_for_manytomany(self, db_field, request, **kwargs):
+ """Filters the disposable authors"""
+ if db_field.name == 'authors':
+ if request.user.has_perm('gstudio.can_change_author'):
+ kwargs['queryset'] = User.objects.filter(is_staff=True)
+ else:
+ kwargs['queryset'] = User.objects.filter(pk=request.user.pk)
+
+ return super(AttributetypeAdmin, self).formfield_for_manytomany(
+ db_field, request, **kwargs)
+
+ def get_actions(self, request):
+ """Define user actions by permissions"""
+ actions = super(AttributetypeAdmin, self).get_actions(request)
+ if not request.user.has_perm('gstudio.can_change_author') \
+ or not request.user.has_perm('gstudio.can_view_all'):
+ del actions['make_mine']
+ if not settings.PING_DIRECTORIES:
+ del actions['ping_directories']
+ if not settings.USE_TWITTER:
+ del actions['make_tweet']
+
+ return actions
+
+ # Custom Actions
+ def make_mine(self, request, queryset):
+ """Set the attributetypes to the user"""
+ for attributetype in queryset:
+ if request.user not in attributetype.authors.all():
+ attributetype.authors.add(request.user)
+ self.message_user(
+ request, _('The selected attributetypes now belong to you.'))
+ make_mine.short_description = _('Set the attributetypes to the user')
+
+ def make_published(self, request, queryset):
+ """Set attributetypes selected as published"""
+ queryset.update(status=PUBLISHED)
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(
+ request, _('The selected attributetypes are now marked as published.'))
+ make_published.short_description = _('Set attributetypes selected as published')
+
+ def make_hidden(self, request, queryset):
+ """Set attributetypes selected as hidden"""
+ queryset.update(status=HIDDEN)
+ self.message_user(
+ request, _('The selected attributetypes are now marked as hidden.'))
+ make_hidden.short_description = _('Set attributetypes selected as hidden')
+
+ def make_tweet(self, request, queryset):
+ """Post an update on Twitter"""
+ import tweepy
+ auth = tweepy.OAuthHandler(settings.TWITTER_CONSUMER_KEY,
+ settings.TWITTER_CONSUMER_SECRET)
+ auth.set_access_token(settings.TWITTER_ACCESS_KEY,
+ settings.TWITTER_ACCESS_SECRET)
+ api = tweepy.API(auth)
+ for attributetype in queryset:
+ short_url = attributetype.short_url
+ message = '%s %s' % (attributetype.title[:139 - len(short_url)], short_url)
+ api.update_status(message)
+ self.message_user(
+ request, _('The selected attributetypes have been tweeted.'))
+ make_tweet.short_description = _('Tweet attributetypes selected')
+
+ def close_comments(self, request, queryset):
+ """Close the comments for selected attributetypes"""
+ queryset.update(comment_enabled=False)
+ self.message_user(
+ request, _('Comments are now closed for selected attributetypes.'))
+ close_comments.short_description = _('Close the comments for '\
+ 'selected attributetypes')
+
+ def close_pingbacks(self, request, queryset):
+ """Close the pingbacks for selected attributetypes"""
+ queryset.update(pingback_enabled=False)
+ self.message_user(
+ request, _('Linkbacks are now closed for selected attributetypes.'))
+ close_pingbacks.short_description = _(
+ 'Close the linkbacks for selected attributetypes')
+
+ def put_on_top(self, request, queryset):
+ """Put the selected attributetypes on top at the current date"""
+ queryset.update(creation_date=datetime.now())
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(request, _(
+ 'The selected attributetypes are now set at the current date.'))
+ put_on_top.short_description = _(
+ 'Put the selected attributetypes on top at the current date')
+
+ def ping_directories(self, request, queryset, messages=True):
+ """Ping Directories for selected attributetypes"""
+ for directory in settings.PING_DIRECTORIES:
+ pinger = DirectoryPinger(directory, queryset)
+ pinger.join()
+ if messages:
+ success = 0
+ for result in pinger.results:
+ if not result.get('flerror', True):
+ success += 1
+ else:
+ self.message_user(request,
+ '%s : %s' % (directory,
+ result['message']))
+ if success:
+ self.message_user(
+ request,
+ _('%(directory)s directory succesfully ' \
+ 'pinged %(success)d attributetypes.') %
+ {'directory': directory, 'success': success})
+ ping_directories.short_description = _(
+ 'Ping Directories for selected attributetypes')
+
+ def get_urls(self):
+ attributetype_admin_urls = super(AttributetypeAdmin, self).get_urls()
+ urls = patterns(
+ 'django.views.generic.simple',
+ url(r'^autocomplete_tags/$', 'direct_to_template',
+ {'template': 'admin/gstudio/attributetype/autocomplete_tags.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_attributetype_autocomplete_tags'),
+ url(r'^wymeditor/$', 'direct_to_template',
+ {'template': 'admin/gstudio/attributetype/wymeditor.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_attributetype_wymeditor'),
+ url(r'^markitup/$', 'direct_to_template',
+ {'template': 'admin/gstudio/attributetype/markitup.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_attributetype_markitup'),)
+ return urls + attributetype_admin_urls
+
+ def _media(self):
+ STATIC_URL = '%sgstudio/' % project_settings.STATIC_URL
+ media = super(AttributetypeAdmin, self).media + Media(
+ css={'all': ('%scss/jquery.autocomplete.css' % STATIC_URL,)},
+ js=('%sjs/jquery.js' % STATIC_URL,
+ '%sjs/jquery.bgiframe.js' % STATIC_URL,
+ '%sjs/jquery.autocomplete.js' % STATIC_URL,
+ reverse('admin:gstudio_attributetype_autocomplete_tags'),))
+
+ if settings.WYSIWYG == 'wymeditor':
+ media += Media(
+ js=('%sjs/wymeditor/jquery.wymeditor.pack.js' % STATIC_URL,
+ '%sjs/wymeditor/plugins/hovertools/'
+ 'jquery.wymeditor.hovertools.js' % STATIC_URL,
+ reverse('admin:gstudio_attributetype_wymeditor')))
+ elif settings.WYSIWYG == 'tinymce':
+ from tinymce.widgets import TinyMCE
+ media += TinyMCE().media + Media(
+ js=(reverse('tinymce-js', args=('admin/gstudio/attributetype',)),))
+ elif settings.WYSIWYG == 'markitup':
+ media += Media(
+ js=('%sjs/markitup/jquery.markitup.js' % STATIC_URL,
+ '%sjs/markitup/sets/%s/set.js' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE),
+ reverse('admin:gstudio_attributetype_markitup')),
+ css={'all': (
+ '%sjs/markitup/skins/django/style.css' % STATIC_URL,
+ '%sjs/markitup/sets/%s/style.css' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE))})
+ return media
+ media = property(_media)
diff --git a/gstudio/admin/complement.py b/gstudio/admin/complement.py
new file mode 100644
index 0000000..b35ad6c
--- /dev/null
+++ b/gstudio/admin/complement.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import ComplementAdminForm
+import reversion
+
+class ComplementAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/expression.py b/gstudio/admin/expression.py
new file mode 100644
index 0000000..a6a8fd2
--- /dev/null
+++ b/gstudio/admin/expression.py
@@ -0,0 +1,13 @@
+"""MetatypeAdmin for Gstudio"""
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import ExpressionAdminForm
+import reversion
+
+class ExpressionAdmin(reversion.VersionAdmin):
+ def save_model(self, request, expression, form, change):
+ expression.title = expression.composed_sentence
+ expression.save()
+
diff --git a/gstudio/admin/forms.py b/gstudio/admin/forms.py
new file mode 100644
index 0000000..37b578c
--- /dev/null
+++ b/gstudio/admin/forms.py
@@ -0,0 +1,505 @@
+"""Forms for Gstudio admin"""
+from django import forms
+from django.db.models import ManyToOneRel
+from django.db.models import ManyToManyRel
+from django.contrib.sites.models import Site
+from django.utils.translation import ugettext_lazy as _
+from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
+
+from gstudio.models import NID
+from gstudio.models import Nodetype
+from gstudio.models import Objecttype
+from gstudio.models import Metatype
+from gstudio.models import Relationtype
+from gstudio.models import Relation
+from gstudio.models import Attributetype
+from gstudio.models import Attribute
+from gstudio.models import AttributeSpecification
+from gstudio.models import RelationSpecification
+from gstudio.models import NodeSpecification
+from gstudio.models import Union
+from gstudio.models import Complement
+from gstudio.models import Intersection
+from gstudio.models import Expression
+
+from gstudio.models import AttributeCharField
+from gstudio.models import AttributeTextField
+from gstudio.models import AttributeIntegerField
+from gstudio.models import AttributeCommaSeparatedIntegerField
+from gstudio.models import AttributeBigIntegerField
+from gstudio.models import AttributePositiveIntegerField
+from gstudio.models import AttributeDecimalField
+from gstudio.models import AttributeFloatField
+from gstudio.models import AttributeBooleanField
+from gstudio.models import AttributeNullBooleanField
+from gstudio.models import AttributeDateField
+from gstudio.models import AttributeDateTimeField
+from gstudio.models import AttributeTimeField
+from gstudio.models import AttributeEmailField
+from gstudio.models import AttributeFileField
+from gstudio.models import AttributeFilePathField
+from gstudio.models import AttributeImageField
+from gstudio.models import AttributeURLField
+from gstudio.models import AttributeIPAddressField
+
+
+
+
+from gstudio.models import Systemtype
+from gstudio.models import Processtype
+
+
+from gstudio.admin.widgets import TreeNodeChoiceField
+from gstudio.admin.widgets import MPTTFilteredSelectMultiple
+from gstudio.admin.widgets import MPTTModelMultipleChoiceField
+from reversion.models import Version
+
+class MetatypeAdminForm(forms.ModelForm):
+ """Form for Metatype's Admin"""
+ parent = TreeNodeChoiceField(
+ label=_('parent metatype').capitalize(),
+ required=False, empty_label=_('No parent metatype'),
+ queryset=Metatype.tree.all())
+
+ def __init__(self, *args, **kwargs):
+ super(MetatypeAdminForm, self).__init__(*args, **kwargs)
+ rel = ManyToOneRel(Metatype, 'id')
+ self.fields['parent'].widget = RelatedFieldWidgetWrapper(
+ self.fields['parent'].widget, rel, self.admin_site)
+
+ def clean_parent(self):
+ """Check if metatype parent is not selfish"""
+ data = self.cleaned_data['parent']
+ if data == self.instance:
+ raise forms.ValidationError(
+ _('A metatype cannot be a parent of itself.'))
+ return data
+
+ class Meta:
+ """MetatypeAdminForm's Meta"""
+ model = Metatype
+
+
+class ObjecttypeAdminForm(forms.ModelForm):
+ """Form for Objecttype's Admin"""
+
+ parent = TreeNodeChoiceField(
+ label=_('parent nodetype').capitalize(),
+ required=False, empty_label=_('No parent nodetype'),
+ queryset=Nodetype.tree.all())
+
+ metatypes = MPTTModelMultipleChoiceField(
+ label=_('Metatypes'), required=False,
+ queryset=Metatype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('metatypes'), False,
+ attrs={'rows': '10'}))
+ priornodes = MPTTModelMultipleChoiceField(
+ label=_('priornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('nodetypes'), False,
+ attrs={'rows': '10'}))
+
+ posteriornodes = MPTTModelMultipleChoiceField(
+ label=_('posteriornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('nodetypes'), False,
+ attrs={'rows': '10'}))
+
+
+
+
+ def __init__(self, *args, **kwargs):
+ super(ObjecttypeAdminForm, self).__init__(*args, **kwargs)
+ meta = ManyToManyRel(Metatype, 'id')
+ prior = ManyToManyRel(Nodetype,'id')
+ post = ManyToManyRel(Nodetype,'id')
+ self.fields['metatypes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['metatypes'].widget, meta, self.admin_site)
+ self.fields['priornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['priornodes'].widget, prior, self.admin_site)
+ self.fields['posteriornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['posteriornodes'].widget, post, self.admin_site)
+
+
+
+ self.fields['sites'].initial = [Site.objects.get_current()]
+
+ def clean_parent(self):
+ """Check if an object does not become a parent of itself"""
+ data = self.cleaned_data['parent']
+ if data == self.instance:
+ raise forms.ValidationError(
+ _('An objectype cannot be parent of itself.'))
+ return data
+
+ class Meta:
+ """NodetypeAdminForm's Meta"""
+ model = Objecttype
+
+
+class RelationtypeAdminForm(forms.ModelForm):
+
+ priornodes = MPTTModelMultipleChoiceField(
+ label=_('Priornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('priornodes'), False,
+ attrs={'rows': '10'}))
+ posteriornodes = MPTTModelMultipleChoiceField(
+ label=_('Prosterior Nodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('prosteriornode'), False,
+ attrs={'rows': '10'}))
+
+ def __init__(self, *args, **kwargs):
+ super(RelationtypeAdminForm, self).__init__(*args, **kwargs)
+ prior = ManyToManyRel(Nodetype, 'id')
+ post = ManyToManyRel(Nodetype, 'id')
+
+
+
+ self.fields['priornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['priornodes'].widget, prior, self.admin_site)
+ self.fields['posteriornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['posteriornodes'].widget, post, self.admin_site)
+
+
+
+
+ class Meta:
+ """MetatypeAdminForm's Meta"""
+ model = Relationtype
+
+
+class RelationAdminForm(forms.ModelForm):
+
+
+ def ApplicableNodeTypes_filter(self):
+ choice = 'NT'
+ if choice == 'ED':
+ nid = 'Edge'
+ if choice == 'ND':
+ nid = 'Node'
+ if choice == 'NT':
+ nid = 'Nodetype'
+ if choice == 'ET':
+ nid = 'Edgetype'
+ if choice == 'OT':
+ nid = 'Objecttype'
+ if choice == 'RT':
+ nid = 'Relationtype'
+ if choice == 'MT':
+ nid = 'Metatype'
+ if choice == 'AT':
+ nid = 'Attributetype'
+ if choice == 'RN':
+ nid = 'Relation'
+ if choice == 'AS':
+ nid = 'Attributes'
+ if choice == 'ST':
+ nid = 'Systemtype'
+ if choice == 'SY':
+ nid = 'System'
+
+ node = NID.objects.get(Objecttype)
+ vrs = Version.objects.filter(type=0 , object_id=node.id)
+ vrs = vrs[0]
+ AppNode = vrs.object._meta.module_name
+ AppNodeList = AppNode.objects.all()
+ return AppNodeList
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ class Meta:
+ """MetatypeAdminForm's Meta"""
+ model = Relation
+
+
+class ProcesstypeAdminForm(forms.ModelForm):
+
+ priornodes = MPTTModelMultipleChoiceField(
+ label=_('Priornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('priornodes'), False,
+ attrs={'rows': '10'}))
+ posteriornodes = MPTTModelMultipleChoiceField(
+ label=_('Prosterior Nodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('prosteriornode'), False,
+ attrs={'rows': '10'}))
+ attributetype_set = MPTTModelMultipleChoiceField(
+ label=_('Attributetype Sets'), required=False,
+ queryset=Attributetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('Attributetype Set'), False,
+ attrs={'rows': '10'}))
+ relationtype_set = MPTTModelMultipleChoiceField(
+ label=_('Relationtype Set'), required=False,
+ queryset=Relationtype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('Relationtype Set'), False,
+ attrs={'rows': '10'}))
+
+
+ def __init__(self, *args, **kwargs):
+ super(ProcesstypeAdminForm, self).__init__(*args, **kwargs)
+ prior = ManyToManyRel(Nodetype, 'id')
+ post = ManyToManyRel(Nodetype, 'id')
+ atype = ManyToManyRel(Attributetype, 'id')
+ rtype = ManyToManyRel(Relationtype, 'id')
+
+
+ self.fields['priornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['priornodes'].widget, prior, self.admin_site)
+ self.fields['posteriornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['posteriornodes'].widget, post, self.admin_site)
+ self.fields['attributetype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['attributetype_set'].widget, atype, self.admin_site)
+ self.fields['relationtype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['relationtype_set'].widget, rtype, self.admin_site)
+
+
+
+
+ class Meta:
+ """SystemAdminForm's Meta"""
+ model = Processtype
+
+class AttributetypeAdminForm(forms.ModelForm):
+ priornodes = MPTTModelMultipleChoiceField(
+ label=_('Priornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('priornodes'), False,
+ attrs={'rows': '10'}))
+ posteriornodes = MPTTModelMultipleChoiceField(
+ label=_('Posterior Nodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('posteriornodes'), False,
+ attrs={'rows': '10'}))
+ def __init__(self, *args, **kwargs):
+ super(AttributetypeAdminForm, self).__init__(*args, **kwargs)
+ prior = ManyToManyRel(Nodetype, 'id')
+ post = ManyToManyRel(Nodetype, 'id')
+
+
+ self.fields['priornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['priornodes'].widget, prior, self.admin_site)
+ self.fields['posteriornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['posteriornodes'].widget, post, self.admin_site)
+
+
+
+ class Meta:
+ """MetatypeAdminForm's Meta"""
+ model = Attributetype
+
+
+class AttributeAdminForm(forms.ModelForm):
+
+ def subject_filter(attr):
+ """
+ returns applicable selection of nodes for selecting objects
+ """
+ for each in Objecttype.objects.all():
+ if attr.subjecttype.id == each.id:
+ return each.get_members
+
+ def __init__(self, *args, **kwargs):
+ super(AttributeAdminForm, self).__init__(*args, **kwargs)
+ self.fields["subject"].queryset = subject_filter(attr)
+
+
+ class Meta:
+ """MetatypeAdminForm's Meta"""
+ model = Attribute
+
+
+
+class SystemtypeAdminForm(forms.ModelForm):
+ nodetype_set = MPTTModelMultipleChoiceField(
+ label=_('Nodetypeset'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('Nodetypesets'), False,
+ attrs={'rows': '10'}))
+ relationtype_set = MPTTModelMultipleChoiceField(
+ label=_('Relationtypeset'), required=False,
+ queryset=Relationtype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('Relationtypesets'), False,
+ attrs={'rows': '10'}))
+ attributetype_set = MPTTModelMultipleChoiceField(
+ label=_('Attributetypeset'), required=False,
+ queryset=Attributetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('Attributetypesets'), False,
+ attrs={'rows': '10'}))
+ metatype_set = MPTTModelMultipleChoiceField(
+ label=_('Metatypeset'), required=False,
+ queryset=Metatype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('metatypesets'), False,
+ attrs={'rows': '10'}))
+ processtype_set = MPTTModelMultipleChoiceField(
+ label=_('Processtypeset'), required=False,
+ queryset=Processtype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('Processtypesets'), False,
+ attrs={'rows': '10'}))
+
+ priornodes = MPTTModelMultipleChoiceField(
+ label=_('priornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('nodetypes'), False,
+ attrs={'rows': '10'}))
+
+ posteriornodes = MPTTModelMultipleChoiceField(
+ label=_('posteriornodes'), required=False,
+ queryset=Nodetype.objects.all(),
+ widget=MPTTFilteredSelectMultiple(_('nodetypes'), False,
+ attrs={'rows': '10'}))
+ def __init__(self, *args, **kwargs):
+ super(SystemtypeAdminForm, self).__init__(*args, **kwargs)
+ ot = ManyToManyRel(Nodetype,'id')
+ rt = ManyToManyRel(Relationtype,'id')
+ at = ManyToManyRel(Attributetype,'id')
+ mt = ManyToManyRel(Metatype,'id')
+ pt = ManyToManyRel(Processtype,'id')
+ prior = ManyToManyRel(Nodetype,'id')
+ post = ManyToManyRel(Nodetype,'id')
+
+ self.fields['nodetype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['nodetype_set'].widget, ot, self.admin_site)
+ self.fields['relationtype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['relationtype_set'].widget, rt, self.admin_site)
+ self.fields['attributetype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['attributetype_set'].widget, at, self.admin_site)
+ self.fields['metatype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['metatype_set'].widget, mt, self.admin_site)
+ self.fields['processtype_set'].widget = RelatedFieldWidgetWrapper(
+ self.fields['processtype_set'].widget, pt, self.admin_site)
+ self.fields['priornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['priornodes'].widget, prior, self.admin_site)
+ self.fields['posteriornodes'].widget = RelatedFieldWidgetWrapper(
+ self.fields['posteriornodes'].widget, post, self.admin_site)
+
+
+
+
+ class Meta:
+ """SystemAdminForm's Meta"""
+ model = Systemtype
+
+
+class AttributeSpecificationAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeSpecification
+
+class RelationSpecificationAdminForm(forms.ModelForm):
+ class Meta:
+ model = RelationSpecification
+
+class NodeSpecificationAdminForm(forms.ModelForm):
+ class Meta:
+ model = NodeSpecification
+
+class UnionAdminForm(forms.ModelForm):
+ class Meta:
+ model = Union
+
+class ComplementAdminForm(forms.ModelForm):
+ class Meta:
+ model = Complement
+
+
+
+class IntersectionAdminForm(forms.ModelForm):
+ class Meta:
+ model = Intersection
+
+
+class ExpressionAdminForm(forms.ModelForm):
+ class Meta:
+ model = Expression
+
+### Datatypes here ###
+
+class AttributeCharFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeCharField
+
+class AttributeTextFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeTextField
+
+class AttributeIntegerFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeIntegerField
+
+class AttributeCommaSeparatedIntegerFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeCommaSeparatedIntegerField
+class AttributeBigIntegerFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeBigIntegerField
+class AttributePositiveIntegerFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributePositiveIntegerField
+
+class AttributeDecimalFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeDecimalField
+class AttributeFloatFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeFloatField
+class AttributeBooleanFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeBooleanField
+
+class AttributeNullBooleanFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeNullBooleanField
+class AttributeDateFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeDateField
+class AttributeDateTimeFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeDateField
+
+class AttributeTimeFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeTimeField
+
+class AttributeEmailFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeEmailField
+class AttributeFileFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeFileField
+class AttributeFilePathFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeFilePathField
+class AttributeImageFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeImageField
+
+class AttributeURLFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeURLField
+class AttributeIPAddressFieldAdminForm(forms.ModelForm):
+ class Meta:
+ model = AttributeIPAddressField
+
+
+
+
+
+
+
+
+
+
diff --git a/gstudio/admin/intersection.py b/gstudio/admin/intersection.py
new file mode 100644
index 0000000..6e9dd3e
--- /dev/null
+++ b/gstudio/admin/intersection.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import IntersectionAdminForm
+import reversion
+
+class IntersectionAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/metatype.py b/gstudio/admin/metatype.py
new file mode 100644
index 0000000..bb24fc7
--- /dev/null
+++ b/gstudio/admin/metatype.py
@@ -0,0 +1,30 @@
+"""MetatypeAdmin for Gstudio"""
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import MetatypeAdminForm
+import reversion
+
+class MetatypeAdmin(reversion.VersionAdmin):
+ """Admin for Metatype model"""
+ form = MetatypeAdminForm
+ fields = ('title','altnames', 'parent', 'description', 'slug')
+ list_display = ('title', 'slug', 'get_tree_path', 'description')
+ prepopulated_fields = {'slug': ('title', )}
+ search_fields = ('title', 'description')
+ list_filter = ('parent',)
+
+ def __init__(self, model, admin_site):
+ self.form.admin_site = admin_site
+ super(MetatypeAdmin, self).__init__(model, admin_site)
+
+ def get_tree_path(self, metatype):
+ """Return the metatype's tree path in HTML"""
+ try:
+ return '<a href="%s" target="blank">/%s/</a>' % \
+ (metatype.get_absolute_url(), metatype.tree_path)
+ except NoReverseMatch:
+ return '/%s/' % metatype.tree_path
+ get_tree_path.allow_tags = True
+ get_tree_path.short_description = _('tree path')
diff --git a/gstudio/admin/nodespecification.py b/gstudio/admin/nodespecification.py
new file mode 100644
index 0000000..aaf784e
--- /dev/null
+++ b/gstudio/admin/nodespecification.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import NodeSpecificationAdminForm
+import reversion
+
+class NodeSpecificationAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/objecttype.py b/gstudio/admin/objecttype.py
new file mode 100644
index 0000000..22ef205
--- /dev/null
+++ b/gstudio/admin/objecttype.py
@@ -0,0 +1,345 @@
+"""ObjecttypeAdmin for Gstudio"""
+from datetime import datetime
+from django.forms import Media
+from django.contrib import admin
+from django.contrib.auth.models import User
+from django.utils.html import strip_tags
+from django.utils.text import truncate_words
+from django.conf.urls.defaults import url
+from django.conf.urls.defaults import patterns
+from django.conf import settings as project_settings
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse, NoReverseMatch
+
+from tagging.models import Tag
+
+import reversion
+from gstudio import settings
+from gstudio.managers import HIDDEN
+from gstudio.managers import PUBLISHED
+from gstudio.ping import DirectoryPinger
+from gstudio.admin.forms import ObjecttypeAdminForm
+
+
+
+
+class ObjecttypeAdmin(reversion.VersionAdmin):
+ """Admin for Objecttype model"""
+ form = ObjecttypeAdminForm
+ date_hierarchy = 'creation_date'
+ fieldsets = ((_('Neighbourhood'), {'fields': ('title','altnames','plural','parent','slug',
+ 'metatypes','tags','image', 'status','content')}),
+ (_('Dependency'), {'fields': ('prior_nodes', 'posterior_nodes',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Options'), {'fields': ('featured', 'excerpt', 'template',
+ 'authors',
+ 'creation_date',
+ 'start_publication',
+ 'end_publication'),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Privacy'), {'fields': ('password', 'login_required',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Discussion'), {'fields': ('comment_enabled',
+ 'pingback_enabled','sites'),'classes': ('collapse', 'collapse-closed')}),
+
+ )
+ list_filter = ('parent','metatypes', 'authors', 'status', 'featured',
+ 'login_required', 'comment_enabled', 'pingback_enabled',
+ 'creation_date', 'start_publication',
+ 'end_publication', 'sites')
+ list_display = ('get_title', 'get_authors', 'get_metatypes',
+ 'get_tags', 'get_sites',
+ 'get_comments_are_open', 'pingback_enabled',
+ 'get_is_actual', 'get_is_visible', 'get_link',
+ 'get_short_url', 'creation_date')
+ radio_fields = {'template': admin.VERTICAL}
+ filter_horizontal = ('metatypes', 'authors' )
+ prepopulated_fields = {'slug': ('title', )}
+ search_fields = ('title', 'excerpt', 'content', 'tags')
+ actions = ['make_mine', 'make_published', 'make_hidden',
+ 'close_comments', 'close_pingbacks',
+ 'ping_directories', 'make_tweet', 'put_on_top']
+ actions_on_top = True
+ actions_on_bottom = True
+
+ def __init__(self, model, admin_site):
+ self.form.admin_site = admin_site
+ super(ObjecttypeAdmin, self).__init__(model, admin_site)
+
+ # Custom Display
+ def get_title(self, nodetype):
+ """Return the title with word count and number of comments"""
+ title = _('%(title)s (%(word_count)i words)') % \
+ {'title': nodetype.title, 'word_count': nodetype.word_count}
+ comments = nodetype.comments.count()
+ if comments:
+ return _('%(title)s (%(comments)i comments)') % \
+ {'title': title, 'comments': comments}
+ return title
+ get_title.short_description = _('title')
+
+ def get_authors(self, nodetype):
+ """Return the authors in HTML"""
+ try:
+ authors = ['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_author_detail',
+ args=[author.username]),
+ author.username) for author in nodetype.authors.all()]
+ except NoReverseMatch:
+ authors = [author.username for author in nodetype.authors.all()]
+ return ', '.join(authors)
+ get_authors.allow_tags = True
+ get_authors.short_description = _('author(s)')
+
+ def get_metatypes(self, nodetype):
+ """Return the metatypes linked in HTML"""
+ try:
+ metatypes = ['<a href="%s" target="blank">%s</a>' %
+ (metatype.get_absolute_url(), metatype.title)
+ for metatype in nodetype.metatypes.all()]
+ except NoReverseMatch:
+ metatypes = [metatype.title for metatype in
+ nodetype.metatypes.all()]
+ return ', '.join(metatypes)
+ get_metatypes.allow_tags = True
+ get_metatypes.short_description = _('metatype(s)')
+
+ def get_tags(self, nodetype):
+ """Return the tags linked in HTML"""
+ try:
+ return ', '.join(['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_tag_detail',
+ args=[tag.name]), tag.name)
+ for tag in Tag.objects.get_for_object(nodetype)])
+ except NoReverseMatch:
+ return nodetype.tags
+ get_tags.allow_tags = True
+ get_tags.short_description = _('tag(s)')
+
+ def get_sites(self, nodetype):
+ """Return the sites linked in HTML"""
+ return ', '.join(
+ ['<a href="http://%(domain)s" target="blank">%(name)s</a>' %
+ site.__dict__ for site in nodetype.sites.all()])
+ get_sites.allow_tags = True
+ get_sites.short_description = _('site(s)')
+
+ def get_comments_are_open(self, nodetype):
+ """Admin wrapper for nodetype.comments_are_open"""
+ return nodetype.comments_are_open
+ get_comments_are_open.boolean = True
+ get_comments_are_open.short_description = _('comment enabled')
+
+ def get_is_actual(self, nodetype):
+ """Admin wrapper for nodetype.is_actual"""
+ return nodetype.is_actual
+ get_is_actual.boolean = True
+ get_is_actual.short_description = _('is actual')
+
+ def get_is_visible(self, nodetype):
+ """Admin wrapper for nodetype.is_visible"""
+ return nodetype.is_visible
+ get_is_visible.boolean = True
+ get_is_visible.short_description = _('is visible')
+
+ def get_link(self, nodetype):
+ """Return a formated link to the nodetype"""
+ return u'<a href="%s" target="blank">%s</a>' % (
+ nodetype.get_absolute_url(), _('View'))
+ get_link.allow_tags = True
+ get_link.short_description = _('View on site')
+
+ def get_short_url(self, nodetype):
+ """Return the short url in HTML"""
+ short_url = nodetype.short_url
+ if not short_url:
+ return _('Unavailable')
+ return '<a href="%(url)s" target="blank">%(url)s</a>' % \
+ {'url': short_url}
+ get_short_url.allow_tags = True
+ get_short_url.short_description = _('short url')
+
+ # Custom Methods
+ def save_model(self, request, nodetype, form, change):
+ """Save the authors, update time, make an excerpt"""
+ if not form.cleaned_data.get('excerpt') and nodetype.status == PUBLISHED:
+ nodetype.excerpt = truncate_words(strip_tags(nodetype.content), 50)
+
+ if nodetype.pk and not request.user.has_perm('gstudio.can_change_author'):
+ form.cleaned_data['authors'] = nodetype.authors.all()
+
+ if not form.cleaned_data.get('authors'):
+ form.cleaned_data['authors'].append(request.user)
+
+ nodetype.last_update = datetime.now()
+ nodetype.save()
+
+ def queryset(self, request):
+ """Make special filtering by user permissions"""
+ queryset = super(ObjecttypeAdmin, self).queryset(request)
+ if request.user.has_perm('gstudio.can_view_all'):
+ return queryset
+ return request.user.nodetypes.all()
+
+ def formfield_for_manytomany(self, db_field, request, **kwargs):
+ """Filters the disposable authors"""
+ if db_field.name == 'authors':
+ if request.user.has_perm('gstudio.can_change_author'):
+ kwargs['queryset'] = User.objects.filter(is_staff=True)
+ else:
+ kwargs['queryset'] = User.objects.filter(pk=request.user.pk)
+
+ return super(ObjecttypeAdmin, self).formfield_for_manytomany(
+ db_field, request, **kwargs)
+
+ def get_actions(self, request):
+ """Define user actions by permissions"""
+ actions = super(ObjecttypeAdmin, self).get_actions(request)
+ if not request.user.has_perm('gstudio.can_change_author') \
+ or not request.user.has_perm('gstudio.can_view_all'):
+ del actions['make_mine']
+ if not settings.PING_DIRECTORIES:
+ del actions['ping_directories']
+ if not settings.USE_TWITTER:
+ del actions['make_tweet']
+
+ return actions
+
+ # Custom Actions
+ def make_mine(self, request, queryset):
+ """Set the nodetypes to the user"""
+ for nodetype in queryset:
+ if request.user not in nodetype.authors.all():
+ nodetype.authors.add(request.user)
+ self.message_user(
+ request, _('The selected nodetypes now belong to you.'))
+ make_mine.short_description = _('Set the nodetypes to the user')
+
+ def make_published(self, request, queryset):
+ """Set nodetypes selected as published"""
+ queryset.update(status=PUBLISHED)
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(
+ request, _('The selected nodetypes are now marked as published.'))
+ make_published.short_description = _('Set nodetypes selected as published')
+
+ def make_hidden(self, request, queryset):
+ """Set nodetypes selected as hidden"""
+ queryset.update(status=HIDDEN)
+ self.message_user(
+ request, _('The selected nodetypes are now marked as hidden.'))
+ make_hidden.short_description = _('Set nodetypes selected as hidden')
+
+ def make_tweet(self, request, queryset):
+ """Post an update on Twitter"""
+ import tweepy
+ auth = tweepy.OAuthHandler(settings.TWITTER_CONSUMER_KEY,
+ settings.TWITTER_CONSUMER_SECRET)
+ auth.set_access_token(settings.TWITTER_ACCESS_KEY,
+ settings.TWITTER_ACCESS_SECRET)
+ api = tweepy.API(auth)
+ for nodetype in queryset:
+ short_url = nodetype.short_url
+ message = '%s %s' % (nodetype.title[:139 - len(short_url)], short_url)
+ api.update_status(message)
+ self.message_user(
+ request, _('The selected nodetypes have been tweeted.'))
+ make_tweet.short_description = _('Tweet nodetypes selected')
+
+ def close_comments(self, request, queryset):
+ """Close the comments for selected nodetypes"""
+ queryset.update(comment_enabled=False)
+ self.message_user(
+ request, _('Comments are now closed for selected nodetypes.'))
+ close_comments.short_description = _('Close the comments for '\
+ 'selected nodetypes')
+
+ def close_pingbacks(self, request, queryset):
+ """Close the pingbacks for selected nodetypes"""
+ queryset.update(pingback_enabled=False)
+ self.message_user(
+ request, _('Linkbacks are now closed for selected nodetypes.'))
+ close_pingbacks.short_description = _(
+ 'Close the linkbacks for selected nodetypes')
+
+ def put_on_top(self, request, queryset):
+ """Put the selected nodetypes on top at the current date"""
+ queryset.update(creation_date=datetime.now())
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(request, _(
+ 'The selected nodetypes are now set at the current date.'))
+ put_on_top.short_description = _(
+ 'Put the selected nodetypes on top at the current date')
+
+ def ping_directories(self, request, queryset, messages=True):
+ """Ping Directories for selected nodetypes"""
+ for directory in settings.PING_DIRECTORIES:
+ pinger = DirectoryPinger(directory, queryset)
+ pinger.join()
+ if messages:
+ success = 0
+ for result in pinger.results:
+ if not result.get('flerror', True):
+ success += 1
+ else:
+ self.message_user(request,
+ '%s : %s' % (directory,
+ result['message']))
+ if success:
+ self.message_user(
+ request,
+ _('%(directory)s directory succesfully ' \
+ 'pinged %(success)d nodetypes.') %
+ {'directory': directory, 'success': success})
+ ping_directories.short_description = _(
+ 'Ping Directories for selected nodetypes')
+
+ def get_urls(self):
+ nodetype_admin_urls = super(ObjecttypeAdmin, self).get_urls()
+ urls = patterns(
+ 'django.views.generic.simple',
+ url(r'^autocomplete_tags/$', 'direct_to_template',
+ {'template': 'admin/gstudio/nodetype/autocomplete_tags.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_nodetype_autocomplete_tags'),
+ url(r'^wymeditor/$', 'direct_to_template',
+ {'template': 'admin/gstudio/nodetype/wymeditor.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_nodetype_wymeditor'),
+ url(r'^markitup/$', 'direct_to_template',
+ {'template': 'admin/gstudio/nodetype/markitup.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_nodetype_markitup'),)
+ return urls + nodetype_admin_urls
+
+ def _media(self):
+ STATIC_URL = '%sgstudio/' % project_settings.STATIC_URL
+ media = super(ObjecttypeAdmin, self).media + Media(
+ css={'all': ('%scss/jquery.autocomplete.css' % STATIC_URL,)},
+ js=('%sjs/jquery.js' % STATIC_URL,
+ '%sjs/jquery.bgiframe.js' % STATIC_URL,
+ '%sjs/jquery.autocomplete.js' % STATIC_URL,
+ reverse('admin:gstudio_nodetype_autocomplete_tags'),))
+
+ if settings.WYSIWYG == 'wymeditor':
+ media += Media(
+ js=('%sjs/wymeditor/jquery.wymeditor.pack.js' % STATIC_URL,
+ '%sjs/wymeditor/plugins/hovertools/'
+ 'jquery.wymeditor.hovertools.js' % STATIC_URL,
+ reverse('admin:gstudio_nodetype_wymeditor')))
+ elif settings.WYSIWYG == 'tinymce':
+ from tinymce.widgets import TinyMCE
+ media += TinyMCE().media + Media(
+ js=(reverse('tinymce-js', args=('admin/gstudio/nodetype',)),))
+ elif settings.WYSIWYG == 'markitup':
+ media += Media(
+ js=('%sjs/markitup/jquery.markitup.js' % STATIC_URL,
+ '%sjs/markitup/sets/%s/set.js' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE),
+ reverse('admin:gstudio_nodetype_markitup')),
+ css={'all': (
+ '%sjs/markitup/skins/django/style.css' % STATIC_URL,
+ '%sjs/markitup/sets/%s/style.css' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE))})
+ return media
+ media = property(_media)
diff --git a/gstudio/admin/processtype.py b/gstudio/admin/processtype.py
new file mode 100644
index 0000000..72a795b
--- /dev/null
+++ b/gstudio/admin/processtype.py
@@ -0,0 +1,349 @@
+"""AttributetypeAdmin for Gstudio"""
+from datetime import datetime
+
+from django.forms import Media
+from django.contrib import admin
+from django.contrib.auth.models import User
+from django.utils.html import strip_tags
+from django.utils.text import truncate_words
+from django.conf.urls.defaults import url
+from django.conf.urls.defaults import patterns
+from django.conf import settings as project_settings
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse, NoReverseMatch
+
+from tagging.models import Tag
+
+import reversion
+from gstudio import settings
+from gstudio.managers import HIDDEN
+from gstudio.managers import PUBLISHED
+from gstudio.ping import DirectoryPinger
+from gstudio.admin.forms import ProcesstypeAdminForm
+
+
+
+
+class ProcesstypeAdmin(reversion.VersionAdmin):
+ """Admin for Processtype model"""
+ form = ProcesstypeAdminForm
+ date_hierarchy = 'creation_date'
+ fieldsets = ((_('Neighbourhood'), {'fields': ('title','altnames' ,'content', 'parent',
+ 'image', 'slug','status')}),
+ (_('Processtype Definiton'), {'fields': ('attributetype_set','relationtype_set'),
+ 'classes': ('collapse', 'collapse-closed')}),
+
+ (_('Dependency'), {'fields': ('prior_nodes', 'posterior_nodes',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Options'), {'fields': ('featured', 'excerpt', 'template',
+ 'authors',
+ 'creation_date',
+ 'start_publication',
+ 'end_publication'),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Privacy'), {'fields': ('password', 'login_required',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Publication'), {'fields': ('tags',
+ 'sites')}))
+
+
+ list_filter = ('parent','metatypes', 'authors', 'status', 'featured',
+ 'login_required', 'comment_enabled', 'pingback_enabled',
+ 'creation_date', 'start_publication',
+ 'end_publication', 'sites')
+ list_display = ('get_title', 'get_authors', 'get_metatypes',
+ 'get_tags', 'get_sites',
+ 'get_comments_are_open', 'pingback_enabled',
+ 'get_is_actual', 'get_is_visible', 'get_link',
+ 'get_short_url', 'creation_date')
+ radio_fields = {'template': admin.VERTICAL}
+ filter_horizontal = ('metatypes', 'authors')
+ prepopulated_fields = {'slug': ('title', )}
+ search_fields = ('title', 'excerpt', 'content', 'tags')
+ actions = ['make_mine', 'make_published', 'make_hidden',
+ 'close_comments', 'close_pingbacks',
+ 'ping_directories', 'make_tweet', 'put_on_top']
+ actions_on_top = True
+ actions_on_bottom = True
+
+ def __init__(self, model, admin_site):
+ self.form.admin_site = admin_site
+ super(ProcesstypeAdmin, self).__init__(model, admin_site)
+
+ # Custom Display
+ def get_title(self, processtype):
+ """Return the title with word count and number of comments"""
+ title = _('%(title)s (%(word_count)i words)') % \
+ {'title': processtype.title, 'word_count': processtype.word_count}
+ comments = processtype.comments.count()
+ if comments:
+ return _('%(title)s (%(comments)i comments)') % \
+ {'title': title, 'comments': comments}
+ return title
+ get_title.short_description = _('title')
+
+ def get_authors(self, processtype):
+ """Return the authors in HTML"""
+ try:
+ authors = ['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_author_detail',
+ args=[author.username]),
+ author.username) for author in processtype.authors.all()]
+ except NoReverseMatch:
+ authors = [author.username for author in processtype.authors.all()]
+ return ', '.join(authors)
+ get_authors.allow_tags = True
+ get_authors.short_description = _('author(s)')
+
+ def get_metatypes(self, processtype):
+ """Return the metatypes linked in HTML"""
+ try:
+ metatypes = ['<a href="%s" target="blank">%s</a>' %
+ (metatype.get_absolute_url(), metatype.title)
+ for metatype in processtype.metatypes.all()]
+ except NoReverseMatch:
+ metatypes = [metatype.title for metatype in
+ processtype.metatypes.all()]
+ return ', '.join(metatypes)
+ get_metatypes.allow_tags = True
+ get_metatypes.short_description = _('metatype(s)')
+
+ def get_tags(self, processtype):
+ """Return the tags linked in HTML"""
+ try:
+ return ', '.join(['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_tag_detail',
+ args=[tag.name]), tag.name)
+ for tag in Tag.processs.get_for_process(processtype)])
+ except NoReverseMatch:
+ return processtype.tags
+ get_tags.allow_tags = True
+ get_tags.short_description = _('tag(s)')
+
+ def get_sites(self, processtype):
+ """Return the sites linked in HTML"""
+ return ', '.join(
+ ['<a href="http://%(domain)s" target="blank">%(name)s</a>' %
+ site.__dict__ for site in processtype.sites.all()])
+ get_sites.allow_tags = True
+ get_sites.short_description = _('site(s)')
+
+ def get_comments_are_open(self, processtype):
+ """Admin wrapper for processtype.comments_are_open"""
+ return processtype.comments_are_open
+ get_comments_are_open.boolean = True
+ get_comments_are_open.short_description = _('comment enabled')
+
+ def get_is_actual(self, processtype):
+ """Admin wrapper for processtype.is_actual"""
+ return processtype.is_actual
+ get_is_actual.boolean = True
+ get_is_actual.short_description = _('is actual')
+
+ def get_is_visible(self, processtype):
+ """Admin wrapper for processtype.is_visible"""
+ return processtype.is_visible
+ get_is_visible.boolean = True
+ get_is_visible.short_description = _('is visible')
+
+ def get_link(self, processtype):
+ """Return a formated link to the processtype"""
+ return u'<a href="%s" target="blank">%s</a>' % (
+ processtype.get_absolute_url(), _('View'))
+ get_link.allow_tags = True
+ get_link.short_description = _('View on site')
+
+ def get_short_url(self, processtype):
+ """Return the short url in HTML"""
+ short_url = processtype.short_url
+ if not short_url:
+ return _('Unavailable')
+ return '<a href="%(url)s" target="blank">%(url)s</a>' % \
+ {'url': short_url}
+ get_short_url.allow_tags = True
+ get_short_url.short_description = _('short url')
+
+ # Custom Methods
+ def save_model(self, request, processtype, form, change):
+ """Save the authors, update time, make an excerpt"""
+ if not form.cleaned_data.get('excerpt') and processtype.status == PUBLISHED:
+ processtype.excerpt = truncate_words(strip_tags(processtype.content), 50)
+
+ if processtype.pk and not request.user.has_perm('gstudio.can_change_author'):
+ form.cleaned_data['authors'] = processtype.authors.all()
+
+ if not form.cleaned_data.get('authors'):
+ form.cleaned_data['authors'].append(request.user)
+
+ processtype.last_update = datetime.now()
+ processtype.save()
+
+ def queryset(self, request):
+ """Make special filtering by user permissions"""
+ queryset = super(ProcesstypeAdmin, self).queryset(request)
+ if request.user.has_perm('gstudio.can_view_all'):
+ return queryset
+ return request.user.processtypes.all()
+
+ def formfield_for_manytomany(self, db_field, request, **kwargs):
+ """Filters the disposable authors"""
+ if db_field.name == 'authors':
+ if request.user.has_perm('gstudio.can_change_author'):
+ kwargs['queryset'] = User.objects.filter(is_staff=True)
+ else:
+ kwargs['queryset'] = User.objects.filter(pk=request.user.pk)
+
+ return super(ProcesstypeAdmin, self).formfield_for_manytomany(
+ db_field, request, **kwargs)
+
+ def get_actions(self, request):
+ """Define user actions by permissions"""
+ actions = super(ProcesstypeAdmin, self).get_actions(request)
+ if not request.user.has_perm('gstudio.can_change_author') \
+ or not request.user.has_perm('gstudio.can_view_all'):
+ del actions['make_mine']
+ if not settings.PING_DIRECTORIES:
+ del actions['ping_directories']
+ if not settings.USE_TWITTER:
+ del actions['make_tweet']
+
+ return actions
+
+ # Custom Actions
+ def make_mine(self, request, queryset):
+ """Set the processtypes to the user"""
+ for processtype in queryset:
+ if request.user not in processtype.authors.all():
+ processtype.authors.add(request.user)
+ self.message_user(
+ request, _('The selected processtypes now belong to you.'))
+ make_mine.short_description = _('Set the processtypes to the user')
+
+ def make_published(self, request, queryset):
+ """Set processtypes selected as published"""
+ queryset.update(status=PUBLISHED)
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(
+ request, _('The selected processtypes are now marked as published.'))
+ make_published.short_description = _('Set processtypes selected as published')
+
+ def make_hidden(self, request, queryset):
+ """Set processtypes selected as hidden"""
+ queryset.update(status=HIDDEN)
+ self.message_user(
+ request, _('The selected processtypes are now marked as hidden.'))
+ make_hidden.short_description = _('Set processtypes selected as hidden')
+
+ def make_tweet(self, request, queryset):
+ """Post an update on Twitter"""
+ import tweepy
+ auth = tweepy.OAuthHandler(settings.TWITTER_CONSUMER_KEY,
+ settings.TWITTER_CONSUMER_SECRET)
+ auth.set_access_token(settings.TWITTER_ACCESS_KEY,
+ settings.TWITTER_ACCESS_SECRET)
+ api = tweepy.API(auth)
+ for processtype in queryset:
+ short_url = processtype.short_url
+ message = '%s %s' % (processtype.title[:139 - len(short_url)], short_url)
+ api.update_status(message)
+ self.message_user(
+ request, _('The selected processtypes have been tweeted.'))
+ make_tweet.short_description = _('Tweet processtypes selected')
+
+ def close_comments(self, request, queryset):
+ """Close the comments for selected processtypes"""
+ queryset.update(comment_enabled=False)
+ self.message_user(
+ request, _('Comments are now closed for selected processtypes.'))
+ close_comments.short_description = _('Close the comments for '\
+ 'selected processtypes')
+
+ def close_pingbacks(self, request, queryset):
+ """Close the pingbacks for selected processtypes"""
+ queryset.update(pingback_enabled=False)
+ self.message_user(
+ request, _('Linkbacks are now closed for selected processtypes.'))
+ close_pingbacks.short_description = _(
+ 'Close the linkbacks for selected processtypes')
+
+ def put_on_top(self, request, queryset):
+ """Put the selected processtypes on top at the current date"""
+ queryset.update(creation_date=datetime.now())
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(request, _(
+ 'The selected processtypes are now set at the current date.'))
+ put_on_top.short_description = _(
+ 'Put the selected processtypes on top at the current date')
+
+ def ping_directories(self, request, queryset, messages=True):
+ """Ping Directories for selected processtypes"""
+ for directory in settings.PING_DIRECTORIES:
+ pinger = DirectoryPinger(directory, queryset)
+ pinger.join()
+ if messages:
+ success = 0
+ for result in pinger.results:
+ if not result.get('flerror', True):
+ success += 1
+ else:
+ self.message_user(request,
+ '%s : %s' % (directory,
+ result['message']))
+ if success:
+ self.message_user(
+ request,
+ _('%(directory)s directory succesfully ' \
+ 'pinged %(success)d processtypes.') %
+ {'directory': directory, 'success': success})
+ ping_directories.short_description = _(
+ 'Ping Directories for selected processtypes')
+
+ def get_urls(self):
+ processtype_admin_urls = super(ProcesstypeAdmin, self).get_urls()
+ urls = patterns(
+ 'django.views.generic.simple',
+ url(r'^autocomplete_tags/$', 'direct_to_template',
+ {'template': 'admin/gstudio/processtype/autocomplete_tags.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_processtype_autocomplete_tags'),
+ url(r'^wymeditor/$', 'direct_to_template',
+ {'template': 'admin/gstudio/processtype/wymeditor.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_processtype_wymeditor'),
+ url(r'^markitup/$', 'direct_to_template',
+ {'template': 'admin/gstudio/processtype/markitup.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_processtype_markitup'),)
+ return urls + processtype_admin_urls
+
+ def _media(self):
+ STATIC_URL = '%sgstudio/' % project_settings.STATIC_URL
+ media = super(ProcesstypeAdmin, self).media + Media(
+ css={'all': ('%scss/jquery.autocomplete.css' % STATIC_URL,)},
+ js=('%sjs/jquery.js' % STATIC_URL,
+ '%sjs/jquery.bgiframe.js' % STATIC_URL,
+ '%sjs/jquery.autocomplete.js' % STATIC_URL,
+ reverse('admin:gstudio_processtype_autocomplete_tags'),))
+
+ if settings.WYSIWYG == 'wymeditor':
+ media += Media(
+ js=('%sjs/wymeditor/jquery.wymeditor.pack.js' % STATIC_URL,
+ '%sjs/wymeditor/plugins/hovertools/'
+ 'jquery.wymeditor.hovertools.js' % STATIC_URL,
+ reverse('admin:gstudio_processtype_wymeditor')))
+ elif settings.WYSIWYG == 'tinymce':
+ from tinymce.widgets import TinyMCE
+ media += TinyMCE().media + Media(
+ js=(reverse('tinymce-js', args=('admin/gstudio/processtype',)),))
+ elif settings.WYSIWYG == 'markitup':
+ media += Media(
+ js=('%sjs/markitup/jquery.markitup.js' % STATIC_URL,
+ '%sjs/markitup/sets/%s/set.js' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE),
+ reverse('admin:gstudio_processtype_markitup')),
+ css={'all': (
+ '%sjs/markitup/skins/django/style.css' % STATIC_URL,
+ '%sjs/markitup/sets/%s/style.css' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE))})
+ return media
+ media = property(_media)
diff --git a/gstudio/admin/relation.py b/gstudio/admin/relation.py
new file mode 100644
index 0000000..04b4e8b
--- /dev/null
+++ b/gstudio/admin/relation.py
@@ -0,0 +1,13 @@
+"""MetatypeAdmin for Gstudio"""
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import RelationAdminForm
+import reversion
+
+class RelationAdmin(reversion.VersionAdmin):
+ def save_model(self, request, relation, form, change):
+ relation.title = relation.composed_sentence
+ relation.save()
+
diff --git a/gstudio/admin/relationspecification.py b/gstudio/admin/relationspecification.py
new file mode 100644
index 0000000..5da162b
--- /dev/null
+++ b/gstudio/admin/relationspecification.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import RelationSpecificationAdminForm
+import reversion
+
+class RelationSpecificationAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/relationtype.py b/gstudio/admin/relationtype.py
new file mode 100644
index 0000000..374f9a8
--- /dev/null
+++ b/gstudio/admin/relationtype.py
@@ -0,0 +1,362 @@
+"""RelationtypeAdmin for Gstudio"""
+from datetime import datetime
+from django.forms import Media
+from django.contrib import admin
+from django.contrib.auth.models import User
+from django.utils.html import strip_tags
+from django.utils.text import truncate_words
+from django.conf.urls.defaults import url
+from django.conf.urls.defaults import patterns
+from django.conf import settings as project_settings
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse, NoReverseMatch
+
+from tagging.models import Tag
+
+import reversion
+from gstudio import settings
+from gstudio.managers import HIDDEN
+from gstudio.managers import PUBLISHED
+from gstudio.ping import DirectoryPinger
+from gstudio.admin.forms import RelationtypeAdminForm
+
+
+
+
+class RelationtypeAdmin(reversion.VersionAdmin):
+ """Admin for Relationtype model"""
+ form = RelationtypeAdminForm
+ date_hierarchy = 'creation_date'
+ fieldsets = ((
+ (_('Neighbourhood Definiton'), {'fields': (
+ 'title',
+ 'inverse',
+ 'altnames',
+ 'parent',
+ 'slug',
+
+ 'left_subjecttype',
+ 'left_applicable_nodetypes',
+ 'left_cardinality',
+ 'right_subjecttype',
+ 'right_applicable_nodetypes',
+ 'right_cardinality',
+ 'is_symmetrical',
+ 'is_reflexive',
+ 'is_transitive')
+ }),
+ (_('Content'), {'fields': ('content', 'image',),
+ 'classes': ('collapse', 'collapse-closed')}),
+
+
+ (_('Dependency'), {'fields': ('prior_nodes', 'posterior_nodes',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Options'), {'fields': ('featured', 'excerpt', 'template',
+ 'authors',
+ 'creation_date',
+ 'start_publication',
+ 'end_publication'),
+ 'classes': ('collapse', 'collapse-closed')}),
+ ))
+
+
+ list_filter = ('parent','metatypes', 'authors', 'status', 'featured',
+ 'login_required', 'comment_enabled', 'pingback_enabled',
+ 'creation_date', 'start_publication',
+ 'end_publication', 'sites')
+ list_display = ('get_title', 'get_authors', 'get_metatypes',
+ 'get_tags', 'get_sites',
+ 'get_comments_are_open', 'pingback_enabled',
+ 'get_is_actual', 'get_is_visible', 'get_link',
+ 'get_short_url', 'creation_date')
+ radio_fields = {'template': admin.VERTICAL}
+ filter_horizontal = ('metatypes', 'authors')
+ prepopulated_fields = {'slug': ('title', )}
+ search_fields = ('title', 'excerpt', 'content', 'tags')
+ actions = ['make_mine', 'make_published', 'make_hidden',
+ 'close_comments', 'close_pingbacks',
+ 'ping_directories', 'make_tweet', 'put_on_top']
+ actions_on_top = True
+ actions_on_bottom = True
+
+ def __init__(self, model, admin_site):
+ self.form.admin_site = admin_site
+ super(RelationtypeAdmin, self).__init__(model, admin_site)
+
+ # Custom Display
+ def get_title(self, relationtype):
+ """Return the title with word count and number of comments"""
+ title = _('%(title)s (%(word_count)i words)') % \
+ {'title': relationtype.title, 'word_count': relationtype.word_count}
+ comments = relationtype.comments.count()
+ if comments:
+ return _('%(title)s (%(comments)i comments)') % \
+ {'title': title, 'comments': comments}
+ return title
+ get_title.short_description = _('title')
+
+ def get_authors(self, relationtype):
+ """Return the authors in HTML"""
+ try:
+ authors = ['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_author_detail',
+ args=[author.username]),
+ author.username) for author in relationtype.authors.all()]
+ except NoReverseMatch:
+ authors = [author.username for author in relationtype.authors.all()]
+ return ', '.join(authors)
+ get_authors.allow_tags = True
+ get_authors.short_description = _('author(s)')
+
+ def get_metatypes(self, relationtype):
+ """Return the metatypes linked in HTML"""
+ try:
+ metatypes = ['<a href="%s" target="blank">%s</a>' %
+ (metatype.get_absolute_url(), metatype.title)
+ for metatype in relationtype.metatypes.all()]
+ except NoReverseMatch:
+ metatypes = [metatype.title for metatype in
+ relationtype.metatypes.all()]
+ return ', '.join(metatypes)
+ get_metatypes.allow_tags = True
+ get_metatypes.short_description = _('metatype(s)')
+
+ def get_tags(self, relationtype):
+ """Return the tags linked in HTML"""
+ try:
+ return ', '.join(['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_tag_detail',
+ args=[tag.name]), tag.name)
+ for tag in Tag.relations.get_for_relation(relationtype)])
+ except NoReverseMatch:
+ return relationtype.tags
+ get_tags.allow_tags = True
+ get_tags.short_description = _('tag(s)')
+
+ def get_sites(self, relationtype):
+ """Return the sites linked in HTML"""
+ return ', '.join(
+ ['<a href="http://%(domain)s" target="blank">%(name)s</a>' %
+ site.__dict__ for site in relationtype.sites.all()])
+ get_sites.allow_tags = True
+ get_sites.short_description = _('site(s)')
+
+ def get_comments_are_open(self, relationtype):
+ """Admin wrapper for relationtype.comments_are_open"""
+ return relationtype.comments_are_open
+ get_comments_are_open.boolean = True
+ get_comments_are_open.short_description = _('comment enabled')
+
+ def get_is_actual(self, relationtype):
+ """Admin wrapper for relationtype.is_actual"""
+ return relationtype.is_actual
+ get_is_actual.boolean = True
+ get_is_actual.short_description = _('is actual')
+
+ def get_is_visible(self, relationtype):
+ """Admin wrapper for relationtype.is_visible"""
+ return relationtype.is_visible
+ get_is_visible.boolean = True
+ get_is_visible.short_description = _('is visible')
+
+ def get_link(self, relationtype):
+ """Return a formated link to the relationtype"""
+ return u'<a href="%s" target="blank">%s</a>' % (
+ relationtype.get_absolute_url(), _('View'))
+ get_link.allow_tags = True
+ get_link.short_description = _('View on site')
+
+ def get_short_url(self, relationtype):
+ """Return the short url in HTML"""
+ short_url = relationtype.short_url
+ if not short_url:
+ return _('Unavailable')
+ return '<a href="%(url)s" target="blank">%(url)s</a>' % \
+ {'url': short_url}
+ get_short_url.allow_tags = True
+ get_short_url.short_description = _('short url')
+
+ # Custom Methods
+ def save_model(self, request, relationtype, form, change):
+ """Save the authors, update time, make an excerpt"""
+ if not form.cleaned_data.get('excerpt') and relationtype.status == PUBLISHED:
+ relationtype.excerpt = truncate_words(strip_tags(relationtype.content), 50)
+
+ if relationtype.pk and not request.user.has_perm('gstudio.can_change_author'):
+ form.cleaned_data['authors'] = relationtype.authors.all()
+
+ if not form.cleaned_data.get('authors'):
+ form.cleaned_data['authors'].append(request.user)
+
+ relationtype.last_update = datetime.now()
+ relationtype.save()
+
+ def queryset(self, request):
+ """Make special filtering by user permissions"""
+ queryset = super(RelationtypeAdmin, self).queryset(request)
+ if request.user.has_perm('gstudio.can_view_all'):
+ return queryset
+ return request.user.relationtypes.all()
+
+ def formfield_for_manytomany(self, db_field, request, **kwargs):
+ """Filters the disposable authors"""
+ if db_field.name == 'authors':
+ if request.user.has_perm('gstudio.can_change_author'):
+ kwargs['queryset'] = User.objects.filter(is_staff=True)
+ else:
+ kwargs['queryset'] = User.objects.filter(pk=request.user.pk)
+
+ return super(RelationtypeAdmin, self).formfield_for_manytomany(
+ db_field, request, **kwargs)
+
+ def get_actions(self, request):
+ """Define user actions by permissions"""
+ actions = super(RelationtypeAdmin, self).get_actions(request)
+ if not request.user.has_perm('gstudio.can_change_author') \
+ or not request.user.has_perm('gstudio.can_view_all'):
+ del actions['make_mine']
+ if not settings.PING_DIRECTORIES:
+ del actions['ping_directories']
+ if not settings.USE_TWITTER:
+ del actions['make_tweet']
+
+ return actions
+
+ # Custom Actions
+ def make_mine(self, request, queryset):
+ """Set the relationtypes to the user"""
+ for relationtype in queryset:
+ if request.user not in relationtype.authors.all():
+ relationtype.authors.add(request.user)
+ self.message_user(
+ request, _('The selected relationtypes now belong to you.'))
+ make_mine.short_description = _('Set the relationtypes to the user')
+
+ def make_published(self, request, queryset):
+ """Set relationtypes selected as published"""
+ queryset.update(status=PUBLISHED)
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(
+ request, _('The selected relationtypes are now marked as published.'))
+ make_published.short_description = _('Set relationtypes selected as published')
+
+ def make_hidden(self, request, queryset):
+ """Set relationtypes selected as hidden"""
+ queryset.update(status=HIDDEN)
+ self.message_user(
+ request, _('The selected relationtypes are now marked as hidden.'))
+ make_hidden.short_description = _('Set relationtypes selected as hidden')
+
+ def make_tweet(self, request, queryset):
+ """Post an update on Twitter"""
+ import tweepy
+ auth = tweepy.OAuthHandler(settings.TWITTER_CONSUMER_KEY,
+ settings.TWITTER_CONSUMER_SECRET)
+ auth.set_access_token(settings.TWITTER_ACCESS_KEY,
+ settings.TWITTER_ACCESS_SECRET)
+ api = tweepy.API(auth)
+ for relationtype in queryset:
+ short_url = relationtype.short_url
+ message = '%s %s' % (relationtype.title[:139 - len(short_url)], short_url)
+ api.update_status(message)
+ self.message_user(
+ request, _('The selected relationtypes have been tweeted.'))
+ make_tweet.short_description = _('Tweet relationtypes selected')
+
+ def close_comments(self, request, queryset):
+ """Close the comments for selected relationtypes"""
+ queryset.update(comment_enabled=False)
+ self.message_user(
+ request, _('Comments are now closed for selected relationtypes.'))
+ close_comments.short_description = _('Close the comments for '\
+ 'selected relationtypes')
+
+ def close_pingbacks(self, request, queryset):
+ """Close the pingbacks for selected relationtypes"""
+ queryset.update(pingback_enabled=False)
+ self.message_user(
+ request, _('Linkbacks are now closed for selected relationtypes.'))
+ close_pingbacks.short_description = _(
+ 'Close the linkbacks for selected relationtypes')
+
+ def put_on_top(self, request, queryset):
+ """Put the selected relationtypes on top at the current date"""
+ queryset.update(creation_date=datetime.now())
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(request, _(
+ 'The selected relationtypes are now set at the current date.'))
+ put_on_top.short_description = _(
+ 'Put the selected relationtypes on top at the current date')
+
+ def ping_directories(self, request, queryset, messages=True):
+ """Ping Directories for selected relationtypes"""
+ for directory in settings.PING_DIRECTORIES:
+ pinger = DirectoryPinger(directory, queryset)
+ pinger.join()
+ if messages:
+ success = 0
+ for result in pinger.results:
+ if not result.get('flerror', True):
+ success += 1
+ else:
+ self.message_user(request,
+ '%s : %s' % (directory,
+ result['message']))
+ if success:
+ self.message_user(
+ request,
+ _('%(directory)s directory succesfully ' \
+ 'pinged %(success)d relationtypes.') %
+ {'directory': directory, 'success': success})
+ ping_directories.short_description = _(
+ 'Ping Directories for selected relationtypes')
+
+ def get_urls(self):
+ relationtype_admin_urls = super(RelationtypeAdmin, self).get_urls()
+ urls = patterns(
+ 'django.views.generic.simple',
+ url(r'^autocomplete_tags/$', 'direct_to_template',
+ {'template': 'admin/gstudio/relationtype/autocomplete_tags.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_relationtype_autocomplete_tags'),
+ url(r'^wymeditor/$', 'direct_to_template',
+ {'template': 'admin/gstudio/relationtype/wymeditor.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_relationtype_wymeditor'),
+ url(r'^markitup/$', 'direct_to_template',
+ {'template': 'admin/gstudio/relationtype/markitup.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_relationtype_markitup'),)
+ return urls + relationtype_admin_urls
+
+ def _media(self):
+ STATIC_URL = '%sgstudio/' % project_settings.STATIC_URL
+ media = super(RelationtypeAdmin, self).media + Media(
+ css={'all': ('%scss/jquery.autocomplete.css' % STATIC_URL,)},
+ js=('%sjs/jquery.js' % STATIC_URL,
+ '%sjs/jquery.bgiframe.js' % STATIC_URL,
+ '%sjs/jquery.autocomplete.js' % STATIC_URL,
+ reverse('admin:gstudio_relationtype_autocomplete_tags'),))
+
+ if settings.WYSIWYG == 'wymeditor':
+ media += Media(
+ js=('%sjs/wymeditor/jquery.wymeditor.pack.js' % STATIC_URL,
+ '%sjs/wymeditor/plugins/hovertools/'
+ 'jquery.wymeditor.hovertools.js' % STATIC_URL,
+ reverse('admin:gstudio_relationtype_wymeditor')))
+ elif settings.WYSIWYG == 'tinymce':
+ from tinymce.widgets import TinyMCE
+ media += TinyMCE().media + Media(
+ js=(reverse('tinymce-js', args=('admin/gstudio/relationtype',)),))
+ elif settings.WYSIWYG == 'markitup':
+ media += Media(
+ js=('%sjs/markitup/jquery.markitup.js' % STATIC_URL,
+ '%sjs/markitup/sets/%s/set.js' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE),
+ reverse('admin:gstudio_relationtype_markitup')),
+ css={'all': (
+ '%sjs/markitup/skins/django/style.css' % STATIC_URL,
+ '%sjs/markitup/sets/%s/style.css' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE))})
+ return media
+ media = property(_media)
diff --git a/gstudio/admin/systemtype.py b/gstudio/admin/systemtype.py
new file mode 100644
index 0000000..8a12856
--- /dev/null
+++ b/gstudio/admin/systemtype.py
@@ -0,0 +1,352 @@
+"""AttributetypeAdmin for Gstudio"""
+from datetime import datetime
+
+from django.forms import Media
+from django.contrib import admin
+from django.contrib.auth.models import User
+from django.utils.html import strip_tags
+from django.utils.text import truncate_words
+from django.conf.urls.defaults import url
+from django.conf.urls.defaults import patterns
+from django.conf import settings as project_settings
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse, NoReverseMatch
+
+from tagging.models import Tag
+
+import reversion
+from gstudio import settings
+from gstudio.managers import HIDDEN
+from gstudio.managers import PUBLISHED
+from gstudio.ping import DirectoryPinger
+from gstudio.admin.forms import SystemtypeAdminForm
+
+
+
+
+class SystemtypeAdmin(reversion.VersionAdmin):
+ """Admin for Systemtype model"""
+ form = SystemtypeAdminForm
+ date_hierarchy = 'creation_date'
+
+ fieldsets = ((_('Neighbourhood'), {'fields': ('title', 'altnames','content', 'parent','image', 'slug','status')}),
+ (_('Systemtype definiton'), {'fields': (
+ 'nodetype_set',
+ 'relationtype_set',
+ 'attributetype_set',
+ 'metatype_set',
+ 'processtype_set')}),
+ (_('Dependency'), {'fields': ('prior_nodes', 'posterior_nodes',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Options'), {'fields': ('featured', 'excerpt', 'template',
+ 'authors',
+ 'creation_date',
+ 'start_publication',
+ 'end_publication'),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Privacy'), {'fields': ('password', 'login_required',),
+ 'classes': ('collapse', 'collapse-closed')}),
+ (_('Publication'), {'fields': ('tags',
+ 'sites')}))
+
+
+ list_filter = ('parent','metatypes', 'authors', 'status', 'featured',
+ 'login_required', 'comment_enabled', 'pingback_enabled',
+ 'creation_date', 'start_publication',
+ 'end_publication', 'sites')
+ list_display = ('get_title', 'get_authors', 'get_metatypes',
+ 'get_tags', 'get_sites',
+ 'get_comments_are_open', 'pingback_enabled',
+ 'get_is_actual', 'get_is_visible', 'get_link',
+ 'get_short_url', 'creation_date')
+ radio_fields = {'template': admin.VERTICAL}
+ filter_horizontal = ('metatypes', 'authors')
+ prepopulated_fields = {'slug': ('title', )}
+ search_fields = ('title', 'excerpt', 'content', 'tags')
+ actions = ['make_mine', 'make_published', 'make_hidden',
+ 'close_comments', 'close_pingbacks',
+ 'ping_directories', 'make_tweet', 'put_on_top']
+ actions_on_top = True
+ actions_on_bottom = True
+
+ def __init__(self, model, admin_site):
+ self.form.admin_site = admin_site
+ super(SystemtypeAdmin, self).__init__(model, admin_site)
+
+ # Custom Display
+ def get_title(self, systemtype):
+ """Return the title with word count and number of comments"""
+ title = _('%(title)s (%(word_count)i words)') % \
+ {'title': systemtype.title, 'word_count': systemtype.word_count}
+ comments = systemtype.comments.count()
+ if comments:
+ return _('%(title)s (%(comments)i comments)') % \
+ {'title': title, 'comments': comments}
+ return title
+ get_title.short_description = _('title')
+
+ def get_authors(self, systemtype):
+ """Return the authors in HTML"""
+ try:
+ authors = ['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_author_detail',
+ args=[author.username]),
+ author.username) for author in systemtype.authors.all()]
+ except NoReverseMatch:
+ authors = [author.username for author in systemtype.authors.all()]
+ return ', '.join(authors)
+ get_authors.allow_tags = True
+ get_authors.short_description = _('author(s)')
+
+ def get_metatypes(self, systemtype):
+ """Return the metatypes linked in HTML"""
+ try:
+ metatypes = ['<a href="%s" target="blank">%s</a>' %
+ (metatype.get_absolute_url(), metatype.title)
+ for metatype in systemtype.metatypes.all()]
+ except NoReverseMatch:
+ metatypes = [metatype.title for metatype in
+ systemtype.metatypes.all()]
+ return ', '.join(metatypes)
+ get_metatypes.allow_tags = True
+ get_metatypes.short_description = _('metatype(s)')
+
+ def get_tags(self, systemtype):
+ """Return the tags linked in HTML"""
+ try:
+ return ', '.join(['<a href="%s" target="blank">%s</a>' %
+ (reverse('gstudio_tag_detail',
+ args=[tag.name]), tag.name)
+ for tag in Tag.systems.get_for_system(systemtype)])
+ except NoReverseMatch:
+ return systemtype.tags
+ get_tags.allow_tags = True
+ get_tags.short_description = _('tag(s)')
+
+ def get_sites(self, systemtype):
+ """Return the sites linked in HTML"""
+ return ', '.join(
+ ['<a href="http://%(domain)s" target="blank">%(name)s</a>' %
+ site.__dict__ for site in systemtype.sites.all()])
+ get_sites.allow_tags = True
+ get_sites.short_description = _('site(s)')
+
+ def get_comments_are_open(self, systemtype):
+ """Admin wrapper for systemtype.comments_are_open"""
+ return systemtype.comments_are_open
+ get_comments_are_open.boolean = True
+ get_comments_are_open.short_description = _('comment enabled')
+
+ def get_is_actual(self, systemtype):
+ """Admin wrapper for systemtype.is_actual"""
+ return systemtype.is_actual
+ get_is_actual.boolean = True
+ get_is_actual.short_description = _('is actual')
+
+ def get_is_visible(self, systemtype):
+ """Admin wrapper for systemtype.is_visible"""
+ return systemtype.is_visible
+ get_is_visible.boolean = True
+ get_is_visible.short_description = _('is visible')
+
+ def get_link(self, systemtype):
+ """Return a formated link to the systemtype"""
+ return u'<a href="%s" target="blank">%s</a>' % (
+ systemtype.get_absolute_url(), _('View'))
+ get_link.allow_tags = True
+ get_link.short_description = _('View on site')
+
+ def get_short_url(self, systemtype):
+ """Return the short url in HTML"""
+ short_url = systemtype.short_url
+ if not short_url:
+ return _('Unavailable')
+ return '<a href="%(url)s" target="blank">%(url)s</a>' % \
+ {'url': short_url}
+ get_short_url.allow_tags = True
+ get_short_url.short_description = _('short url')
+
+ # Custom Methods
+ def save_model(self, request, systemtype, form, change):
+ """Save the authors, update time, make an excerpt"""
+ if not form.cleaned_data.get('excerpt') and systemtype.status == PUBLISHED:
+ systemtype.excerpt = truncate_words(strip_tags(systemtype.content), 50)
+
+ if systemtype.pk and not request.user.has_perm('gstudio.can_change_author'):
+ form.cleaned_data['authors'] = systemtype.authors.all()
+
+ if not form.cleaned_data.get('authors'):
+ form.cleaned_data['authors'].append(request.user)
+
+ systemtype.last_update = datetime.now()
+ systemtype.save()
+
+ def queryset(self, request):
+ """Make special filtering by user permissions"""
+ queryset = super(SystemtypeAdmin, self).queryset(request)
+ if request.user.has_perm('gstudio.can_view_all'):
+ return queryset
+ return request.user.systemtypes.all()
+
+ def formfield_for_manytomany(self, db_field, request, **kwargs):
+ """Filters the disposable authors"""
+ if db_field.name == 'authors':
+ if request.user.has_perm('gstudio.can_change_author'):
+ kwargs['queryset'] = User.objects.filter(is_staff=True)
+ else:
+ kwargs['queryset'] = User.objects.filter(pk=request.user.pk)
+
+ return super(SystemtypeAdmin, self).formfield_for_manytomany(
+ db_field, request, **kwargs)
+
+ def get_actions(self, request):
+ """Define user actions by permissions"""
+ actions = super(SystemtypeAdmin, self).get_actions(request)
+ if not request.user.has_perm('gstudio.can_change_author') \
+ or not request.user.has_perm('gstudio.can_view_all'):
+ del actions['make_mine']
+ if not settings.PING_DIRECTORIES:
+ del actions['ping_directories']
+ if not settings.USE_TWITTER:
+ del actions['make_tweet']
+
+ return actions
+
+ # Custom Actions
+ def make_mine(self, request, queryset):
+ """Set the systemtypes to the user"""
+ for systemtype in queryset:
+ if request.user not in systemtype.authors.all():
+ systemtype.authors.add(request.user)
+ self.message_user(
+ request, _('The selected systemtypes now belong to you.'))
+ make_mine.short_description = _('Set the systemtypes to the user')
+
+ def make_published(self, request, queryset):
+ """Set systemtypes selected as published"""
+ queryset.update(status=PUBLISHED)
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(
+ request, _('The selected systemtypes are now marked as published.'))
+ make_published.short_description = _('Set systemtypes selected as published')
+
+ def make_hidden(self, request, queryset):
+ """Set systemtypes selected as hidden"""
+ queryset.update(status=HIDDEN)
+ self.message_user(
+ request, _('The selected systemtypes are now marked as hidden.'))
+ make_hidden.short_description = _('Set systemtypes selected as hidden')
+
+ def make_tweet(self, request, queryset):
+ """Post an update on Twitter"""
+ import tweepy
+ auth = tweepy.OAuthHandler(settings.TWITTER_CONSUMER_KEY,
+ settings.TWITTER_CONSUMER_SECRET)
+ auth.set_access_token(settings.TWITTER_ACCESS_KEY,
+ settings.TWITTER_ACCESS_SECRET)
+ api = tweepy.API(auth)
+ for systemtype in queryset:
+ short_url = systemtype.short_url
+ message = '%s %s' % (systemtype.title[:139 - len(short_url)], short_url)
+ api.update_status(message)
+ self.message_user(
+ request, _('The selected systemtypes have been tweeted.'))
+ make_tweet.short_description = _('Tweet systemtypes selected')
+
+ def close_comments(self, request, queryset):
+ """Close the comments for selected systemtypes"""
+ queryset.update(comment_enabled=False)
+ self.message_user(
+ request, _('Comments are now closed for selected systemtypes.'))
+ close_comments.short_description = _('Close the comments for '\
+ 'selected systemtypes')
+
+ def close_pingbacks(self, request, queryset):
+ """Close the pingbacks for selected systemtypes"""
+ queryset.update(pingback_enabled=False)
+ self.message_user(
+ request, _('Linkbacks are now closed for selected systemtypes.'))
+ close_pingbacks.short_description = _(
+ 'Close the linkbacks for selected systemtypes')
+
+ def put_on_top(self, request, queryset):
+ """Put the selected systemtypes on top at the current date"""
+ queryset.update(creation_date=datetime.now())
+ self.ping_directories(request, queryset, messages=False)
+ self.message_user(request, _(
+ 'The selected systemtypes are now set at the current date.'))
+ put_on_top.short_description = _(
+ 'Put the selected systemtypes on top at the current date')
+
+ def ping_directories(self, request, queryset, messages=True):
+ """Ping Directories for selected systemtypes"""
+ for directory in settings.PING_DIRECTORIES:
+ pinger = DirectoryPinger(directory, queryset)
+ pinger.join()
+ if messages:
+ success = 0
+ for result in pinger.results:
+ if not result.get('flerror', True):
+ success += 1
+ else:
+ self.message_user(request,
+ '%s : %s' % (directory,
+ result['message']))
+ if success:
+ self.message_user(
+ request,
+ _('%(directory)s directory succesfully ' \
+ 'pinged %(success)d systemtypes.') %
+ {'directory': directory, 'success': success})
+ ping_directories.short_description = _(
+ 'Ping Directories for selected systemtypes')
+
+ def get_urls(self):
+ systemtype_admin_urls = super(SystemtypeAdmin, self).get_urls()
+ urls = patterns(
+ 'django.views.generic.simple',
+ url(r'^autocomplete_tags/$', 'direct_to_template',
+ {'template': 'admin/gstudio/systemtype/autocomplete_tags.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_systemtype_autocomplete_tags'),
+ url(r'^wymeditor/$', 'direct_to_template',
+ {'template': 'admin/gstudio/systemtype/wymeditor.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_systemtype_wymeditor'),
+ url(r'^markitup/$', 'direct_to_template',
+ {'template': 'admin/gstudio/systemtype/markitup.js',
+ 'mimetype': 'application/javascript'},
+ name='gstudio_systemtype_markitup'),)
+ return urls + systemtype_admin_urls
+
+ def _media(self):
+ STATIC_URL = '%sgstudio/' % project_settings.STATIC_URL
+ media = super(SystemtypeAdmin, self).media + Media(
+ css={'all': ('%scss/jquery.autocomplete.css' % STATIC_URL,)},
+ js=('%sjs/jquery.js' % STATIC_URL,
+ '%sjs/jquery.bgiframe.js' % STATIC_URL,
+ '%sjs/jquery.autocomplete.js' % STATIC_URL,
+ reverse('admin:gstudio_systemtype_autocomplete_tags'),))
+
+ if settings.WYSIWYG == 'wymeditor':
+ media += Media(
+ js=('%sjs/wymeditor/jquery.wymeditor.pack.js' % STATIC_URL,
+ '%sjs/wymeditor/plugins/hovertools/'
+ 'jquery.wymeditor.hovertools.js' % STATIC_URL,
+ reverse('admin:gstudio_systemtype_wymeditor')))
+ elif settings.WYSIWYG == 'tinymce':
+ from tinymce.widgets import TinyMCE
+ media += TinyMCE().media + Media(
+ js=(reverse('tinymce-js', args=('admin/gstudio/systemtype',)),))
+ elif settings.WYSIWYG == 'markitup':
+ media += Media(
+ js=('%sjs/markitup/jquery.markitup.js' % STATIC_URL,
+ '%sjs/markitup/sets/%s/set.js' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE),
+ reverse('admin:gstudio_systemtype_markitup')),
+ css={'all': (
+ '%sjs/markitup/skins/django/style.css' % STATIC_URL,
+ '%sjs/markitup/sets/%s/style.css' % (
+ STATIC_URL, settings.MARKUP_LANGUAGE))})
+ return media
+ media = property(_media)
diff --git a/gstudio/admin/union.py b/gstudio/admin/union.py
new file mode 100644
index 0000000..0836936
--- /dev/null
+++ b/gstudio/admin/union.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+from django.core.urlresolvers import NoReverseMatch
+from django.utils.translation import ugettext_lazy as _
+
+from gstudio.admin.forms import UnionAdminForm
+import reversion
+
+class UnionAdmin(reversion.VersionAdmin):
+ pass
diff --git a/gstudio/admin/widgets.py b/gstudio/admin/widgets.py
new file mode 100644
index 0000000..bc6a962
--- /dev/null
+++ b/gstudio/admin/widgets.py
@@ -0,0 +1,107 @@
+"""Widgets for Gstudio admin"""
+from itertools import chain
+
+from django import forms
+from django.conf import settings
+from django.contrib.admin import widgets
+from django.utils.html import escape
+from django.utils.html import conditional_escape
+from django.utils.encoding import smart_unicode
+from django.utils.encoding import force_unicode
+
+
+class TreeNodeChoiceField(forms.ModelChoiceField):
+ """Duplicating the TreeNodeChoiceField bundled in django-mptt
+ to avoid conflict with the TreeNodeChoiceField bundled in django-cms..."""
+ def __init__(self, level_indicator=u'|--', *args, **kwargs):
+ self.level_indicator = level_indicator
+ if kwargs.get('required', True) and not 'empty_label' in kwargs:
+ kwargs['empty_label'] = None
+ super(TreeNodeChoiceField, self).__init__(*args, **kwargs)
+
+ def label_from_instance(self, obj):
+ """Creates labels which represent the tree level of each node
+ when generating option labels."""
+ return u'%s %s' % (self.level_indicator * getattr(
+ obj, obj._mptt_meta.level_attr), smart_unicode(obj))
+
+
+class MPTTModelChoiceIterator(forms.models.ModelChoiceIterator):
+ """MPTT version of ModelChoiceIterator"""
+ def choice(self, obj):
+ """Overriding choice method"""
+ tree_id = getattr(obj, self.queryset.model._mptt_meta.tree_id_attr, 0)
+ left = getattr(obj, self.queryset.model._mptt_meta.left_attr, 0)
+ return super(MPTTModelChoiceIterator,
+ self).choice(obj) + ((tree_id, left),)
+
+
+class MPTTModelMultipleChoiceField(forms.ModelMultipleChoiceField):
+ """MPTT version of ModelMultipleChoiceField"""
+ def __init__(self, level_indicator=u'|--', *args, **kwargs):
+ self.level_indicator = level_indicator
+ super(MPTTModelMultipleChoiceField, self).__init__(*args, **kwargs)
+
+ def label_from_instance(self, obj):
+ """Creates labels which represent the tree level of each node
+ when generating option labels."""
+ return u'%s %s' % (self.level_indicator * getattr(
+ obj, obj._mptt_meta.level_attr), smart_unicode(obj))
+
+ def _get_choices(self):
+ """Overriding _get_choices"""
+ if hasattr(self, '_choices'):
+ return self._choices
+ return MPTTModelChoiceIterator(self)
+
+ choices = property(_get_choices, forms.ChoiceField._set_choices)
+
+
+class MPTTFilteredSelectMultiple(widgets.FilteredSelectMultiple):
+ """MPTT version of FilteredSelectMultiple"""
+ def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
+ super(MPTTFilteredSelectMultiple, self).__init__(
+ verbose_name, is_stacked, attrs, choices)
+
+ def render_options(self, choices, selected_choices):
+ """
+ This is copy'n'pasted from django.forms.widgets Select(Widget)
+ change to the for loop and render_option so they will unpack
+ and use our extra tuple of mptt sort fields (if you pass in
+ some default choices for this field, make sure they have the
+ extra tuple too!)
+ """
+ def render_option(option_value, option_label, sort_fields):
+ """Inner scope render_option"""
+ option_value = force_unicode(option_value)
+ selected_html = (option_value in selected_choices) \
+ and u' selected="selected"' or ''
+ return u'<option value="%s" data-tree-id="%s" ' \
+ 'data-left-value="%s"%s>%s</option>' % (
+ escape(option_value),
+ sort_fields[0],
+ sort_fields[1],
+ selected_html,
+ conditional_escape(force_unicode(option_label)),
+ )
+ # Normalize to strings.
+ selected_choices = set([force_unicode(v) for v in selected_choices])
+ output = []
+ for option_value, option_label, sort_fields in chain(
+ self.choices, choices):
+ if isinstance(option_label, (list, tuple)):
+ output.append(u'<optgroup label="%s">' % escape(
+ force_unicode(option_value)))
+ for option in option_label:
+ output.append(render_option(*option))
+ output.append(u'</optgroup>')
+ else:
+ output.append(render_option(option_value, option_label,
+ sort_fields))
+ return u'\n'.join(output)
+
+ class Media:
+ """MPTTFilteredSelectMultiple's Media"""
+ js = (settings.ADMIN_MEDIA_PREFIX + 'js/core.js',
+ settings.STATIC_URL + 'gstudio/js/mptt_m2m_selectbox.js',
+ settings.ADMIN_MEDIA_PREFIX + 'js/SelectFilter2.js',)