Add app_registry and bootstrap apps
This commit is contained in:
23
apps/app_registry/__init__.py
Normal file
23
apps/app_registry/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
from .models import App
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def register_apps():
|
||||||
|
for app_name in settings.INSTALLED_APPS:
|
||||||
|
logger.debug('registering: %s' % app_name)
|
||||||
|
App.register(app_name)
|
||||||
|
try:
|
||||||
|
post_init = import_module('%s.post_init' % app_name)
|
||||||
|
except ImportError:
|
||||||
|
logger.error('Unable to import post_init module from: %s' % app_name)
|
||||||
|
|
||||||
|
|
||||||
|
register_apps()
|
||||||
63
apps/app_registry/models.py
Normal file
63
apps/app_registry/models.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import imp
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
from project_setup.api import register_setup
|
||||||
|
from project_tools.api import register_tool
|
||||||
|
from navigation.api import register_top_menu
|
||||||
|
from bootstrap.classes import Cleanup, BootstrapModel
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class App(object):
|
||||||
|
@classmethod
|
||||||
|
def register(cls, app_name):
|
||||||
|
logger.debug('Trying to import: %s' % app_name)
|
||||||
|
try:
|
||||||
|
app_module = import_module(app_name)
|
||||||
|
except ImportError:
|
||||||
|
transaction.rollback
|
||||||
|
logger.error('Unable to import app: %s' % app_name)
|
||||||
|
else:
|
||||||
|
logger.debug('Trying to import registry from: %s' % app_name)
|
||||||
|
try:
|
||||||
|
registration = import_module('%s.registry' % app_name)
|
||||||
|
except ImportError:
|
||||||
|
logger.error('Unable to import registry for app: %s' % app_name)
|
||||||
|
else:
|
||||||
|
if not getattr(registration, 'disabled', False):
|
||||||
|
app = App()
|
||||||
|
app.name=app_name
|
||||||
|
# If there are not error go ahead with the stored app instance
|
||||||
|
app.label = getattr(registration, 'label', app_name)
|
||||||
|
app.description = getattr(registration, 'description', u'')
|
||||||
|
|
||||||
|
for link in getattr(registration, 'setup_links', []):
|
||||||
|
logger.debug('setup link: %s' % link)
|
||||||
|
register_setup(link)
|
||||||
|
|
||||||
|
for link in getattr(registration, 'tool_links', []):
|
||||||
|
logger.debug('tool link: %s' % link)
|
||||||
|
register_tool(link)
|
||||||
|
|
||||||
|
for index, link in enumerate(getattr(registration, 'menu_links', [])):
|
||||||
|
logger.debug('menu_link: %s' % link)
|
||||||
|
register_top_menu(name='%s.%s' % (app_name, index), link=link)
|
||||||
|
|
||||||
|
for cleanup_function in getattr(registration, 'cleanup_functions', []):
|
||||||
|
logger.debug('cleanup_function: %s' % cleanup_function)
|
||||||
|
Cleanup(cleanup_function)
|
||||||
|
|
||||||
|
for bootstrap_model in getattr(registration, 'bootstrap_models', []):
|
||||||
|
logger.debug('bootstrap_model: %s' % bootstrap_model)
|
||||||
|
BootstrapModel(model_name=bootstrap_model.get('name'), app_name=app_name, sanitize=bootstrap_model.get('sanitize', True))
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode(self.label)
|
||||||
0
apps/bootstrap/__init__.py
Normal file
0
apps/bootstrap/__init__.py
Normal file
7
apps/bootstrap/admin.py
Normal file
7
apps/bootstrap/admin.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import BootstrapSetup
|
||||||
|
|
||||||
|
admin.site.register(BootstrapSetup)
|
||||||
73
apps/bootstrap/classes.py
Normal file
73
apps/bootstrap/classes.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.core import serializers
|
||||||
|
from django.utils.datastructures import SortedDict
|
||||||
|
|
||||||
|
from .exceptions import ExistingData
|
||||||
|
from .literals import FIXTURE_TYPE_PK_NULLIFIER
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Cleanup(object):
|
||||||
|
"""
|
||||||
|
Class to store all the registered cleanup functions in one place
|
||||||
|
"""
|
||||||
|
_registry = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def execute_all(cls):
|
||||||
|
for cleanup in cls._registry.values():
|
||||||
|
cleanup.function()
|
||||||
|
|
||||||
|
def __init__(self, function):
|
||||||
|
self.function = function
|
||||||
|
self.__class__._registry[id(self)] = self
|
||||||
|
|
||||||
|
|
||||||
|
class BootstrapModel(object):
|
||||||
|
"""
|
||||||
|
Class used to keep track of all the models to be dumped to create a
|
||||||
|
bootstrap setup from the current setup in use
|
||||||
|
"""
|
||||||
|
_registry = SortedDict()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_for_data(cls):
|
||||||
|
for model in cls.get_all():
|
||||||
|
model_instance = models.get_model(model.app_name, model.model_name)
|
||||||
|
if model_instance.objects.all().count():
|
||||||
|
raise ExistingData
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all(cls):
|
||||||
|
return cls._registry.values()
|
||||||
|
|
||||||
|
def get_fullname(self):
|
||||||
|
return '.'.join([self.app_name, self.model_name])
|
||||||
|
|
||||||
|
def get_model_instance(self):
|
||||||
|
return models.get_model(self.app_name, self.model_name)
|
||||||
|
|
||||||
|
def __init__(self, model_name, app_name=None, sanitize=True):
|
||||||
|
app_name_splitted = None
|
||||||
|
if '.' in model_name:
|
||||||
|
app_name_splitted, model_name = model_name.split('.')
|
||||||
|
|
||||||
|
self.app_name = app_name_splitted or app_name
|
||||||
|
if not self.app_name:
|
||||||
|
raise Exception('Pass either a dotted app plus model name or a model name and a separate app name')
|
||||||
|
self.model_name = model_name
|
||||||
|
self.__class__._registry[self.get_fullname()] = self
|
||||||
|
self.sanitize = sanitize
|
||||||
|
|
||||||
|
def dump(self, serialization_format):
|
||||||
|
result = serializers.serialize(serialization_format, self.get_model_instance().objects.all(), indent=4, use_natural_keys=True)
|
||||||
|
logger.debug('result: %s' % result)
|
||||||
|
if self.sanitize:
|
||||||
|
# Remove primary key values
|
||||||
|
result = FIXTURE_TYPE_PK_NULLIFIER[serialization_format](result)
|
||||||
|
return result
|
||||||
10
apps/bootstrap/exceptions.py
Normal file
10
apps/bootstrap/exceptions.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
|
||||||
|
class ExistingData(Exception):
|
||||||
|
"""
|
||||||
|
Raised when an attempt to execute a bootstrap setup is made and there is
|
||||||
|
existing data that would be corrupted or damaged by the loading the
|
||||||
|
bootstrap's fixture
|
||||||
|
"""
|
||||||
|
pass
|
||||||
28
apps/bootstrap/forms.py
Normal file
28
apps/bootstrap/forms.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from common.forms import DetailForm
|
||||||
|
|
||||||
|
from .models import BootstrapSetup
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BootstrapSetupForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = BootstrapSetup
|
||||||
|
|
||||||
|
|
||||||
|
class BootstrapSetupForm_view(DetailForm):
|
||||||
|
class Meta:
|
||||||
|
model = BootstrapSetup
|
||||||
|
|
||||||
|
|
||||||
|
class BootstrapSetupForm_dump(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = BootstrapSetup
|
||||||
|
exclude = ['fixture']
|
||||||
18
apps/bootstrap/links.py
Normal file
18
apps/bootstrap/links.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE,
|
||||||
|
PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE,
|
||||||
|
PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_BOOTSTRAP_DUMP,
|
||||||
|
PERMISSION_NUKE_DATABASE)
|
||||||
|
|
||||||
|
link_bootstrap_setup_tool = {'text': _(u'bootstrap'), 'view': 'bootstrap_setup_list', 'icon': 'lightning.png', 'permissions': [PERMISSION_BOOTSTRAP_VIEW]}
|
||||||
|
link_bootstrap_setup_list = {'text': _(u'bootstrap setup list'), 'view': 'bootstrap_setup_list', 'famfam': 'lightning', 'permissions': [PERMISSION_BOOTSTRAP_VIEW]}
|
||||||
|
link_bootstrap_setup_create = {'text': _(u'create new bootstrap setup'), 'view': 'bootstrap_setup_create', 'famfam': 'lightning_add', 'permissions': [PERMISSION_BOOTSTRAP_CREATE]}
|
||||||
|
link_bootstrap_setup_edit = {'text': _(u'edit'), 'view': 'bootstrap_setup_edit', 'args': 'object.pk', 'famfam': 'edit', 'permissions': [PERMISSION_BOOTSTRAP_EDIT]}
|
||||||
|
link_bootstrap_setup_delete = {'text': _(u'delete'), 'view': 'bootstrap_setup_delete', 'args': 'object.pk', 'famfam': 'lightning_delete', 'permissions': [PERMISSION_BOOTSTRAP_DELETE]}
|
||||||
|
link_bootstrap_setup_view = {'text': _(u'details'), 'view': 'bootstrap_setup_view', 'args': 'object.pk', 'famfam': 'lightning', 'permissions': [PERMISSION_BOOTSTRAP_VIEW]}
|
||||||
|
link_bootstrap_setup_execute = {'text': _(u'execute'), 'view': 'bootstrap_setup_execute', 'args': 'object.pk', 'famfam': 'lightning_go', 'permissions': [PERMISSION_BOOTSTRAP_EXECUTE]}
|
||||||
|
link_bootstrap_setup_dump = {'text': _(u'dump current setup'), 'view': 'bootstrap_setup_dump', 'famfam': 'arrow_down', 'permissions': [PERMISSION_BOOTSTRAP_DUMP]}
|
||||||
|
link_erase_database = {'text': _(u'erase database'), 'view': 'erase_database_view', 'icon': 'radioactivity.png', 'permissions': [PERMISSION_NUKE_DATABASE]}
|
||||||
30
apps/bootstrap/literals.py
Normal file
30
apps/bootstrap/literals.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
FIXTURE_TYPE_JSON = 'json'
|
||||||
|
FIXTURE_TYPE_YAML = 'yaml'
|
||||||
|
FIXTURE_TYPE_XML = 'xml'
|
||||||
|
|
||||||
|
FIXTURE_TYPES_CHOICES = (
|
||||||
|
(FIXTURE_TYPE_JSON, _(u'JSON')),
|
||||||
|
(FIXTURE_TYPE_YAML, _(u'YAML')),
|
||||||
|
# Disabing XML until a way to specify a null pk is found
|
||||||
|
#(FIXTURE_TYPE_XML, _(u'XML')),
|
||||||
|
)
|
||||||
|
|
||||||
|
FIXTURE_FILE_TYPE = {
|
||||||
|
FIXTURE_TYPE_JSON: 'json',
|
||||||
|
FIXTURE_TYPE_YAML: 'yaml',
|
||||||
|
FIXTURE_TYPE_XML: 'xml',
|
||||||
|
}
|
||||||
|
|
||||||
|
FIXTURE_TYPE_PK_NULLIFIER = {
|
||||||
|
FIXTURE_TYPE_JSON: lambda x: re.sub('"pk": [0-9]{1,5}', '"pk": null', x),
|
||||||
|
FIXTURE_TYPE_YAML: lambda x: re.sub('pk: [0-9]{1,5}', 'pk: null', x),
|
||||||
|
FIXTURE_TYPE_XML: lambda x: re.sub('pk="[0-9]{1,5}"', 'pk=null', x),
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_LOADDATA = 'loaddata'
|
||||||
36
apps/bootstrap/managers.py
Normal file
36
apps/bootstrap/managers.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
#try:
|
||||||
|
# from cStringIO import StringIO
|
||||||
|
#except ImportError:
|
||||||
|
# from StringIO import StringIO
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.core import serializers
|
||||||
|
|
||||||
|
from .classes import BootstrapModel
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BootstrapSetupManager(models.Manager):
|
||||||
|
def explode(self, data):
|
||||||
|
"""
|
||||||
|
Gets a compressed and compacted bootstrap setup and creates a new
|
||||||
|
database BootstrapSetup instance
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def dump(self, serialization_format):
|
||||||
|
result = []
|
||||||
|
#models = [instance.get_fullname()
|
||||||
|
for bootstrap_model in BootstrapModel.get_all():
|
||||||
|
#logger.debug('models: %s' % models)
|
||||||
|
#options = dict(indent=4, format=format, use_natural_keys=True, interactive=False, verbosity=0, stdout=result)
|
||||||
|
#management.call_command(COMMAND_DUMPDATA, *models, **options)
|
||||||
|
#logger.debug('result: %s' % result)
|
||||||
|
result.append(bootstrap_model.dump(serialization_format))
|
||||||
|
#return result.read()
|
||||||
|
return '\n'.join(result)
|
||||||
38
apps/bootstrap/migrations/0001_initial.py
Normal file
38
apps/bootstrap/migrations/0001_initial.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# -*- 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 'BootstrapSetup'
|
||||||
|
db.create_table('bootstrap_bootstrapsetup', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128)),
|
||||||
|
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||||
|
('fixture', self.gf('django.db.models.fields.TextField')()),
|
||||||
|
('type', self.gf('django.db.models.fields.CharField')(max_length=16)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('bootstrap', ['BootstrapSetup'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Deleting model 'BootstrapSetup'
|
||||||
|
db.delete_table('bootstrap_bootstrapsetup')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'bootstrap.bootstrapsetup': {
|
||||||
|
'Meta': {'ordering': "['name']", 'object_name': 'BootstrapSetup'},
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'fixture': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
|
||||||
|
'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['bootstrap']
|
||||||
0
apps/bootstrap/migrations/__init__.py
Normal file
0
apps/bootstrap/migrations/__init__.py
Normal file
59
apps/bootstrap/models.py
Normal file
59
apps/bootstrap/models.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.core import management
|
||||||
|
|
||||||
|
from .literals import (FIXTURE_TYPES_CHOICES, FIXTURE_FILE_TYPE, COMMAND_LOADDATA)
|
||||||
|
from .managers import BootstrapSetupManager
|
||||||
|
from .classes import BootstrapModel
|
||||||
|
|
||||||
|
|
||||||
|
class BootstrapSetup(models.Model):
|
||||||
|
"""
|
||||||
|
Model to store the fixture for a pre configured setup.
|
||||||
|
"""
|
||||||
|
name = models.CharField(max_length=128, verbose_name=_(u'name'), unique=True)
|
||||||
|
description = models.TextField(verbose_name=_(u'description'), blank=True)
|
||||||
|
fixture = models.TextField(verbose_name=_(u'fixture'), help_text=_(u'These are the actual database structure creation instructions.'))
|
||||||
|
type = models.CharField(max_length=16, verbose_name=_(u'type'), choices=FIXTURE_TYPES_CHOICES)
|
||||||
|
|
||||||
|
objects = BootstrapSetupManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def get_extension(self):
|
||||||
|
return FIXTURE_FILE_TYPE[self.type]
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
BootstrapModel.check_for_data()
|
||||||
|
handle, filepath = tempfile.mkstemp()
|
||||||
|
# Just need the filepath, close the file description
|
||||||
|
os.close(handle)
|
||||||
|
|
||||||
|
filepath = os.path.extsep.join([filepath, self.get_extension()])
|
||||||
|
|
||||||
|
with open(filepath, 'w') as file_handle:
|
||||||
|
file_handle.write(self.fixture)
|
||||||
|
|
||||||
|
management.call_command(COMMAND_LOADDATA, filepath, verbosity=0)
|
||||||
|
os.unlink(filepath)
|
||||||
|
|
||||||
|
def compress(self):
|
||||||
|
"""
|
||||||
|
Return a compacted and compressed version of the BootstrapSetup
|
||||||
|
instance, meant for download.
|
||||||
|
"""
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
return super(BootstrapSetup, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _(u'bootstrap setup')
|
||||||
|
verbose_name_plural = _(u'bootstrap setups')
|
||||||
|
ordering = ['name']
|
||||||
15
apps/bootstrap/permissions.py
Normal file
15
apps/bootstrap/permissions.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from permissions.models import PermissionNamespace, Permission
|
||||||
|
|
||||||
|
namespace = PermissionNamespace('bootstrap', _(u'Database bootstrap'))
|
||||||
|
|
||||||
|
PERMISSION_BOOTSTRAP_VIEW = Permission.objects.register(namespace, 'bootstrap_view', _(u'View bootstrap setups'))
|
||||||
|
PERMISSION_BOOTSTRAP_CREATE = Permission.objects.register(namespace, 'bootstrap_create', _(u'Create bootstrap setups'))
|
||||||
|
PERMISSION_BOOTSTRAP_EDIT = Permission.objects.register(namespace, 'bootstrap_edit', _(u'Edit bootstrap setups'))
|
||||||
|
PERMISSION_BOOTSTRAP_DELETE = Permission.objects.register(namespace, 'bootstrap_delete', _(u'Delete bootstrap setups'))
|
||||||
|
PERMISSION_BOOTSTRAP_EXECUTE = Permission.objects.register(namespace, 'bootstrap_execute', _(u'Execute bootstrap setups'))
|
||||||
|
PERMISSION_BOOTSTRAP_DUMP = Permission.objects.register(namespace, 'bootstrap_dump', _(u'Dump the current project\s setup into a bootstrap setup'))
|
||||||
|
PERMISSION_NUKE_DATABASE = Permission.objects.register(namespace, 'nuke_database', _(u'Erase the entire database and document storage'))
|
||||||
12
apps/bootstrap/post_init.py
Normal file
12
apps/bootstrap/post_init.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from navigation.api import register_links
|
||||||
|
|
||||||
|
from .links import (link_bootstrap_setup_create, link_bootstrap_setup_execute,
|
||||||
|
link_bootstrap_setup_list, link_bootstrap_setup_edit, link_bootstrap_setup_delete,
|
||||||
|
link_bootstrap_setup_view, link_bootstrap_setup_dump)
|
||||||
|
from .models import BootstrapSetup
|
||||||
|
|
||||||
|
register_links([BootstrapSetup], [link_bootstrap_setup_view, link_bootstrap_setup_edit, link_bootstrap_setup_delete, link_bootstrap_setup_execute])
|
||||||
|
register_links([BootstrapSetup], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump], menu_name='secondary_menu')
|
||||||
|
register_links(['bootstrap_setup_list', 'bootstrap_setup_create', 'bootstrap_setup_dump'], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump], menu_name='secondary_menu')
|
||||||
10
apps/bootstrap/registry.py
Normal file
10
apps/bootstrap/registry.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .links import link_bootstrap_setup_tool, link_erase_database
|
||||||
|
|
||||||
|
label = _(u'Bootstrap')
|
||||||
|
description = _(u'Provides pre configured setups for indexes, document types, tags, etc.')
|
||||||
|
dependencies = ['app_registry', 'icons', 'navigation', 'documents', 'indexing', 'metadata', 'tags']
|
||||||
|
setup_links = [link_bootstrap_setup_tool, link_erase_database]
|
||||||
BIN
apps/bootstrap/static/images/icons/lightning.png
Normal file
BIN
apps/bootstrap/static/images/icons/lightning.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
apps/bootstrap/static/images/icons/lightning_go.png
Normal file
BIN
apps/bootstrap/static/images/icons/lightning_go.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
apps/bootstrap/static/images/icons/radioactivity.png
Normal file
BIN
apps/bootstrap/static/images/icons/radioactivity.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
12
apps/bootstrap/urls.py
Normal file
12
apps/bootstrap/urls.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django.conf.urls.defaults import patterns, url
|
||||||
|
|
||||||
|
urlpatterns = patterns('bootstrap.views',
|
||||||
|
url(r'^setup/list/$', 'bootstrap_setup_list', (), 'bootstrap_setup_list'),
|
||||||
|
url(r'^setup/create/$', 'bootstrap_setup_create', (), 'bootstrap_setup_create'),
|
||||||
|
url(r'^setup/(?P<bootstrap_setup_pk>\d+)/edit/$', 'bootstrap_setup_edit', (), 'bootstrap_setup_edit'),
|
||||||
|
url(r'^setup/(?P<bootstrap_setup_pk>\d+)/delete/$', 'bootstrap_setup_delete', (), 'bootstrap_setup_delete'),
|
||||||
|
url(r'^setup/(?P<bootstrap_setup_pk>\d+)/$', 'bootstrap_setup_view', (), 'bootstrap_setup_view'),
|
||||||
|
url(r'^setup/(?P<bootstrap_setup_pk>\d+)/execute/$', 'bootstrap_setup_execute', (), 'bootstrap_setup_execute'),
|
||||||
|
url(r'^setup/dump/$', 'bootstrap_setup_dump', (), 'bootstrap_setup_dump'),
|
||||||
|
url(r'^nuke/$', 'erase_database_view', (), 'erase_database_view'),
|
||||||
|
)
|
||||||
235
apps/bootstrap/views.py
Normal file
235
apps/bootstrap/views.py
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
from permissions.models import Permission
|
||||||
|
|
||||||
|
from .models import BootstrapSetup
|
||||||
|
from .classes import Cleanup, BootstrapModel
|
||||||
|
from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE,
|
||||||
|
PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE,
|
||||||
|
PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_NUKE_DATABASE, PERMISSION_BOOTSTRAP_DUMP)
|
||||||
|
from .forms import BootstrapSetupForm, BootstrapSetupForm_view, BootstrapSetupForm_dump
|
||||||
|
from .exceptions import ExistingData
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_list(request):
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_VIEW])
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'object_list': BootstrapSetup.objects.all(),
|
||||||
|
'title': _(u'bootstrap setups'),
|
||||||
|
'hide_link': True,
|
||||||
|
'extra_columns': [
|
||||||
|
{'name': _(u'description'), 'attribute': 'description'},
|
||||||
|
{'name': _(u'type'), 'attribute': 'get_type_display'},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_to_response('generic_list.html', context,
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_create(request):
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_CREATE])
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = BootstrapSetupForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
bootstrap = form.save()
|
||||||
|
messages.success(request, _(u'Bootstrap created successfully'))
|
||||||
|
return HttpResponseRedirect(reverse('bootstrap_setup_list'))
|
||||||
|
else:
|
||||||
|
messages.error(request, _(u'Error creating bootstrap setup.'))
|
||||||
|
else:
|
||||||
|
form = BootstrapSetupForm()
|
||||||
|
|
||||||
|
return render_to_response('generic_form.html', {
|
||||||
|
'title': _(u'create bootstrap'),
|
||||||
|
'form': form,
|
||||||
|
},
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_edit(request, bootstrap_setup_pk):
|
||||||
|
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
|
||||||
|
|
||||||
|
bootstrap = get_object_or_404(BootstrapSetup, pk=bootstrap_setup_pk)
|
||||||
|
|
||||||
|
try:
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_EDIT])
|
||||||
|
except PermissionDenied:
|
||||||
|
AccessEntry.objects.check_access(PERMISSION_BOOTSTRAP_EDIT, request.user, bootstrap)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = BootstrapSetupForm(instance=bootstrap, data=request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _(u'Bootstrap setup edited successfully'))
|
||||||
|
return HttpResponseRedirect(previous)
|
||||||
|
else:
|
||||||
|
messages.error(request, _(u'Error editing bootstrap setup.'))
|
||||||
|
else:
|
||||||
|
form = BootstrapSetupForm(instance=bootstrap)
|
||||||
|
|
||||||
|
return render_to_response('generic_form.html', {
|
||||||
|
'title': _(u'edit bootstrap setup: %s') % bootstrap,
|
||||||
|
'form': form,
|
||||||
|
'object': bootstrap,
|
||||||
|
'previous': previous,
|
||||||
|
'object_name': _(u'bootstrap setup'),
|
||||||
|
},
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_delete(request, bootstrap_setup_pk):
|
||||||
|
bootstrap = get_object_or_404(BootstrapSetup, pk=bootstrap_setup_pk)
|
||||||
|
|
||||||
|
try:
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_DELETE])
|
||||||
|
except PermissionDenied:
|
||||||
|
AccessEntry.objects.check_access(PERMISSION_BOOTSTRAP_DELETE, request.user, bootstrap)
|
||||||
|
|
||||||
|
post_action_redirect = reverse('bootstrap_setup_list')
|
||||||
|
|
||||||
|
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
|
||||||
|
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
try:
|
||||||
|
bootstrap.delete()
|
||||||
|
messages.success(request, _(u'Bootstrap setup: %s deleted successfully.') % bootstrap)
|
||||||
|
except Exception, e:
|
||||||
|
messages.error(request, _(u'Bootstrap setup: %(bootstrap)s delete error: %(error)s') % {
|
||||||
|
'bootstrap': bootstrap, 'error': e})
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse('bootstrap_setup_list'))
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'object_name': _(u'bootstrap setup'),
|
||||||
|
'delete_view': True,
|
||||||
|
'previous': previous,
|
||||||
|
'next': next,
|
||||||
|
'object': bootstrap,
|
||||||
|
'title': _(u'Are you sure you with to delete the bootstrap setup: %s?') % bootstrap,
|
||||||
|
'form_icon': icon_bootstrap_setup_delete,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_to_response('generic_confirm.html', context,
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_view(request, bootstrap_setup_pk):
|
||||||
|
bootstrap = get_object_or_404(BootstrapSetup, pk=bootstrap_setup_pk)
|
||||||
|
|
||||||
|
try:
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_VIEW])
|
||||||
|
except PermissionDenied:
|
||||||
|
AccessEntry.objects.check_access(PERMISSION_BOOTSTRAP_VIEW, request.user, bootstrap)
|
||||||
|
|
||||||
|
form = BootstrapSetupForm_view(instance=bootstrap)
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'object': bootstrap,
|
||||||
|
'object_name': _(u'bootstrap setup'),
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_to_response('generic_detail.html', context,
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_execute(request, bootstrap_setup_pk):
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_EXECUTE])
|
||||||
|
bootstrap_setup = get_object_or_404(BootstrapSetup, pk=bootstrap_setup_pk)
|
||||||
|
|
||||||
|
post_action_redirect = reverse('bootstrap_setup_list')
|
||||||
|
|
||||||
|
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
|
||||||
|
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
try:
|
||||||
|
bootstrap_setup.execute()
|
||||||
|
except ExistingData:
|
||||||
|
messages.error(request, _(u'Cannot execute bootstrap setup, there is existing data. Erase database and try again.'))
|
||||||
|
except Exception, exc:
|
||||||
|
messages.error(request, _(u'Error executing bootstrap setup; %s') % exc)
|
||||||
|
else:
|
||||||
|
messages.success(request, _(u'Bootstrap setup "%s" executed successfully.') % bootstrap_setup)
|
||||||
|
return HttpResponseRedirect(next)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'object_name': _(u'bootstrap setup'),
|
||||||
|
'delete_view': False,
|
||||||
|
'previous': previous,
|
||||||
|
'next': next,
|
||||||
|
'form_icon': 'lightning_go.png',
|
||||||
|
'object': bootstrap_setup,
|
||||||
|
}
|
||||||
|
|
||||||
|
context['title'] = _(u'Are you sure you wish to execute the database bootstrap named: %s?') % bootstrap_setup
|
||||||
|
|
||||||
|
return render_to_response('generic_confirm.html', context,
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def bootstrap_setup_dump(request):
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_DUMP])
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = BootstrapSetupForm_dump(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
bootstrap = form.save(commit=False)
|
||||||
|
try:
|
||||||
|
bootstrap.fixture = BootstrapSetup.objects.dump(serialization_format=bootstrap.type)
|
||||||
|
except Exception as exception:
|
||||||
|
messages.error(request, _(u'Error dumping bootstrap setup; %s') % exception)
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
bootstrap.save()
|
||||||
|
messages.success(request, _(u'Bootstrap created successfully.'))
|
||||||
|
return HttpResponseRedirect(reverse('bootstrap_setup_list'))
|
||||||
|
else:
|
||||||
|
form = BootstrapSetupForm_dump()
|
||||||
|
|
||||||
|
return render_to_response('generic_form.html', {
|
||||||
|
'title': _(u'dump current setup into a bootstrap setup'),
|
||||||
|
'form': form,
|
||||||
|
},
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def erase_database_view(request):
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_NUKE_DATABASE])
|
||||||
|
|
||||||
|
post_action_redirect = None
|
||||||
|
|
||||||
|
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
|
||||||
|
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
try:
|
||||||
|
Cleanup.execute_all()
|
||||||
|
except Exception, exc:
|
||||||
|
messages.error(request, _(u'Error erasing database; %s') % exc)
|
||||||
|
else:
|
||||||
|
messages.success(request, _(u'Database erased successfully.'))
|
||||||
|
return HttpResponseRedirect(next)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'delete_view': False,
|
||||||
|
'previous': previous,
|
||||||
|
'next': next,
|
||||||
|
'form_icon': 'radioactivity.png',
|
||||||
|
}
|
||||||
|
|
||||||
|
context['title'] = _(u'Are you sure you wish to erase the entire database and document storage?')
|
||||||
|
context['message'] = _(u'All documents, sources, metadata, metadata types, set, tags, indexes and logs will be lost irreversibly!')
|
||||||
|
|
||||||
|
return render_to_response('generic_confirm.html', context,
|
||||||
|
context_instance=RequestContext(request))
|
||||||
@@ -103,6 +103,7 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'common.middleware.strip_spaces_widdleware.SpacelessMiddleware',
|
'common.middleware.strip_spaces_widdleware.SpacelessMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.transaction.TransactionMiddleware',
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
@@ -164,6 +165,7 @@ INSTALLED_APPS = (
|
|||||||
'installation',
|
'installation',
|
||||||
# Mayan EDMS
|
# Mayan EDMS
|
||||||
'storage',
|
'storage',
|
||||||
|
'app_registry',
|
||||||
'folders',
|
'folders',
|
||||||
'tags',
|
'tags',
|
||||||
'document_comments',
|
'document_comments',
|
||||||
@@ -179,7 +181,7 @@ INSTALLED_APPS = (
|
|||||||
'rest_api',
|
'rest_api',
|
||||||
'document_signatures',
|
'document_signatures',
|
||||||
'checkouts',
|
'checkouts',
|
||||||
|
'bootstrap',
|
||||||
# Has to be last so the other apps can register it's signals
|
# Has to be last so the other apps can register it's signals
|
||||||
'signaler',
|
'signaler',
|
||||||
)
|
)
|
||||||
|
|||||||
1
urls.py
1
urls.py
@@ -34,6 +34,7 @@ urlpatterns = patterns('',
|
|||||||
(r'^checkouts/', include('checkouts.urls')),
|
(r'^checkouts/', include('checkouts.urls')),
|
||||||
(r'^installation/', include('installation.urls')),
|
(r'^installation/', include('installation.urls')),
|
||||||
(r'^scheduler/', include('scheduler.urls')),
|
(r'^scheduler/', include('scheduler.urls')),
|
||||||
|
(r'^bootstrap/', include('bootstrap.urls')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user