diff --git a/apps/app_registry/__init__.py b/apps/app_registry/__init__.py new file mode 100644 index 0000000000..984fd6a527 --- /dev/null +++ b/apps/app_registry/__init__.py @@ -0,0 +1,16 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from icons.literals import APP +from navigation.api import bind_links +from project_tools.api import register_tool +from project_setup.api import register_setup + +from .models import App +from .links import app_registry_tool_link, app_list +from .api import register_app + +register_tool(app_registry_tool_link) +register_app('app_registry', label=_(u'App registry'), icon=APP) +bind_links(['app_list'], [app_list], menu_name='secondary_menu') diff --git a/apps/app_registry/api.py b/apps/app_registry/api.py new file mode 100644 index 0000000000..84392cea56 --- /dev/null +++ b/apps/app_registry/api.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import + +from django.db import DatabaseError, transaction + +from .models import App +from .links import app_registry_tool_link + + +@transaction.commit_on_success +def register_app(name, label, icon=None): + try: + app, created = App.objects.get_or_create(name=name) + except DatabaseError: + transaction.rollback() + return None + else: + app.label = label + if icon: + app.icon = icon + app.save() + return app diff --git a/apps/app_registry/links.py b/apps/app_registry/links.py new file mode 100644 index 0000000000..1a044ef133 --- /dev/null +++ b/apps/app_registry/links.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from navigation.api import Link +from icons.api import get_icon_name, get_sprite_name +from icons.literals import APP + +#from .permissions import PERMISSION_BACKUP_JOB_VIEW, PERMISSION_BACKUP_JOB_CREATE, PERMISSION_BACKUP_JOB_EDIT, PERMISSION_BACKUP_JOB_DELETE + +app_registry_tool_link = Link(text=_(u'Apps'), view='app_list', icon=get_icon_name(APP))#, permissions=[PERMISSION_BACKUP_JOB_VIEW]) +app_list = Link(text=_(u'app list'), view='app_list', sprite=get_sprite_name(APP))#, permissions=[PERMISSION_BACKUP_JOB_VIEW]) diff --git a/apps/app_registry/migrations/0001_initial.py b/apps/app_registry/migrations/0001_initial.py new file mode 100644 index 0000000000..38e5e9c21c --- /dev/null +++ b/apps/app_registry/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'App' + db.create_table('app_registry_app', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), + )) + db.send_create_signal('app_registry', ['App']) + + + def backwards(self, orm): + # Deleting model 'App' + db.delete_table('app_registry_app') + + + models = { + 'app_registry.app': { + 'Meta': {'ordering': "('name',)", 'object_name': 'App'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}) + } + } + + complete_apps = ['app_registry'] \ No newline at end of file diff --git a/apps/app_registry/migrations/0002_auto__add_field_app_icon__add_unique_app_name.py b/apps/app_registry/migrations/0002_auto__add_field_app_icon__add_unique_app_name.py new file mode 100644 index 0000000000..c7dced7a8d --- /dev/null +++ b/apps/app_registry/migrations/0002_auto__add_field_app_icon__add_unique_app_name.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'App.icon' + db.add_column('app_registry_app', 'icon', + self.gf('django.db.models.fields.CharField')(default='', max_length=64, blank=True), + keep_default=False) + + # Adding unique constraint on 'App', fields ['name'] + db.create_unique('app_registry_app', ['name']) + + + def backwards(self, orm): + # Removing unique constraint on 'App', fields ['name'] + db.delete_unique('app_registry_app', ['name']) + + # Deleting field 'App.icon' + db.delete_column('app_registry_app', 'icon') + + + models = { + 'app_registry.app': { + 'Meta': {'ordering': "('name',)", 'object_name': 'App'}, + 'icon': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}) + } + } + + complete_apps = ['app_registry'] \ No newline at end of file diff --git a/apps/app_registry/migrations/__init__.py b/apps/app_registry/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/app_registry/models.py b/apps/app_registry/models.py new file mode 100644 index 0000000000..d26570d6bc --- /dev/null +++ b/apps/app_registry/models.py @@ -0,0 +1,62 @@ +from __future__ import absolute_import + +import logging + +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext + +logger = logging.getLogger(__name__) + + +class TranslatableLabelMixin(models.Model): + _labels = {} + + @property + def label(self): + try: + return self.__class__._labels[self.pk] + except KeyError: + return unicode(self.__class__) + + def __setattr__(self, attr, value): + if attr == 'label': + self.__class__._labels[self.pk] = value + else: + return super(TranslatableLabelMixin, self).__setattr__(attr, value) + + def __unicode__(self): + return unicode(self.label) + + class Meta: + abstract = True + + +class LiveObjectsManager(models.Manager): + def get_query_set(self): + return super(LiveObjectsManager, self).get_query_set().filter(pk__in=(entry.pk for entry in self.model._registry)) + + +class LiveObjectMixin(models.Model): + _registry = [] + + def save(self, *args, **kwargs): + super(LiveObjectMixin, self).save(*args, **kwargs) + self.__class__._registry.append(self) + return self + + live = LiveObjectsManager() + objects = models.Manager() + + class Meta: + abstract = True + + +class App(TranslatableLabelMixin, LiveObjectMixin, models.Model): + name = models.CharField(max_length=64, verbose_name=_(u'name'), unique=True) + icon = models.CharField(max_length=64, verbose_name=_(u'icon'), blank=True) + + class Meta: + ordering = ('name', ) + verbose_name = _(u'app') + verbose_name_plural = _(u'apps') diff --git a/apps/app_registry/static/images/icons/plugin.png b/apps/app_registry/static/images/icons/plugin.png new file mode 100644 index 0000000000..c1ee68def0 Binary files /dev/null and b/apps/app_registry/static/images/icons/plugin.png differ diff --git a/apps/app_registry/urls.py b/apps/app_registry/urls.py new file mode 100644 index 0000000000..2adcf71cf8 --- /dev/null +++ b/apps/app_registry/urls.py @@ -0,0 +1,5 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('app_registry.views', + url(r'^list/$', 'app_list', (), 'app_list'), +) diff --git a/apps/app_registry/views.py b/apps/app_registry/views.py new file mode 100644 index 0000000000..ca373501ab --- /dev/null +++ b/apps/app_registry/views.py @@ -0,0 +1,22 @@ +from __future__ import absolute_import + +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import render_to_response, get_object_or_404 +from django.template import RequestContext +from django.utils.translation import ugettext as _ +from django.core.urlresolvers import reverse + +from .models import App + + +def app_list(request): + #order = [i for i,f in sorted(smart_modules.items(), key=lambda k: 'dependencies' in k[1] and k[1]['dependencies'])] + + return render_to_response('generic_list.html', { + 'object_list' : App.live.all(), + 'hide_object': True, + 'extra_columns': [ + {'name': _(u'name'), 'attribute': 'name'}, + {'name': _(u'label'), 'attribute': 'label'}, + ], + }, context_instance=RequestContext(request))