File:  [Repository] / VSyncer / BaseSyncer.py
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Fri Jan 4 15:34:43 2008 UTC (16 years, 4 months ago) by casties
Branches: MAIN
CVS tags: HEAD
more unicode fixes

from OFS import SimpleItem
from Globals import Persistent, data_dir, MessageDialog
from AccessControl import getSecurityManager, Role
import Acquisition, base64, time
from Config import *
from SysConfig import *
from DocumentTemplate.DT_Var import url_quote_plus
from StringIO import StringIO
import string, os
from os.path import exists
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

# do xml
import xmlrpclibBasicAuth

def unicodify(s):
    """decode str (utf-8 or latin-1 representation) into unicode object"""
    if not s:
        return u""
    if isinstance(s, str):
        try:
            return s.decode('utf-8')
        except:
            return s.decode('latin-1')
    else:
        return s

def utf8ify(s):
    """encode unicode object or string into byte string in utf-8 representation.
       assumes string objects to be utf-8"""
    if not s:
        return ""
    if isinstance(s, str):
        return s
    else:
        return s.encode('utf-8')


class BaseSyncer(SimpleItem.Item, Persistent, Acquisition.Implicit, Role.RoleManager):
    """This class contains Basic methods, even These methods will be common if we implements Module Syncer"""
    manage_options = (
        {'label': 'Sync', 'action': 'manage_vsync' },
        {'label': 'Edit Server', 'action': 'manage_edit' },
        {'label': 'View Log', 'action': 'manage_viewlog' },
    )
    
    __ac_permissions__= (
        ('View management screens', (
        'manage_tabs','manage_main','manage_edit','is_diffable', 'manage_approvedAction', 'manage_addXMLRPC',
        'manage_listObjects', 'manage_exportXMLRPC', 'manage_deleteXMLRPC', 'manage_diffObject',
        'manage_compare', 'manage_srcXMLRPC', 'status_colour', 'manage_folders', 'manage_vsync') ),
        ('Change permissions', ('manage_access',) ),
    )

    targetServer=dest_syncer
    allowed_objs_sync = allowed_objs_sync
    manage_viewlog = PageTemplateFile('zpt/VViewLog', globals())
    

    def __init__(self, id, title=''):
        """initialize a new instance of Server"""
        self.id = id
        self.title = title
        self.source_server = [ None, ] # source is this Syncer
        self.dest_server = ''
        self.log = 0
        self.approval = 1
        self.syncable = syncable
        self.filtered_objects = []
        self.logfile = os.path.join(data_dir, 'VSourceSyncer.log')

    def manage_editServer(self, title='', dest=None, log=0, approval=0, logfile='', REQUEST=None, syncable=syncable, filterObjects=0, allowed_objs=[] ):
        "edit server"
        auth_user = getSecurityManager().getUser().getId()
        if auth_user not in managers_list:
            return MessageDialog(title='Addess Denied', message='You are not allowed to edit SourceSyncer', action='manage_vsync')
        
        self.title = title
        self.log = log
        self.logfile = logfile
        self.approval = approval
        self.syncable = syncable
        self.dest_server = string.strip(dest)
        self.filterObjects = filterObjects
        self.filtered_objects = allowed_objs
        if REQUEST is not None:
            return MessageDialog(title = 'Edited', message = "Properties changed.", action = 'manage_edit')
            
    #################### for displaying the log info ##########################
    def manage_getLog(self, filter=None):
        """Return the log file details as a list """
        log_list=[]
        if not exists(self.logfile):
                return 'file not found. Please enable log option from edit server tab'

        # Cool. File found. Open. if we have permission.
        try:
            fp = open(self.logfile, 'r')
            data_list = fp.readlines()
            fp.close()
        except :
            return "problem with opening/reading file" 
        dummy_list = []    
        for line in data_list:
            if string.find(line, 'Syncing finished') > -1:
                dummy_list.reverse()
                log_list = log_list + dummy_list
                dummy_list = []
                continue
            elif string.find(line, 'Syncing started') > -1:
                dummy_list.append({'head':1,'text':line[:25]})
            elif (string.find(line, 'Syncer:') > -1 or
                    string.find(line, 'Approver:') > -1):
                dummy_list.append({'spec':1,'text':line[25:]})
            else:
                dummy_list.append({'normal':1,'text':line[25:]})

        log_list.reverse()
        return log_list
    ############################################################    
    def manage_approvedAction(self, REQUEST=None, action='', object=None, syncer=None, approver=None, comments=None):
        """ If this action is to be approved, throw that data in into the message list """
        if not syncer : syncer = getSecurityManager().getUser().getId()
        msgs = ['Syncer: %s' % syncer,]
        msgs.append('Approver: %s' % approver)
        
        # string out any newlines in comments
        msgs.append('Comments: %s' % string.replace(comments, '\n', ''))
        # call the relevant thing
        if action == 'manage_updateXMLRPC':
            return self.manage_updateXMLRPC(object, msgs=msgs, REQUEST=REQUEST)
        else:
            return self._error(msg='Unknown action')


    def manage_addXMLRPC(self, data, obj_path, add_in=1):
        """ Adds an object into the server """
        # make sure we always get a string or a list
        if type(obj_path) == type('string'): obj_path = string.split(obj_path, '/')

        # object lets try finding the parent
        try: parent = self.restrictedTraverse(obj_path[:-1])
        except KeyError: return 404

        # lets check they are allowed to do this
        c = getSecurityManager().checkPermission
        allowed = 1
        for perm in ['Delete objects', 'Import/Export objects']:
            if not c(perm, parent): allowed = 0
        if not allowed: return 403

        # if there is one there already, delete it
        if obj_path[-1] in parent.objectIds():
            parent.manage_delObjects([obj_path[-1],])
        else:
            if not add_in: # ok so if we are deleting
                return 404

        # lets do it
        if add_in:
            # fake a file using StringIO
            file = StringIO()
            file.write(self._decode(data))
            file.seek(0)

            # now import
            new = parent._p_jar.importFile(file)
            parent._setObject(new.getId(), new)

        # wow!..
        return 200

    def manage_takeBackup(self, obj=None):
        #take a back of the syncable file in the backup_sync folder if not exists just create one.
        if obj is None : return None
        obj_id = obj.getId()
        parent = obj.aq_parent
        parent_contents = parent.objectIds()
        bak_id = 'backup_sync' #  backup folder name.
        if bak_id not in parent_contents:parent.manage_addFolder(id=bak_id)
        bak_folder = getattr(parent,bak_id)
        if obj_id in bak_folder.objectIds(): bak_folder.manage_delObjects([obj_id])
        bak_folder.manage_pasteObjects(parent.manage_copyObjects([obj_id]))

    #############################################################################
    #Private Methods
    #############################################################################
    
    def _log(self, msgs):
        # log to ZSyncer
        # this will become more configurable
        file = open(self.logfile, 'a')

        # write out the log
        file.write('%s\tSyncing started\n' % self._get_time())
        for m in msgs: file.write('%s\t%s\n' % (self._get_time(), m))
        file.write('%s\tSyncing finished\n' % self._get_time())

        file.close()

    def _get_time(self):
        # get time for logging
        # could be done using DateTime, but i think I want to fiddle this
        return time.asctime(time.localtime(time.time()))    

    def _encode(self, s):
        # do any other encoding here
        # eg twofish, zlib etc
        # this will do me for now
        return base64.encodestring(utf8ify(s))
    
    def _decode(self, s):
        # do any other encoding here
        return base64.decodestring(s)

    def _serverUser(self, url):
        # extract user from server url, returns server, user, pw
        if url.find('@'):
            # user:password in URL
            (us,ur) = url.split('@')
            (prot,upw) = us.split('//')
            (user,pw) = upw.split(':')
            url = prot + '//' + ur
        else: 
            u = getSecurityManager().getUser()
            user = u.getId()
            pw = u._getPassword()
        return (url,user,pw)

    def _serverConn(self, url):
        # connect using xmlrpc lib
        (server,user,pw) = self._serverUser(url)
        return xmlrpclibBasicAuth.Server(server, user, pw)

    def _check_http(self, v):
        # so people can get away with leaving http:// off :)
        if v[:7] != 'http://' and v[:8] != 'https://': v = 'http://%s' % v
        if v[:5] != 'http:' and v[:6] != 'https:': v = 'http:%s' % v
        return v

    def _msg(self, msgs, REQUEST=None):
        # what to do with these messages
        ms = []
        for m in msgs:
            # hack-o-rama, if i have a number, its a status code, so lets look it up and get a nicer message
            if type(m) == type(1): ms.append(' - %s' % (error_messages.get(str(m), '<font color=red>Unknown error occured</font>')))
            elif m[:6] == 'Object': ms.append('<li><font color=blue size=3>%s</font>' % m)
            else: ms.append(m)

        if self.log or self.approval: self._log(ms)
        if REQUEST is not None:
            return REQUEST.RESPONSE.redirect(
                    'manage_vsync?folder=%s&msg=%s' %
                    (
                        self.REQUEST.get('folder', '/'),
                        url_quote_plus(string.join(ms, '<br>'))
                    )    
                )

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