Add support for importing bootstrap setups from file

This commit is contained in:
Roberto Rosario
2012-10-14 07:00:27 -04:00
parent 37372ba554
commit 6ea76ef84f
10 changed files with 119 additions and 25 deletions

View File

@@ -8,7 +8,8 @@ from django.core import serializers
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from .exceptions import ExistingData from .exceptions import ExistingData
from .literals import FIXTURE_TYPE_PK_NULLIFIER, FIXTURE_TYPE_MODEL_PROCESS from .literals import (FIXTURE_TYPE_PK_NULLIFIER, FIXTURE_TYPE_MODEL_PROCESS,
FIXTURE_METADATA_REMARK_CHARACTER)
from .utils import toposort2 from .utils import toposort2
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -131,13 +132,32 @@ class FixtureMetadata(object):
return '\n'.join(result) return '\n'.join(result)
def __init__(self, literal, generate_function): @classmethod
def read_all(cls, data):
result = {}
for instance in cls.get_all():
single_result = instance.read_value(data)
if single_result:
result[instance.property_name] = single_result
return result
def __init__(self, literal, generate_function, read_function=None, property_name=None):
self.literal = literal self.literal = literal
self.generate_function = generate_function self.generate_function = generate_function
self.property_name = property_name
self.read_function = read_function or (lambda x: x)
self.__class__._registry[id(self)] = self self.__class__._registry[id(self)] = self
def get_with_remark(self):
return '%s %s' % (FIXTURE_METADATA_REMARK_CHARACTER, self.literal)
def generate(self, fixture_instance): def generate(self, fixture_instance):
return '# %s: %s' % (self.literal, self.generate_function(fixture_instance)) return '%s: %s' % (self.get_with_remark(), self.generate_function(fixture_instance))
def read_value(self, fixture_data): def read_value(self, fixture_data):
return [line[line.find(self.literal) + len(self.literal) + 2:] for line in fixture_data.splitlines(False) if line.find(self.literal)] if self.property_name:
for line in fixture_data.splitlines(False):
if line.startswith(self.get_with_remark()):
# TODO: replace the "+ 4" with a space and next character finding algo
return self.read_function(line[len(self.literal) + 4:])

View File

@@ -43,3 +43,9 @@ class BootstrapSetupForm_dump(BootstrapSetupForm):
class Meta(BootstrapSetupForm.Meta): class Meta(BootstrapSetupForm.Meta):
model = BootstrapSetup model = BootstrapSetup
exclude = ('fixture',) exclude = ('fixture',)
class BootstrapUploadForm(forms.Form):
file = forms.FileField(
label=_(u'Bootstrap setup file'),
)

View File

@@ -5,7 +5,8 @@ from django.utils.translation import ugettext_lazy as _
from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE, from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE,
PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE, PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE,
PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_BOOTSTRAP_DUMP, PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_BOOTSTRAP_DUMP,
PERMISSION_NUKE_DATABASE, PERMISSION_BOOTSTRAP_EXPORT) PERMISSION_NUKE_DATABASE, PERMISSION_BOOTSTRAP_EXPORT,
PERMISSION_BOOTSTRAP_IMPORT)
link_bootstrap_setup_tool = {'text': _(u'bootstrap'), 'view': 'bootstrap_setup_list', 'icon': 'lightning.png', 'permissions': [PERMISSION_BOOTSTRAP_VIEW]} 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_list = {'text': _(u'bootstrap setup list'), 'view': 'bootstrap_setup_list', 'famfam': 'lightning', 'permissions': [PERMISSION_BOOTSTRAP_VIEW]}
@@ -16,4 +17,5 @@ link_bootstrap_setup_view = {'text': _(u'details'), 'view': 'bootstrap_setup_vie
link_bootstrap_setup_execute = {'text': _(u'execute'), 'view': 'bootstrap_setup_execute', 'args': 'object.pk', 'famfam': 'lightning_go', 'permissions': [PERMISSION_BOOTSTRAP_EXECUTE]} 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_bootstrap_setup_dump = {'text': _(u'dump current setup'), 'view': 'bootstrap_setup_dump', 'famfam': 'arrow_down', 'permissions': [PERMISSION_BOOTSTRAP_DUMP]}
link_bootstrap_setup_export = {'text': _(u'export'), 'view': 'bootstrap_setup_export', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_BOOTSTRAP_EXPORT]} link_bootstrap_setup_export = {'text': _(u'export'), 'view': 'bootstrap_setup_export', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_BOOTSTRAP_EXPORT]}
link_bootstrap_setup_import = {'text': _(u'import'), 'view': 'bootstrap_setup_import', 'famfam': 'folder', 'permissions': [PERMISSION_BOOTSTRAP_IMPORT]}
link_erase_database = {'text': _(u'erase database'), 'view': 'erase_database_view', 'icon': 'radioactivity.png', 'permissions': [PERMISSION_NUKE_DATABASE]} link_erase_database = {'text': _(u'erase database'), 'view': 'erase_database_view', 'icon': 'radioactivity.png', 'permissions': [PERMISSION_NUKE_DATABASE]}

View File

@@ -64,6 +64,7 @@ if YAML_AVAILABLE:
FIXTURE_TYPES_CHOICES += (FIXTURE_TYPE_BETTER_YAML, _(u'Better YAML')), FIXTURE_TYPES_CHOICES += (FIXTURE_TYPE_BETTER_YAML, _(u'Better YAML')),
# better_yaml is not working with natural keys # better_yaml is not working with natural keys
FIXTURE_METADATA_REMARK_CHARACTER = '#'
DATETIME_STRING_FORMAT = '%a, %d %b %Y %H:%M:%S +0000' DATETIME_STRING_FORMAT = '%a, %d %b %Y %H:%M:%S +0000'
FIXTURE_METADATA_CREATED = 'created' FIXTURE_METADATA_CREATED = 'created'
FIXTURE_METADATA_EDITED = 'edited' FIXTURE_METADATA_EDITED = 'edited'
@@ -71,5 +72,4 @@ FIXTURE_METADATA_MAYAN_VERSION = 'mayan_edms_version'
FIXTURE_METADATA_FORMAT = 'format' FIXTURE_METADATA_FORMAT = 'format'
FIXTURE_METADATA_NAME = 'name' FIXTURE_METADATA_NAME = 'name'
FIXTURE_METADATA_DESCRIPTION = 'description' FIXTURE_METADATA_DESCRIPTION = 'description'
BOOTSTRAP_EXTENSION = 'txt' BOOTSTRAP_EXTENSION = 'txt'

View File

@@ -5,7 +5,7 @@ import logging
from django.db import models from django.db import models
from django.core import serializers from django.core import serializers
from .classes import BootstrapModel from .classes import BootstrapModel, FixtureMetadata
from .literals import FIXTURE_TYPE_FIXTURE_PROCESS, FIXTURE_TYPE_EMPTY_FIXTURE from .literals import FIXTURE_TYPE_FIXTURE_PROCESS, FIXTURE_TYPE_EMPTY_FIXTURE
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -32,3 +32,11 @@ class BootstrapSetupManager(models.Manager):
if not FIXTURE_TYPE_EMPTY_FIXTURE[serialization_format](model_fixture): if not FIXTURE_TYPE_EMPTY_FIXTURE[serialization_format](model_fixture):
result.append(model_fixture) result.append(model_fixture)
return FIXTURE_TYPE_FIXTURE_PROCESS[serialization_format]('\n'.join(result)) return FIXTURE_TYPE_FIXTURE_PROCESS[serialization_format]('\n'.join(result))
def import_setup(self, files):
file_data = files.read()
metadata = FixtureMetadata.read_all(file_data)
instance = self.model(fixture=file_data, **metadata)
instance.save(update_metadata=False)

View File

@@ -16,7 +16,7 @@ from django.core import management
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from .literals import (FIXTURE_TYPES_CHOICES, FIXTURE_FILE_TYPE, COMMAND_LOADDATA, from .literals import (FIXTURE_TYPES_CHOICES, FIXTURE_FILE_TYPE, COMMAND_LOADDATA,
BOOTSTRAP_EXTENSION) BOOTSTRAP_EXTENSION, FIXTURE_METADATA_REMARK_CHARACTER)
from .managers import BootstrapSetupManager from .managers import BootstrapSetupManager
from .classes import BootstrapModel, FixtureMetadata from .classes import BootstrapModel, FixtureMetadata
@@ -78,7 +78,7 @@ class BootstrapSetup(models.Model):
""" """
Return the bootstrap setup's fixture without comments. Return the bootstrap setup's fixture without comments.
""" """
return re.sub(re.compile('#.*?\n'), '', self.fixture) return re.sub(re.compile('%s.*?\n' % FIXTURE_METADATA_REMARK_CHARACTER), '', self.fixture)
def get_metadata_string(self): def get_metadata_string(self):
""" """
@@ -93,7 +93,9 @@ class BootstrapSetup(models.Model):
return SimpleUploadedFile(name=self.get_filename(), content=self.fixture) return SimpleUploadedFile(name=self.get_filename(), content=self.fixture)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.fixture = '%s\n\n%s' % ( update_metadata = kwargs.pop('update_metadata', True)
if update_metadata:
self.fixture = '%s\n%s' % (
self.get_metadata_string(), self.get_metadata_string(),
self.cleaned_fixture self.cleaned_fixture
) )

View File

@@ -12,5 +12,6 @@ PERMISSION_BOOTSTRAP_EDIT = Permission.objects.register(namespace, 'bootstrap_ed
PERMISSION_BOOTSTRAP_DELETE = Permission.objects.register(namespace, 'bootstrap_delete', _(u'Delete 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_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_BOOTSTRAP_DUMP = Permission.objects.register(namespace, 'bootstrap_dump', _(u'Dump the current project\s setup into a bootstrap setup'))
PERMISSION_BOOTSTRAP_EXPORT = Permission.objects.register(namespace, 'bootstrap_export', _(u'Export the bootstrap setup as files')) PERMISSION_BOOTSTRAP_EXPORT = Permission.objects.register(namespace, 'bootstrap_export', _(u'Export bootstrap setups as files'))
PERMISSION_BOOTSTRAP_IMPORT = Permission.objects.register(namespace, 'bootstrap_import', _(u'Import new bootstrap setups'))
PERMISSION_NUKE_DATABASE = Permission.objects.register(namespace, 'nuke_database', _(u'Erase the entire database and document storage')) PERMISSION_NUKE_DATABASE = Permission.objects.register(namespace, 'nuke_database', _(u'Erase the entire database and document storage'))

View File

@@ -1,13 +1,14 @@
from __future__ import absolute_import from __future__ import absolute_import
from time import gmtime, strftime import datetime
from navigation.api import register_links from navigation.api import register_links
from main import __version__ from main import __version__
from .links import (link_bootstrap_setup_create, link_bootstrap_setup_execute, 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_list, link_bootstrap_setup_edit, link_bootstrap_setup_delete,
link_bootstrap_setup_view, link_bootstrap_setup_dump, link_bootstrap_setup_export) link_bootstrap_setup_view, link_bootstrap_setup_dump, link_bootstrap_setup_export,
link_bootstrap_setup_import)
from .models import BootstrapSetup from .models import BootstrapSetup
from .classes import FixtureMetadata from .classes import FixtureMetadata
from .literals import (FIXTURE_METADATA_CREATED, FIXTURE_METADATA_EDITED, from .literals import (FIXTURE_METADATA_CREATED, FIXTURE_METADATA_EDITED,
@@ -15,12 +16,12 @@ from .literals import (FIXTURE_METADATA_CREATED, FIXTURE_METADATA_EDITED,
FIXTURE_METADATA_DESCRIPTION, DATETIME_STRING_FORMAT) FIXTURE_METADATA_DESCRIPTION, DATETIME_STRING_FORMAT)
register_links([BootstrapSetup], [link_bootstrap_setup_view, link_bootstrap_setup_edit, link_bootstrap_setup_delete, link_bootstrap_setup_execute, link_bootstrap_setup_export]) register_links([BootstrapSetup], [link_bootstrap_setup_view, link_bootstrap_setup_edit, link_bootstrap_setup_delete, link_bootstrap_setup_execute, link_bootstrap_setup_export])
register_links([BootstrapSetup], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump], menu_name='secondary_menu') register_links([BootstrapSetup], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump, link_bootstrap_setup_import], 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') register_links(['bootstrap_setup_list', 'bootstrap_setup_create', 'bootstrap_setup_dump', 'bootstrap_setup_import'], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump, link_bootstrap_setup_import], menu_name='secondary_menu')
FixtureMetadata(FIXTURE_METADATA_CREATED, generate_function=lambda fixture_instance: strftime(fixture_instance.created.strftime(DATETIME_STRING_FORMAT))) FixtureMetadata(FIXTURE_METADATA_CREATED, generate_function=lambda fixture_instance: fixture_instance.created.strftime(DATETIME_STRING_FORMAT), read_function=lambda x: datetime.datetime.strptime(x, DATETIME_STRING_FORMAT), property_name='created')
FixtureMetadata(FIXTURE_METADATA_EDITED, generate_function=lambda fixture_instance: strftime(DATETIME_STRING_FORMAT, gmtime())) FixtureMetadata(FIXTURE_METADATA_EDITED, generate_function=lambda fixture_instance: datetime.datetime.now().strftime(DATETIME_STRING_FORMAT))
FixtureMetadata(FIXTURE_METADATA_MAYAN_VERSION, generate_function=lambda fixture_instance: __version__) FixtureMetadata(FIXTURE_METADATA_MAYAN_VERSION, generate_function=lambda fixture_instance: __version__)
FixtureMetadata(FIXTURE_METADATA_FORMAT, generate_function=lambda fixture_instance: fixture_instance.type) FixtureMetadata(FIXTURE_METADATA_FORMAT, generate_function=lambda fixture_instance: fixture_instance.type, property_name='type')
FixtureMetadata(FIXTURE_METADATA_NAME, generate_function=lambda fixture_instance: fixture_instance.name) FixtureMetadata(FIXTURE_METADATA_NAME, generate_function=lambda fixture_instance: fixture_instance.name, property_name='name')
FixtureMetadata(FIXTURE_METADATA_DESCRIPTION, generate_function=lambda fixture_instance: fixture_instance.description) FixtureMetadata(FIXTURE_METADATA_DESCRIPTION, generate_function=lambda fixture_instance: fixture_instance.description, property_name='description')

View File

@@ -9,5 +9,6 @@ urlpatterns = patterns('bootstrap.views',
url(r'^setup/(?P<bootstrap_setup_pk>\d+)/execute/$', 'bootstrap_setup_execute', (), 'bootstrap_setup_execute'), url(r'^setup/(?P<bootstrap_setup_pk>\d+)/execute/$', 'bootstrap_setup_execute', (), 'bootstrap_setup_execute'),
url(r'^setup/(?P<bootstrap_setup_pk>\d+)/export/$', 'bootstrap_setup_export', (), 'bootstrap_setup_export'), url(r'^setup/(?P<bootstrap_setup_pk>\d+)/export/$', 'bootstrap_setup_export', (), 'bootstrap_setup_export'),
url(r'^setup/dump/$', 'bootstrap_setup_dump', (), 'bootstrap_setup_dump'), url(r'^setup/dump/$', 'bootstrap_setup_dump', (), 'bootstrap_setup_dump'),
url(r'^setup/import/$', 'bootstrap_setup_import', (), 'bootstrap_setup_import'),
url(r'^nuke/$', 'erase_database_view', (), 'erase_database_view'), url(r'^nuke/$', 'erase_database_view', (), 'erase_database_view'),
) )

View File

@@ -17,9 +17,9 @@ from .classes import Cleanup, BootstrapModel
from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE, from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE,
PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE, PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE,
PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_NUKE_DATABASE, PERMISSION_BOOTSTRAP_DUMP, PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_NUKE_DATABASE, PERMISSION_BOOTSTRAP_DUMP,
PERMISSION_BOOTSTRAP_EXPORT) PERMISSION_BOOTSTRAP_EXPORT, PERMISSION_BOOTSTRAP_IMPORT)
from .forms import (BootstrapSetupForm, BootstrapSetupForm_view, BootstrapSetupForm_dump, from .forms import (BootstrapSetupForm, BootstrapSetupForm_view, BootstrapSetupForm_dump,
BootstrapSetupForm_edit) BootstrapSetupForm_edit, BootstrapUploadForm)
from .exceptions import ExistingData from .exceptions import ExistingData
@@ -227,6 +227,59 @@ def bootstrap_setup_export(request, bootstrap_setup_pk):
) )
def bootstrap_setup_import(request):
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_IMPORT])
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
if request.method == 'POST':
form = BootstrapUploadForm(request.POST, request.FILES)
if form.is_valid():
try:
BootstrapSetup.objects.import_setup(request.FILES['file'])
messages.success(request, _(u'Bootstrap setup imported successfully.'))
return HttpResponseRedirect(reverse('bootstrap_setup_list'))
except Exception as exception:
messages.error(request, exception)
return HttpResponseRedirect(previous)
else:
form = BootstrapUploadForm()
return render_to_response('generic_form.html', {
'title': _(u'Import bootstrap setup'),
'form_icon': 'folder.png',
'form': form,
'previous': previous,
}, 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): def erase_database_view(request):
Permission.objects.check_permissions(request.user, [PERMISSION_NUKE_DATABASE]) Permission.objects.check_permissions(request.user, [PERMISSION_NUKE_DATABASE])