diff -r 000000000000 -r b97547f5f1fa goa/appobjects/dbmgmt.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/goa/appobjects/dbmgmt.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,185 @@ +"""special management views to manage repository content (initialization and +restoration). + +:organization: Logilab +:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +from os.path import exists, join, abspath +from pickle import loads, dumps + +from logilab.common.decorators import cached +from logilab.mtconverter import html_escape + +from cubicweb.common.view import StartupView +from cubicweb.web import Redirect +from cubicweb.goa.dbinit import fix_entities, init_persistent_schema, insert_versions + +from google.appengine.api.datastore import Entity, Key, Get, Put, Delete +from google.appengine.api.datastore_types import Blob +from google.appengine.api.datastore_errors import EntityNotFoundError + + +def _get_status(name, create=True): + key = Key.from_path('EApplicationStatus', name) + try: + status = Get(key) + except EntityNotFoundError: + if create: + status = Entity('EApplicationStatus', name=name) + else: + status = None + return status + + +class AuthInfo(StartupView): + """special management view to get cookie values to give to laxctl commands + which are doing datastore administration requests + """ + id = 'authinfo' + require_groups = ('managers',) + + def call(self): + cookie = self.req.get_cookie() + values = [] + if self.config['use-google-auth']: + for param in ('ACSID', 'dev_appserver_login'): + morsel = cookie.get(param) + if morsel: + values.append('%s=%s' % (param, morsel.value)) + break + values.append('__session=%s' % cookie['__session'].value) + self.w(u"

pass this flag to the client: --cookie='%s'

" + % html_escape('; '.join(values))) + + + +class ContentInit(StartupView): + """special management view to initialize content of a repository, + step by step to avoid depassing quotas + """ + id = 'contentinit' + require_groups = ('managers',) + + def server_session(self): + ssession = self.config.repo_session(self.req.cnx.sessionid) + ssession.set_pool() + return ssession + + def end_core_step(self, msg, status, stepid): + status['cpath'] = '' + status['stepid'] = stepid + Put(status) + self.msg(msg) + + def call(self): + status = _get_status('creation') + if status.get('finished'): + self.redirect('process already completed') + config = self.config + # execute cubicweb's post script + #mhandler.exec_event_script('post%s' % event) + # execute cubes'post script if any + paths = [p for p in config.cubes_path() + [config.apphome] + if exists(join(p, 'migration'))] + paths = [abspath(p) for p in (reversed(paths))] + cpath = status.get('cpath') + if cpath is None and status.get('stepid') is None: + init_persistent_schema(self.server_session(), self.schema) + self.end_core_step(u'inserted schema entities', status, 0) + return + if cpath == '' and status.get('stepid') == 0: + fix_entities(self.schema) + self.end_core_step(u'fixed bootstrap groups and users', status, 1) + return + if cpath == '' and status.get('stepid') == 1: + insert_versions(self.server_session(), self.config) + self.end_core_step(u'inserted software versions', status, None) + return + for i, path in enumerate(paths): + if not cpath or cpath == path: + self.info('running %s', path) + stepid = status.get('stepid') + context = status.get('context') + if context is not None: + context = loads(context) + else: + context = {} + stepid = self._migrhandler.exec_event_script( + 'postcreate', path, 'stepable_postcreate', stepid, context) + if stepid is None: # finished for this script + # reset script state + context = stepid = None + # next time, go to the next script + self.msg(u'finished postcreate for %s' % path) + try: + path = paths[i+1] + self.continue_link() + except IndexError: + status['finished'] = True + path = None + self.redirect('process completed') + else: + if context.get('stepidx'): + self.msg(u'created %s entities for step %s of %s' % ( + context['stepidx'], stepid, path)) + else: + self.msg(u'finished postcreate step %s for %s' % ( + stepid, path)) + context = Blob(dumps(context)) + self.continue_link() + status['context'] = context + status['stepid'] = stepid + status['cpath'] = path + break + else: + if not cpath: + # nothing to be done + status['finished'] = True + self.redirect('process completed') + else: + # Note the error: is expected by the laxctl command line tool, + # deal with this if internationalization is introduced + self.msg(u'error: strange creation state, can\'t find %s' + % cpath) + self.w(u'
click here to ' + 'delete all datastore content so process can be ' + 'reinitialized
' % html_escape(self.req.base_url())) + Put(status) + + @property + @cached + def _migrhandler(self): + return self.config.migration_handler(self.schema, interactive=False, + cnx=self.req.cnx, + repo=self.config.repository()) + + def msg(self, msg): + self.w(u'
%s
' % html_escape(msg)) + def redirect(self, msg): + raise Redirect(self.req.build_url('', msg)) + def continue_link(self): + self.w(u'continue
' % html_escape(self.req.url())) + + +class ContentClear(StartupView): + id = 'contentclear' + require_groups = ('managers',) + skip_etypes = ('EGroup', 'EUser') + + def call(self): + # XXX should use unsafe_execute with all hooks deactivated + # XXX step by catching datastore errors? + for eschema in self.schema.entities(): + if eschema.is_final() or eschema in self.skip_etypes: + continue + self.req.execute('DELETE %s X' % eschema) + self.w(u'deleted all %s entities
' % eschema) + status = _get_status('creation', create=False) + if status: + Delete(status) + self.w(u'done
') + self.w(u'click here to start the data ' + 'initialization process
' % self.req.base_url())