"""special management views to manage repository content (initialization andrestoration).:organization: Logilab:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"fromos.pathimportexists,join,abspathfrompickleimportloads,dumpsfromlogilab.common.decoratorsimportcachedfromlogilab.mtconverterimportxml_escapefromcubicweb.selectorsimportnone_rset,match_user_groupsfromcubicweb.common.viewimportStartupViewfromcubicweb.webimportRedirectfromcubicweb.goa.dbinitimportfix_entities,init_persistent_schema,insert_versionsfromgoogle.appengine.api.datastoreimportEntity,Key,Get,Put,Deletefromgoogle.appengine.api.datastore_typesimportBlobfromgoogle.appengine.api.datastore_errorsimportEntityNotFoundErrordef_get_status(name,create=True):key=Key.from_path('EApplicationStatus',name)try:status=Get(key)exceptEntityNotFoundError:ifcreate:status=Entity('EApplicationStatus',name=name)else:status=NonereturnstatusclassAuthInfo(StartupView):"""special management view to get cookie values to give to laxctl commands which are doing datastore administration requests """id='authinfo'__select__=none_rset()&match_user_groups('managers')defcall(self):cookie=self.req.get_cookie()values=[]ifself.config['use-google-auth']:forparamin('ACSID','dev_appserver_login'):morsel=cookie.get(param)ifmorsel:values.append('%s=%s'%(param,morsel.value))breakvalues.append('__session=%s'%cookie['__session'].value)self.w(u"<p>pass this flag to the client: --cookie='%s'</p>"%xml_escape('; '.join(values)))classContentInit(StartupView):"""special management view to initialize content of a repository, step by step to avoid depassing quotas """id='contentinit'__select__=none_rset()&match_user_groups('managers')defserver_session(self):ssession=self.config.repo_session(self.req.cnx.sessionid)ssession.set_pool()returnssessiondefend_core_step(self,msg,status,stepid):status['cpath']=''status['stepid']=stepidPut(status)self.msg(msg)defcall(self):status=_get_status('creation')ifstatus.get('finished'):self.redirect('process already completed')config=self.config# execute cubicweb's post<event> script#mhandler.exec_event_script('post%s' % event)# execute cubes'post<event> script if anypaths=[pforpinconfig.cubes_path()+[config.apphome]ifexists(join(p,'migration'))]paths=[abspath(p)forpin(reversed(paths))]cpath=status.get('cpath')ifcpathisNoneandstatus.get('stepid')isNone:init_persistent_schema(self.server_session(),self.schema)self.end_core_step(u'inserted schema entities',status,0)returnifcpath==''andstatus.get('stepid')==0:fix_entities(self.schema)self.end_core_step(u'fixed bootstrap groups and users',status,1)returnifcpath==''andstatus.get('stepid')==1:insert_versions(self.server_session(),self.config)self.end_core_step(u'inserted software versions',status,None)returnfori,pathinenumerate(paths):ifnotcpathorcpath==path:self.info('running %s',path)stepid=status.get('stepid')context=status.get('context')ifcontextisnotNone:context=loads(context)else:context={}stepid=self._migrhandler.exec_event_script('postcreate',path,'stepable_postcreate',stepid,context)ifstepidisNone:# finished for this script# reset script statecontext=stepid=None# next time, go to the next scriptself.msg(u'finished postcreate for %s'%path)try:path=paths[i+1]self.continue_link()exceptIndexError:status['finished']=Truepath=Noneself.redirect('process completed')else:ifcontext.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']=contextstatus['stepid']=stepidstatus['cpath']=pathbreakelse:ifnotcpath:# nothing to be donestatus['finished']=Trueself.redirect('process completed')else:# Note the error: is expected by the laxctl command line tool,# deal with this if internationalization is introducedself.msg(u'error: strange creation state, can\'t find %s'%cpath)self.w(u'<div>click <a href="%s?vid=contentclear">here</a> to ''<b>delete all datastore content</b> so process can be ''reinitialized</div>'%xml_escape(self.req.base_url()))Put(status)@property@cacheddef_migrhandler(self):returnself.config.migration_handler(self.schema,interactive=False,cnx=self.req.cnx,repo=self.config.repository())defmsg(self,msg):self.w(u'<div class="message">%s</div>'%xml_escape(msg))defredirect(self,msg):raiseRedirect(self.req.build_url('',msg))defcontinue_link(self):self.w(u'<a href="%s">continue</a><br/>'%xml_escape(self.req.url()))classContentClear(StartupView):id='contentclear'__select__=none_rset()&match_user_groups('managers')skip_etypes=('CWGroup','CWUser')defcall(self):# XXX should use unsafe_execute with all hooks deactivated# XXX step by catching datastore errors?foreschemainself.schema.entities():ifeschema.is_final()oreschemainself.skip_etypes:continueself.req.execute('DELETE %s X'%eschema)self.w(u'deleted all %s entities<br/>'%eschema)status=_get_status('creation',create=False)ifstatus:Delete(status)self.w(u'done<br/>')self.w(u'click <a href="%s?vid=contentinit">here</a> to start the data ''initialization process<br/>'%self.req.base_url())