Annotation of VSyncer/VSyncer.py, revision 1.1

1.1     ! casties     1: # import stuff
        !             2: from Globals import DTMLFile, MessageDialog, data_dir, Persistent
        !             3: from DateTime import DateTime
        !             4: from AccessControl import getSecurityManager
        !             5: from StringIO import StringIO
        !             6: import string, md5, difflib, time
        !             7: from types import StringType
        !             8: from cgi import escape
        !             9: import logging
        !            10: # import our own things.
        !            11: from Config import *
        !            12: from BaseSyncer import BaseSyncer
        !            13: from SysConfig import *
        !            14: 
        !            15: manage_addVSServerForm = DTMLFile('dtml/VAdd', globals()) 
        !            16: 
        !            17: 
        !            18: def manage_addVSServer(self, id='SourceSyncer', title='', REQUEST=None):
        !            19:     """ adds a server """
        !            20:     if id in self.objectIds():
        !            21:         return MessageDialog(title = 'Unable to add',
        !            22:                              message = '%s already exists)' % (id),
        !            23:                              action = 'manage_main')
        !            24:     user = getSecurityManager().getUser().getUserName()
        !            25:     if user not in managers_list:
        !            26:         return MessageDialog(title ='permission denied!', message='You are not allowed to create this object', action='manage_main')
        !            27:         
        !            28:     if '/'.join(self.getPhysicalPath()) not in allowed_contexts:
        !            29:         if allowed_contexts:
        !            30:             msg = 'Sorry! This object can only be created in : \n <br>'
        !            31:         else:
        !            32:             msg = 'Please update allowed_contexts list in config.py file '
        !            33:             
        !            34:         for path in allowed_contexts:
        !            35:             msg += path + '\n <br>'
        !            36:         #example list
        !            37:         """allowed_contexts = ['', # if you want to instanciate in root
        !            38:                     '/abc/xyz',
        !            39:                     '/abc/def
        !            40:                    ]
        !            41:         """
        !            42:         return MessageDialog(title="unable to add", message=msg, action="manage_main")
        !            43:     self._setObject(id, VSSyncer(id, title))
        !            44:         
        !            45:     if REQUEST is not None:
        !            46:         return MessageDialog(title = 'Added', message = "%s sucessfully added." % (id), action = '%s/manage_edit' % id, )
        !            47: 
        !            48: 
        !            49: 
        !            50: class VSSyncer(BaseSyncer):
        !            51:     meta_type = 'VSSyncer'
        !            52: 
        !            53:     manage_main = manage_edit = DTMLFile('dtml/VEdit', globals())
        !            54:     manage_vsync = DTMLFile('dtml/VSync', globals())
        !            55:     manage_folders = DTMLFile('dtml/VFolder', globals())
        !            56:     manage_diff = DTMLFile('dtml/VDiff', globals())
        !            57:     manage_approval = DTMLFile('dtml/VApproval', globals())
        !            58:     diffable = diffable
        !            59:     
        !            60:     try: manage_edit._setName("manage_edit")
        !            61:     except AttributeError: pass # python 1.5.2
        !            62:     
        !            63:     
        !            64:     def __init__(self, id, title=''):
        !            65:         """initialize the class"""
        !            66:         BaseSyncer.__init__(self, id, title)
        !            67: 
        !            68:     ###################################################
        !            69:     # Code Display 
        !            70:     ##################################################
        !            71: 
        !            72:     def manage_compare(self, folder):
        !            73:         """return allowed object for syncing"""
        !            74:         sync_obj_ids = self.filtered_objects
        !            75:         
        !            76:         try:
        !            77:             source = self.manage_listObjects(folder)
        !            78:             dest = self._get_list(self.dest_server, folder)
        !            79:         except IndexError:
        !            80:             raise 'Server Error', 'There was a problem syncing the servers'
        !            81:         items = self._compare_lists(source, dest)
        !            82:         return filter(lambda obj, sync_obj_ids=sync_obj_ids:obj['id'] in sync_obj_ids, items)
        !            83: 
        !            84:     def dump(self, tag, x, lo, hi, r):
        !            85:         r1=[]
        !            86:         r2=[]
        !            87:         for i in xrange(lo, hi):
        !            88:             r1.append(tag)
        !            89:             r2.append(x[i])
        !            90:         r.append("<tr>\n"
        !            91:                  "<td><pre>\n%s\n</pre></td>\n"
        !            92:                  "<td><pre>\n%s\n</pre></td>\n"
        !            93:                  "</tr>\n"
        !            94:                  % ('\n'.join(r1), escape('\n'.join(r2))))
        !            95: 
        !            96: 
        !            97:     def manage_srcXMLRPC(self, obj_path):
        !            98:         """ Get a src from an object (if allowed) suitable for diffing """
        !            99:         try:
        !           100:             obj = self.restrictedTraverse(obj_path)
        !           101:         except KeyError: return 404
        !           102: 
        !           103:         c = getSecurityManager().checkPermission
        !           104:         if not c('View management screens', obj):
        !           105:             return 403
        !           106: 
        !           107:         return self._encode(obj.document_src())
        !           108: 
        !           109:     def manage_getDiff(self, object):
        !           110:         """get the code diff between the server nad clients"""
        !           111:         source = self._decode(self.manage_srcXMLRPC(object))
        !           112:         dest = self._decode(self._srcXMLRPC(self.dest_server, object))
        !           113:         from_source = self.manage_getSourceCode(source, dest, bg_color='green')
        !           114:         from_dest = self.manage_getSourceCode(dest, source, bg_color='red')
        !           115:         return '<table><tr><td>' + from_source + '</td>' + '<td>' + from_dest + '</td></tr></table>'
        !           116: 
        !           117:     def manage_getSourceCode(self, source, dest, bg_color):
        !           118:         "return the source code"
        !           119:         a=dest.split('\n')
        !           120:         b=source.split('\n')        
        !           121:         cruncher=difflib.SequenceMatcher()
        !           122:         cruncher.set_seqs(a,b)
        !           123: 
        !           124:         r=['<table border=1 width="100%"> ']
        !           125:         for tag, alo, ahi, blo, bhi in cruncher.get_opcodes():
        !           126:             if tag == 'replace':
        !           127:                 (x, xlo, xhi, y, ylo, yhi, r) = (a, alo, ahi, b, blo, bhi, r)
        !           128:                 rx1=[]
        !           129:                 rx2=[]
        !           130:                 for i in xrange(xlo, xhi):
        !           131:                     rx1.append(' ')
        !           132:                     rx2.append(' ')
        !           133:                 r.append("<tr>\n"
        !           134:                          "<td ><pre>\n%s\n</pre></td>\n"
        !           135:                          "<td ><pre>\n%s\n</pre></td>\n"
        !           136:                          "</tr>\n"
        !           137:                          % ( '\n'.join(rx1),
        !           138:                             escape('\n'.join(rx2))))
        !           139:                 
        !           140:                 ry1=[]
        !           141:                 ry2=[]
        !           142:                 for i in xrange(ylo, yhi):
        !           143:                     ry1.append('+')
        !           144:                     ry2.append(y[i])
        !           145: 
        !           146: 
        !           147:                 r.append("<tr>\n"
        !           148:                          "<td bgcolor=%s style='color:white;'><pre>\n%s\n</pre></td>\n"
        !           149:                          "<td bgcolor=%s style='color:white;'><pre>\n%s\n</pre></td>\n"
        !           150:                          "</tr>\n"
        !           151:                          % (bg_color, '\n'.join(ry1), bg_color, escape('\n'.join(ry2))))
        !           152: 
        !           153:             elif tag == 'delete':
        !           154:                 (tag, x, lo, hi, r) = ('-', a, alo, ahi, r) 
        !           155:                 r1=[]
        !           156:                 r2=[]
        !           157: 
        !           158:                 for i in xrange(lo, hi):
        !           159:                     r1.append(' ')
        !           160:                     r2.append(' ')
        !           161:                 r.append("<tr>\n"
        !           162:                  "<td ><pre>\n%s\n</pre></td>\n"
        !           163:                  "<td ><pre>\n%s\n</pre></td>\n"
        !           164:                  "</tr>\n"
        !           165:                  % ('\n'.join(r1), escape('\n'.join(r2))))
        !           166:                 
        !           167:             elif tag == 'insert':
        !           168:                 (tag, x, lo, hi, r) = ('+', b, blo, bhi, r) 
        !           169:                 r1=[]
        !           170:                 r2=[]
        !           171:                 for i in xrange(lo, hi):
        !           172:                     r1.append(tag)
        !           173:                     r2.append(x[i])
        !           174:                 r.append("<tr>\n"
        !           175:                  "<td bgcolor=%s style='color:white;'><pre>\n%s\n</pre></td>\n"
        !           176:                  "<td bgcolor=%s style='color:white;'><pre>\n%s\n</pre></td>\n"
        !           177:                  "</tr>\n"
        !           178:                  % (bg_color, '\n'.join(r1), bg_color, escape('\n'.join(r2))))
        !           179:                 
        !           180: 
        !           181:             elif tag == 'equal':
        !           182:                 self.dump(' ', a, alo, ahi, r)
        !           183:             else:
        !           184:                 raise ValueError, 'unknown tag ' + `tag`
        !           185: 
        !           186:         r.append('</table>')
        !           187:  
        !           188:         return '\n'.join(r)
        !           189: 
        !           190:     ##########################################################
        !           191: 
        !           192:     def status_colour(self, status):
        !           193:         ''' gives a list of status colours for pretty html '''
        !           194:         return colours.get(status, 'white')
        !           195:     
        !           196:     def getFilterObjects(self):
        !           197:         """ do we filter objects? """
        !           198:         return getattr(self, 'filterObjects', 1)   
        !           199:     
        !           200:     def manage_getAvailableObjects(self):
        !           201:         x= [[obj.getId(),obj.title_or_id()] for obj in self.aq_parent.objectValues() if obj.meta_type in syncable]
        !           202:         return x
        !           203:      
        !           204:     #TODO: we will delete this if it is not required 
        !           205:     def manage_getSyncableObjs(self):
        !           206:         "return all syncable "
        !           207:         if not self.filtered_objects: return ["Sorry! There are no syncable items found for this context"]
        !           208:         return [item + '\n'  for item in self.filtered_objects]
        !           209: 
        !           210:     def manage_listObjects(self, folder):
        !           211:         ''' Gets a list of the objects '''
        !           212:         obs = {}
        !           213:         
        !           214:         try:
        !           215:             folder_obj = self.restrictedTraverse(string.split(folder, '/'))
        !           216:         except:
        !           217:             return {}#because this folder is not found in on of the servers
        !           218:         
        !           219:         # go find the folder, then iterate through the subject
        !           220:         for ob in folder_obj.objectValues():
        !           221:             if ob.meta_type in syncable:
        !           222:                 # we dont to sync ZSyncers, that way leads much confusion
        !           223:                 # so we'll just sync objects we know work
        !           224:                 # avoid broken objects
        !           225:                 # allow people to turn this feature on and off
        !           226:                 if self.getFilterObjects() and not self._isSyncable(ob.meta_type): continue
        !           227:                 if ob.meta_type[:14] == 'Broken Because': continue
        !           228: 
        !           229:                 o = {}
        !           230:                 o['id'] = ob.getId()
        !           231:                 o['path'] = ob.getPhysicalPath()            
        !           232:             
        !           233:                 # this should always be a string right?
        !           234:                 o['meta_type'] = ob.meta_type
        !           235: 
        !           236:                 # CMF fix, where apparently ob.icon is not always a string
        !           237:                 o['icon'] = ob.icon
        !           238:                 if not isinstance(o['icon'], StringType): o['icon'] = ob.icon()
        !           239:            
        !           240:                 o['is_folder'] = getattr(ob, 'isPrincipiaFolderish', 0)
        !           241:                 o['last_modified_time'] = str(ob.bobobase_modification_time().toZone('GMT'))
        !           242:                 o['src_digest'] = self.manage_getSrcDigest(ob.getPhysicalPath())
        !           243:                 # add this to the list of objects
        !           244:                 obs[o['id']] = o
        !           245:         return obs
        !           246: 
        !           247:     def manage_updateXMLRPC(self, object=None, msgs=None, REQUEST=None ):
        !           248:         "updates the object using xml rpc"
        !           249:         if not object :
        !           250:             return MessageDialog(title='Please select', message='you have not selected any objects to sync', action='manage_vsync')
        !           251:         if msgs is None: msgs = []
        !           252: 
        !           253:         if type(object) == StringType: object = [object,]
        !           254:         
        !           255:         for ob in object:
        !           256:             if ob not in allowed_objs_sync: 
        !           257:                 msgs.append(403)    
        !           258:                 continue
        !           259:             try:
        !           260:                 msgs.append('Object <b>%s</b> to <b>%s</b>' % (ob, self.dest_server))
        !           261:                 msgs.append(self._editXMLRPC(ob, self.dest_server))
        !           262:             except:
        !           263:                 msgs.append('<font color=red>object %s not found in source server</font>' % (ob))
        !           264:         return self._msg(msgs, REQUEST)
        !           265: 
        !           266:     def manage_editXMLRPC(self, data, obj_path, obj_id):
        !           267:         "edit the object here"
        !           268:     
        !           269:         if type(obj_path) == type('string'): obj_path = string.split(obj_path, '/')
        !           270: 
        !           271:         try: parent = self.restrictedTraverse(obj_path[:-1])
        !           272:         except KeyError: return 404
        !           273: 
        !           274:      
        !           275:         obj = getattr(parent, obj_id, None)
        !           276:         if obj is None:
        !           277:             self.manage_addXMLRPC(data, obj_path)
        !           278:         else:
        !           279:             data = self._decode(data)
        !           280:             obj = getattr(parent, obj_id)
        !           281:             self.manage_takeBackup(obj)
        !           282:             if obj.meta_type in diffable:
        !           283:                 obj.manage_edit(data, obj.title)
        !           284:             else:
        !           285:                 obj.manage_upload(data)
        !           286: 
        !           287:         return 200
        !           288:         # we have updated successfully:)
        !           289:        
        !           290:     def manage_getSrcDigest(self, object):
        !           291:         """returns the digest of the object source"""
        !           292:         try:
        !           293:             obj = self.restrictedTraverse(object)
        !           294:         except:
        !           295:             return 404 # what to do object not foud :(
        !           296: 
        !           297:         if obj.meta_type in diffable:
        !           298:             src = obj.document_src()
        !           299:         else:
        !           300:             data = obj.data
        !           301:             src = ''
        !           302:             if type(data) == type(''):
        !           303:                 src = data
        !           304:             else:# more tricky. We are getting wrapper here. np :)
        !           305:                 while data is not None:
        !           306:                     src += data.data
        !           307:                     data=data.next
        !           308:             #return self._encode(src)
        !           309:         return self._encode(md5.new(src).digest())
        !           310: 
        !           311:     ###############################
        !           312:     # internal only
        !           313:     # protected by having _ as the first character
        !           314: 
        !           315:     def _isSyncable(self, m):
        !           316:        if m in self.syncable:
        !           317:             return 1
        !           318:        
        !           319:     def _compare_lists(self, s_dict, d_dict):
        !           320:         """compare the lists from 2 zopes"""
        !           321:         _l = []
        !           322:         d_keys = d_dict.keys()
        !           323:         s_keys = s_dict.keys()
        !           324: 
        !           325: 
        !           326:         for item in s_dict.keys():
        !           327:             if s_dict[item]['id'] not in d_keys: 
        !           328:                 s_dict[item]['status'] = 'missing'
        !           329:                 _l.append(s_dict[item])
        !           330:             # ok its on the dest, We cont depend on time stamp because bothe servers are in different time zone.
        !           331:             # so we will check whether the sourse of the s_server and d_server same or not 
        !           332:             elif self._decode(s_dict[item]['src_digest']) != self._decode(d_dict[item]['src_digest']) :
        !           333:                 s_dict[item]['status'] = 'out of date'
        !           334:                 _l.append(s_dict[item])
        !           335:             # not sure what else to check
        !           336:             else: 
        !           337:                 s_dict[item]['status'] = 'ok'
        !           338:                 _l.append(s_dict[item])
        !           339: 
        !           340:         # ok check its on the destination, but not on the original
        !           341:         for item in d_dict.keys():
        !           342:             if d_dict[item]['id'] not in s_keys: 
        !           343:                 d_dict[item]['status'] = 'extra'
        !           344:                 _l.append(d_dict[item])
        !           345:         return _l
        !           346: 
        !           347:     def _srcXMLRPC(self, server, object=None):
        !           348:         # call the src method
        !           349:         serverconn = self._serverConn(self._check_http(server))
        !           350:         return serverconn.manage_srcXMLRPC(object)
        !           351: 
        !           352:     def _get_list(self, server, folder):
        !           353:         ''' actually get the list '''
        !           354:         serverconn = self._serverConn(self._check_http(server))
        !           355:         return serverconn.manage_listObjects(folder)
        !           356: 
        !           357:     def _exportXMLRPC(self, object=None, dest_url=None, add_in=1):
        !           358:         """exports an object"""
        !           359:         # go get the object
        !           360:         obj = self.restrictedTraverse(object)
        !           361:         data = StringIO()
        !           362:         obj._p_jar.exportFile(obj._p_oid, data)
        !           363: 
        !           364:         # do xml-rpc
        !           365:         serverconn = self._serverConn(self._check_http(dest_url))
        !           366:         try: result = serverconn.manage_addXMLRPC(self._encode(data.getvalue()), obj.getPhysicalPath(), add_in)
        !           367:         except: return 500
        !           368: 
        !           369:         # return result
        !           370:         return result
        !           371: 
        !           372:     def _editXMLRPC(self, object=None, dest_url=None, add_in=1):
        !           373:         "edit the object"
        !           374:         logging.debug("_editXMLRPC object=%s dest_url=%s"%(object,dest_url))
        !           375:         obj = self.restrictedTraverse(object)
        !           376:         if obj.meta_type in diffable:
        !           377:             obj_data = obj.document_src()
        !           378:         else:
        !           379:             obj_data = obj.data
        !           380:         obj_id = obj.getId()
        !           381:         
        !           382:         # do xml-rpc
        !           383:         serverconn = self._serverConn(self._check_http(dest_url))
        !           384:         try: result = serverconn.manage_editXMLRPC(self._encode(obj_data), obj.getPhysicalPath(), obj_id)
        !           385:         except:
        !           386:             try:self._exportXMLRPC(object, dest_url)
        !           387:             except:return 500
        !           388:         return 200

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>