Add support for synchronizing bootstrap setups available with the official repository

This commit is contained in:
Roberto Rosario
2012-12-11 01:22:46 -04:00
parent 74689a970d
commit 1743ce93f2
8 changed files with 76 additions and 12 deletions

View File

@@ -6,7 +6,7 @@ from .permissions import (PERMISSION_BOOTSTRAP_VIEW, PERMISSION_BOOTSTRAP_CREATE
PERMISSION_BOOTSTRAP_EDIT, PERMISSION_BOOTSTRAP_DELETE,
PERMISSION_BOOTSTRAP_EXECUTE, PERMISSION_BOOTSTRAP_DUMP,
PERMISSION_NUKE_DATABASE, PERMISSION_BOOTSTRAP_EXPORT,
PERMISSION_BOOTSTRAP_IMPORT)
PERMISSION_BOOTSTRAP_IMPORT, PERMISSION_BOOTSTRAP_REPOSITORY_SYNC)
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]}
@@ -19,4 +19,5 @@ link_bootstrap_setup_dump = {'text': _(u'dump current setup'), 'view': 'bootstra
link_bootstrap_setup_export = {'text': _(u'export'), 'view': 'bootstrap_setup_export', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_BOOTSTRAP_EXPORT]}
link_bootstrap_setup_import_from_file = {'text': _(u'import from file'), 'view': 'bootstrap_setup_import_from_file', 'famfam': 'folder', 'permissions': [PERMISSION_BOOTSTRAP_IMPORT]}
link_bootstrap_setup_import_from_url = {'text': _(u'import from URL'), 'view': 'bootstrap_setup_import_from_url', 'famfam': 'world', 'permissions': [PERMISSION_BOOTSTRAP_IMPORT]}
link_bootstrap_setup_repository_sync = {'text': _(u'sync with repository'), 'view': 'bootstrap_setup_repository_sync', 'famfam': 'world', 'permissions': [PERMISSION_BOOTSTRAP_REPOSITORY_SYNC]}
link_erase_database = {'text': _(u'erase database'), 'view': 'erase_database_view', 'icon': 'radioactivity.png', 'permissions': [PERMISSION_NUKE_DATABASE]}

View File

@@ -76,3 +76,6 @@ FIXTURE_METADATA_DESCRIPTION = 'description'
BOOTSTRAP_EXTENSION = 'txt'
BOOTSTRAP_SETUP_MAGIC_NUMBER = 'bootstrap setup'
BOOTSTRAP_REPOSITORY_URL = 'http://bootstrap.mayan-edms.com'
BOOTSTRAP_REPOSITORY_INDEX_FILE = '_repo_index.txt'

View File

@@ -6,9 +6,13 @@ import requests
from django.db import models
from django.core import serializers
from django.utils.simplejson import loads
from django.db import IntegrityError
from django.db.models import Q
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,
BOOTSTRAP_REPOSITORY_URL, BOOTSTRAP_REPOSITORY_INDEX_FILE)
logger = logging.getLogger(__name__)
@@ -28,19 +32,44 @@ class BootstrapSetupManager(models.Manager):
result.append(model_fixture)
return FIXTURE_TYPE_FIXTURE_PROCESS[serialization_format]('\n'.join(result))
def import_setup(self, file_data):
def import_setup(self, file_data, overwrite=False):
BootstrapModel.check_magic_number(file_data)
metadata = FixtureMetadata.read_all(file_data)
instance = self.model(fixture=file_data, **metadata)
try:
instance.save(update_metadata=False)
except IntegrityError:
if not overwrite:
raise
else:
# Delete conflicting bootstrap setups
query = Q()
if 'slug' in metadata:
query = query | Q(slug=metadata['slug'])
if 'name' in metadata:
query = query | Q(name=metadata['name'])
self.model.objects.filter(query).delete()
self.import_setup(file_data)
def import_from_file(self, files):
file_data = files.read()
self.import_setup(file_data)
def import_from_url(self, url):
def import_from_url(self, url, **kwargs):
response = requests.get(url)
if response.status_code == requests.codes.ok:
self.import_setup(response.text)
self.import_setup(response.text, **kwargs)
else:
response.raise_for_status()
def repository_sync(self):
response = requests.get('%s/%s' % (BOOTSTRAP_REPOSITORY_URL, BOOTSTRAP_REPOSITORY_INDEX_FILE))
if response.status_code == requests.codes.ok:
for entry in loads(response.text):
bootstrap_setup_url = '%s/%s' % (BOOTSTRAP_REPOSITORY_URL, entry['filename'])
self.import_from_url(bootstrap_setup_url, overwrite=True)
else:
response.raise_for_status()

View File

@@ -14,4 +14,5 @@ PERMISSION_BOOTSTRAP_EXECUTE = Permission.objects.register(namespace, 'bootstrap
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 bootstrap setups as files'))
PERMISSION_BOOTSTRAP_IMPORT = Permission.objects.register(namespace, 'bootstrap_import', _(u'Import new bootstrap setups'))
PERMISSION_BOOTSTRAP_REPOSITORY_SYNC = Permission.objects.register(namespace, 'bootstrap_repo_sync', _(u'Sync the local bootstrap setups with a published repository'))
PERMISSION_NUKE_DATABASE = Permission.objects.register(namespace, 'nuke_database', _(u'Erase the entire database and document storage'))

View File

@@ -8,7 +8,8 @@ from main import __version__
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, link_bootstrap_setup_export,
link_bootstrap_setup_import_from_url, link_bootstrap_setup_import_from_file)
link_bootstrap_setup_import_from_url, link_bootstrap_setup_import_from_file,
link_bootstrap_setup_repository_sync)
from .models import BootstrapSetup
from .classes import FixtureMetadata
from .literals import (FIXTURE_METADATA_CREATED, FIXTURE_METADATA_EDITED,
@@ -16,8 +17,8 @@ from .literals import (FIXTURE_METADATA_CREATED, FIXTURE_METADATA_EDITED,
FIXTURE_METADATA_DESCRIPTION, DATETIME_STRING_FORMAT, FIXTURE_METADATA_SLUG)
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, link_bootstrap_setup_import_from_file, link_bootstrap_setup_import_from_url], menu_name='secondary_menu')
register_links(['bootstrap_setup_list', 'bootstrap_setup_create', 'bootstrap_setup_dump', 'bootstrap_setup_import_from_file', 'bootstrap_setup_import_from_url'], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump, link_bootstrap_setup_import_from_file, link_bootstrap_setup_import_from_url], menu_name='secondary_menu')
register_links([BootstrapSetup], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump, link_bootstrap_setup_import_from_file, link_bootstrap_setup_import_from_url, link_bootstrap_setup_repository_sync], menu_name='secondary_menu')
register_links(['bootstrap_setup_list', 'bootstrap_setup_create', 'bootstrap_setup_dump', 'bootstrap_setup_import_from_file', 'bootstrap_setup_import_from_url', 'bootstrap_setup_repository_sync'], [link_bootstrap_setup_list, link_bootstrap_setup_create, link_bootstrap_setup_dump, link_bootstrap_setup_import_from_file, link_bootstrap_setup_import_from_url, link_bootstrap_setup_repository_sync], menu_name='secondary_menu')
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: datetime.datetime.now().strftime(DATETIME_STRING_FORMAT))

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -11,5 +11,6 @@ urlpatterns = patterns('bootstrap.views',
url(r'^setup/dump/$', 'bootstrap_setup_dump', (), 'bootstrap_setup_dump'),
url(r'^setup/import/file/$', 'bootstrap_setup_import_from_file', (), 'bootstrap_setup_import_from_file'),
url(r'^setup/import/url/$', 'bootstrap_setup_import_from_url', (), 'bootstrap_setup_import_from_url'),
url(r'^setup/repository/sync/$', 'bootstrap_setup_repository_sync', (), 'bootstrap_setup_repository_sync'),
url(r'^nuke/$', 'erase_database_view', (), 'erase_database_view'),
)

View File

@@ -17,7 +17,7 @@ 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,
PERMISSION_BOOTSTRAP_EXPORT, PERMISSION_BOOTSTRAP_IMPORT)
PERMISSION_BOOTSTRAP_EXPORT, PERMISSION_BOOTSTRAP_IMPORT, PERMISSION_BOOTSTRAP_REPOSITORY_SYNC)
from .forms import (BootstrapSetupForm, BootstrapSetupForm_view, BootstrapSetupForm_dump,
BootstrapSetupForm_edit, BootstrapFileImportForm, BootstrapURLImportForm)
from .exceptions import ExistingData, NotABootstrapSetup
@@ -242,7 +242,7 @@ def bootstrap_setup_import_from_file(request):
except NotABootstrapSetup:
messages.error(request, _(u'File is not a bootstrap setup.'))
except Exception as exception:
messages.error(request, exception)
messages.error(request, _(u'Error importing bootstrap setup from file; %s.') % exception)
return HttpResponseRedirect(previous)
else:
form = BootstrapFileImportForm()
@@ -270,7 +270,7 @@ def bootstrap_setup_import_from_url(request):
except NotABootstrapSetup:
messages.error(request, _(u'Data from URL is not a bootstrap setup.'))
except Exception as exception:
messages.error(request, exception)
messages.error(request, _(u'Error importing bootstrap setup from URL; %s.') % exception)
return HttpResponseRedirect(previous)
else:
form = BootstrapURLImportForm()
@@ -312,3 +312,31 @@ def erase_database_view(request):
return render_to_response('generic_confirm.html', context,
context_instance=RequestContext(request))
def bootstrap_setup_repository_sync(request):
Permission.objects.check_permissions(request.user, [PERMISSION_BOOTSTRAP_REPOSITORY_SYNC])
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:
BootstrapSetup.objects.repository_sync()
messages.success(request, _(u'Bootstrap repository successfully synchronized.'))
except Exception, e:
messages.error(request, _(u'Bootstrap repository synchronization error: %(error)s') % {'error': e})
return HttpResponseRedirect(reverse('bootstrap_setup_list'))
context = {
'previous': previous,
'next': next,
'title': _(u'Are you sure you wish to synchronize with the bootstrap repository?'),
'form_icon': 'world.png',
}
return render_to_response('generic_confirm.html', context,
context_instance=RequestContext(request))