Changeset 591

Show
Ignore:
Timestamp:
2007-07-30 11:35:06 (3 years ago)
Author:
alfonsoml
Message:

New Python connector from #575

Location:
FCKeditor/trunk
Files:
9 added
4 modified

Legend:

Unmodified
Added
Removed
  • FCKeditor/trunk/editor/filemanager/connectors/py/connector.py

    r413 r591  
    2121== END LICENSE == 
    2222 
    23 Connector for Python. 
     23Connector for Python (CGI and WSGI). 
    2424 
    25 Tested With: 
    26 Standard: 
    27         Python 2.3.3 
    28 Zope: 
    29         Zope Version: (Zope 2.8.1-final, python 2.3.5, linux2) 
    30         Python Version: 2.3.5 (#4, Mar 10 2005, 01:40:25) 
    31                 [GCC 3.3.3 20040412 (Red Hat Linux 3.3.3-7)] 
    32         System Platform: linux2 
    33 """ 
     25See config.py for configuration settings 
    3426 
    3527""" 
    36 Author Notes (04 December 2005): 
    37 This module has gone through quite a few phases of change.  Obviously, 
    38 I am only supporting that part of the code that I use.  Initially 
    39 I had the upload directory as a part of zope (ie. uploading files 
    40 directly into Zope), before realising that there were too many 
    41 complex intricacies within Zope to deal with.  Zope is one ugly piece 
    42 of code.  So I decided to complement Zope by an Apache server (which 
    43 I had running anyway, and doing nothing).  So I mapped all uploads 
    44 from an arbitrary server directory to an arbitrary web directory. 
    45 All the FCKeditor uploading occurred this way, and I didn't have to 
    46 stuff around with fiddling with Zope objects and the like (which are 
    47 terribly complex and something you don't want to do - trust me). 
     28import os 
    4829 
    49 Maybe a Zope expert can touch up the Zope components.  In the end, 
    50 I had FCKeditor loaded in Zope (probably a bad idea as well), and 
    51 I replaced the connector.py with an alias to a server module. 
    52 Right now, all Zope components will simple remain as is because 
    53 I've had enough of Zope. 
     30from fckutil import * 
     31from fckcommands import *       # default command's implementation 
     32from fckoutput import *         # base http, xml and html output mixins 
     33from fckconnector import FCKeditorConnectorBase # import base connector 
     34import config as Config 
    5435 
    55 See notes right at the end of this file for how I aliased out of Zope. 
     36class FCKeditorConnector(       FCKeditorConnectorBase, 
     37                                                        GetFoldersCommandMixin, 
     38                                                        GetFoldersAndFilesCommandMixin, 
     39                                                        CreateFolderCommandMixin, 
     40                                                        UploadFileCommandMixin,  
     41                                                        BaseHttpMixin, BaseXmlMixin, BaseHtmlMixin  ): 
     42        "The Standard connector class." 
     43        def doResponse(self): 
     44                "Main function. Process the request, set headers and return a string as response." 
     45                s = "" 
     46                # Check if this connector is disabled 
     47                if not(Config.Enabled): 
     48                        return self.sendError(1, "This connector is disabled.  Please check the connector configurations in \"editor/filemanager/connectors/py/config.py\" and try again.") 
     49                # Make sure we have valid inputs 
     50                for key in ("Command","Type","CurrentFolder"): 
     51                        if not self.request.has_key (key): 
     52                                return 
     53                # Get command, resource type and current folder 
     54                command = self.request.get("Command") 
     55                resourceType = self.request.get("Type") 
     56                currentFolder = getCurrentFolder(self.request.get("CurrentFolder")) 
     57                # Check for invalid paths 
     58                if currentFolder is None: 
     59                        return self.sendError(102, "") 
     60                 
     61                # Check if it is an allowed command 
     62                if ( not command in Config.ConfigAllowedCommands ): 
     63                        return self.sendError( 1, 'The %s command isn\'t allowed' % command )  
     64                 
     65                if ( not resourceType in Config.ConfigAllowedTypes  ): 
     66                        return self.sendError( 1, 'Invalid type specified' )  
    5667 
    57 Anyway, most of you probably wont use Zope, so things are pretty 
    58 simple in that regard. 
     68                # Setup paths 
     69                if command == "QuickUpload": 
     70                        self.userFilesFolder = Config.QuickUploadAbsolutePath[resourceType]  
     71                        self.webUserFilesFolder =  Config.QuickUploadPath[resourceType] 
     72                else: 
     73                        self.userFilesFolder = Config.FileTypesAbsolutePath[resourceType] 
     74                        self.webUserFilesFolder = Config.FileTypesPath[resourceType]     
     75                 
     76                if not self.userFilesFolder: # no absolute path given (dangerous...) 
     77                        self.userFilesFolder = mapServerPath(self.environ,  
     78                                                                        self.webUserFilesFolder) 
     79                # Ensure that the directory exists. 
     80                if not os.path.exists(self.userFilesFolder): 
     81                        try: 
     82                                self.createServerFoldercreateServerFolder( self.userFilesFolder )  
     83                        except: 
     84                                return self.sendError(1, "This connector couldn\'t access to local user\'s files directories.  Please check the UserFilesAbsolutePath in \"editor/filemanager/connectors/py/config.py\" and try again. ") 
    5985 
    60 Typically, SERVER_DIR is the root of WEB_DIR (not necessarily). 
    61 Most definitely, SERVER_USERFILES_DIR points to WEB_USERFILES_DIR. 
    62 """ 
    63  
    64 import cgi 
    65 import re 
    66 import os 
    67 import string 
    68  
    69 """ 
    70 escape 
    71  
    72 Converts the special characters '<', '>', and '&'. 
    73  
    74 RFC 1866 specifies that these characters be represented 
    75 in HTML as &lt; &gt; and &amp; respectively. In Python 
    76 1.5 we use the new string.replace() function for speed. 
    77 """ 
    78 def escape(text, replace=string.replace): 
    79     text = replace(text, '&', '&amp;') # must be done 1st 
    80     text = replace(text, '<', '&lt;') 
    81     text = replace(text, '>', '&gt;') 
    82     text = replace(text, '"', '&quot;') 
    83     return text 
    84  
    85 """ 
    86 getFCKeditorConnector 
    87  
    88 Creates a new instance of an FCKeditorConnector, and runs it 
    89 """ 
    90 def getFCKeditorConnector(context=None): 
    91         # Called from Zope.  Passes the context through 
    92         connector = FCKeditorConnector(context=context) 
    93         return connector.run() 
    94  
    95  
    96 """ 
    97 FCKeditorRequest 
    98  
    99 A wrapper around the request object 
    100 Can handle normal CGI request, or a Zope request 
    101 Extend as required 
    102 """ 
    103 class FCKeditorRequest(object): 
    104         def __init__(self, context=None): 
    105                 if (context is not None): 
    106                         r = context.REQUEST 
    107                 else: 
    108                         r = cgi.FieldStorage() 
    109                 self.context = context 
    110                 self.request = r 
    111  
    112         def isZope(self): 
    113                 if (self.context is not None): 
    114                         return True 
    115                 return False 
    116  
    117         def has_key(self, key): 
    118                 return self.request.has_key(key) 
    119  
    120         def get(self, key, default=None): 
    121                 value = None 
    122                 if (self.isZope()): 
    123                         value = self.request.get(key, default) 
    124                 else: 
    125                         if key in self.request.keys(): 
    126                                 value = self.request[key].value 
    127                         else: 
    128                                 value = default 
    129                 return value 
    130  
    131 """ 
    132 FCKeditorConnector 
    133  
    134 The connector class 
    135 """ 
    136 class FCKeditorConnector(object): 
    137         # Configuration for FCKEditor 
    138         # can point to another server here, if linked correctly 
    139         #WEB_HOST = "http://127.0.0.1/" 
    140         WEB_HOST = "" 
    141         SERVER_DIR = "/var/www/html/" 
    142  
    143         WEB_USERFILES_FOLDER = WEB_HOST + "upload/" 
    144         SERVER_USERFILES_FOLDER = SERVER_DIR + "upload/" 
    145  
    146         # Allow access (Zope) 
    147         __allow_access_to_unprotected_subobjects__ = 1 
    148         # Class Attributes 
    149         parentFolderRe = re.compile("[\/][^\/]+[\/]?$") 
    150  
    151         """ 
    152         Constructor 
    153         """ 
    154         def __init__(self, context=None): 
    155                 # The given root path will NOT be shown to the user 
    156                 # Only the userFilesPath will be shown 
    157  
    158                 # Instance Attributes 
    159                 self.context = context 
    160                 self.request = FCKeditorRequest(context=context) 
    161                 self.rootPath = self.SERVER_DIR 
    162                 self.userFilesFolder = self.SERVER_USERFILES_FOLDER 
    163                 self.webUserFilesFolder = self.WEB_USERFILES_FOLDER 
    164  
    165                 # Enables / Disables the connector 
    166                 self.enabled = False # Set to True to enable this connector 
    167  
    168                 # These are instance variables 
    169                 self.zopeRootContext = None 
    170                 self.zopeUploadContext = None 
    171  
    172                 # Copied from php module =) 
    173                 self.allowedExtensions = { 
    174                                 "File": None, 
    175                                 "Image": None, 
    176                                 "Flash": None, 
    177                                 "Media": None 
    178                                 } 
    179                 self.deniedExtensions = { 
    180                                 "File": [ "html","htm","php","php2","php3","php4","php5","phtml","pwml","inc","asp","aspx","ascx","jsp","cfm","cfc","pl","bat","exe","com","dll","vbs","js","reg","cgi","htaccess","asis","sh","shtml","shtm","phtm" ], 
    181                                 "Image": [ "html","htm","php","php2","php3","php4","php5","phtml","pwml","inc","asp","aspx","ascx","jsp","cfm","cfc","pl","bat","exe","com","dll","vbs","js","reg","cgi","htaccess","asis","sh","shtml","shtm","phtm" ], 
    182                                 "Flash": [ "html","htm","php","php2","php3","php4","php5","phtml","pwml","inc","asp","aspx","ascx","jsp","cfm","cfc","pl","bat","exe","com","dll","vbs","js","reg","cgi","htaccess","asis","sh","shtml","shtm","phtm" ], 
    183                                 "Media": [ "html","htm","php","php2","php3","php4","php5","phtml","pwml","inc","asp","aspx","ascx","jsp","cfm","cfc","pl","bat","exe","com","dll","vbs","js","reg","cgi","htaccess","asis","sh","shtml","shtm","phtm" ] 
    184                                 } 
    185  
    186         """ 
    187         Zope specific functions 
    188         """ 
    189         def isZope(self): 
    190                 # The context object is the zope object 
    191                 if (self.context is not None): 
    192                         return True 
    193                 return False 
    194  
    195         def getZopeRootContext(self): 
    196                 if self.zopeRootContext is None: 
    197                         self.zopeRootContext = self.context.getPhysicalRoot() 
    198                 return self.zopeRootContext 
    199  
    200         def getZopeUploadContext(self): 
    201                 if self.zopeUploadContext is None: 
    202                         folderNames = self.userFilesFolder.split("/") 
    203                         c = self.getZopeRootContext() 
    204                         for folderName in folderNames: 
    205                                 if (folderName <> ""): 
    206                                         c = c[folderName] 
    207                         self.zopeUploadContext = c 
    208                 return self.zopeUploadContext 
    209  
    210         """ 
    211         Generic manipulation functions 
    212         """ 
    213         def getUserFilesFolder(self): 
    214                 return self.userFilesFolder 
    215  
    216         def getWebUserFilesFolder(self): 
    217                 return self.webUserFilesFolder 
    218  
    219         def getAllowedExtensions(self, resourceType): 
    220                 return self.allowedExtensions[resourceType] 
    221  
    222         def getDeniedExtensions(self, resourceType): 
    223                 return self.deniedExtensions[resourceType] 
    224  
    225         def removeFromStart(self, string, char): 
    226                 return string.lstrip(char) 
    227  
    228         def removeFromEnd(self, string, char): 
    229                 return string.rstrip(char) 
    230  
    231         def convertToXmlAttribute(self, value): 
    232                 if (value is None): 
    233                         value = "" 
    234                 return escape(value) 
    235  
    236         def convertToPath(self, path): 
    237                 if (path[-1] <> "/"): 
    238                         return path + "/" 
    239                 else: 
    240                         return path 
    241  
    242         def getUrlFromPath(self, resourceType, path): 
    243                 if (resourceType is None) or (resourceType == ''): 
    244                         url = "%s%s" % ( 
    245                                         self.removeFromEnd(self.getUserFilesFolder(), '/'), 
    246                                         path 
    247                                         ) 
    248                 else: 
    249                         url = "%s%s%s" % ( 
    250                                         self.getUserFilesFolder(), 
    251                                         resourceType, 
    252                                         path 
    253                                         ) 
    254                 return url 
    255  
    256         def getWebUrlFromPath(self, resourceType, path): 
    257                 if (resourceType is None) or (resourceType == ''): 
    258                         url = "%s%s" % ( 
    259                                         self.removeFromEnd(self.getWebUserFilesFolder(), '/'), 
    260                                         path 
    261                                         ) 
    262                 else: 
    263                         url = "%s%s%s" % ( 
    264                                         self.getWebUserFilesFolder(), 
    265                                         resourceType, 
    266                                         path 
    267                                         ) 
    268                 return url 
    269  
    270         def removeExtension(self, fileName): 
    271                 index = fileName.rindex(".") 
    272                 newFileName = fileName[0:index] 
    273                 return newFileName 
    274  
    275         def getExtension(self, fileName): 
    276                 index = fileName.rindex(".") + 1 
    277                 fileExtension = fileName[index:] 
    278                 return fileExtension 
    279  
    280         def getParentFolder(self, folderPath): 
    281                 parentFolderPath = self.parentFolderRe.sub('', folderPath) 
    282                 return parentFolderPath 
    283  
    284         """ 
    285         serverMapFolder 
    286  
    287         Purpose: works out the folder map on the server 
    288         """ 
    289         def serverMapFolder(self, resourceType, folderPath): 
    290                 # Get the resource type directory 
    291                 resourceTypeFolder = "%s%s/" % ( 
    292                                 self.getUserFilesFolder(), 
    293                                 resourceType 
    294                                 ) 
    295                 # Ensure that the directory exists 
    296                 self.createServerFolder(resourceTypeFolder) 
    297  
    298                 # Return the resource type directory combined with the 
    299                 # required path 
    300                 return "%s%s" % ( 
    301                                 resourceTypeFolder, 
    302                                 self.removeFromStart(folderPath, '/') 
    303                                 ) 
    304  
    305         """ 
    306         createServerFolder 
    307  
    308         Purpose: physically creates a folder on the server 
    309         """ 
    310         def createServerFolder(self, folderPath): 
    311                 # Check if the parent exists 
    312                 parentFolderPath = self.getParentFolder(folderPath) 
    313                 if not(os.path.exists(parentFolderPath)): 
    314                         errorMsg = self.createServerFolder(parentFolderPath) 
    315                         if errorMsg is not None: 
    316                                 return errorMsg 
    317                 # Check if this exists 
    318                 if not(os.path.exists(folderPath)): 
    319                         os.mkdir(folderPath) 
    320                         os.chmod(folderPath, 0755) 
    321                         errorMsg = None 
    322                 else: 
    323                         if os.path.isdir(folderPath): 
    324                                 errorMsg = None 
    325                         else: 
    326                                 raise "createServerFolder: Non-folder of same name already exists" 
    327                 return errorMsg 
    328  
    329  
    330         """ 
    331         getRootPath 
    332  
    333         Purpose: returns the root path on the server 
    334         """ 
    335         def getRootPath(self): 
    336                 return self.rootPath 
    337  
    338         """ 
    339         setXmlHeaders 
    340  
    341         Purpose: to prepare the headers for the xml to return 
    342         """ 
    343         def setXmlHeaders(self): 
    344                 #now = self.context.BS_get_now() 
    345                 #yesterday = now - 1 
    346                 self.setHeader("Content-Type", "text/xml") 
    347                 #self.setHeader("Expires", yesterday) 
    348                 #self.setHeader("Last-Modified", now) 
    349                 #self.setHeader("Cache-Control", "no-store, no-cache, must-revalidate") 
    350                 self.printHeaders() 
    351                 return 
    352  
    353         def setHeader(self, key, value): 
    354                 if (self.isZope()): 
    355                         self.context.REQUEST.RESPONSE.setHeader(key, value) 
    356                 else: 
    357                         print "%s: %s" % (key, value) 
    358                 return 
    359  
    360         def printHeaders(self): 
    361                 # For non-Zope requests, we need to print an empty line 
    362                 # to denote the end of headers 
    363                 if (not(self.isZope())): 
    364                         print "" 
    365  
    366         """ 
    367         createXmlFooter 
    368  
    369         Purpose: returns the xml header 
    370         """ 
    371         def createXmlHeader(self, command, resourceType, currentFolder): 
    372                 self.setXmlHeaders() 
    373                 s = "" 
    374                 # Create the XML document header 
    375                 s += """<?xml version="1.0" encoding="utf-8" ?>""" 
    376                 # Create the main connector node 
    377                 s += """<Connector command="%s" resourceType="%s">""" % ( 
    378                                 command, 
    379                                 resourceType 
    380                                 ) 
    381                 # Add the current folder node 
    382                 s += """<CurrentFolder path="%s" url="%s" />""" % ( 
    383                                 self.convertToXmlAttribute(currentFolder), 
    384                                 self.convertToXmlAttribute( 
    385                                         self.getWebUrlFromPath( 
    386                                                 resourceType, 
    387                                                 currentFolder 
    388                                                 ) 
    389                                         ), 
    390                                 ) 
    391                 return s 
    392  
    393         """ 
    394         createXmlFooter 
    395  
    396         Purpose: returns the xml footer 
    397         """ 
    398         def createXmlFooter(self): 
    399                 s = """</Connector>""" 
    400                 return s 
    401  
    402         """ 
    403         sendError 
    404  
    405         Purpose: in the event of an error, return an xml based error 
    406         """ 
    407         def sendError(self, number, text): 
    408                 self.setXmlHeaders() 
    409                 s = "" 
    410                 # Create the XML document header 
    411                 s += """<?xml version="1.0" encoding="utf-8" ?>""" 
    412                 s += """<Connector>""" 
    413                 s += """<Error number="%s" text="%s" />""" % (number, text) 
    414                 s += """</Connector>""" 
    415                 return s 
    416  
    417         """ 
    418         getFolders 
    419  
    420         Purpose: command to recieve a list of folders 
    421         """ 
    422         def getFolders(self, resourceType, currentFolder): 
    423                 if (self.isZope()): 
    424                         return self.getZopeFolders(resourceType, currentFolder) 
    425                 else: 
    426                         return self.getNonZopeFolders(resourceType, currentFolder) 
    427  
    428         def getZopeFolders(self, resourceType, currentFolder): 
    429                 # Open the folders node 
    430                 s = "" 
    431                 s += """<Folders>""" 
    432                 zopeFolder = self.findZopeFolder(resourceType, currentFolder) 
    433                 for (name, o) in zopeFolder.objectItems(["Folder"]): 
    434                         s += """<Folder name="%s" />""" % ( 
    435                                         self.convertToXmlAttribute(name) 
    436                                         ) 
    437                 # Close the folders node 
    438                 s += """</Folders>""" 
    439                 return s 
    440  
    441         def getNonZopeFolders(self, resourceType, currentFolder): 
    442                 # Map the virtual path to our local server 
    443                 serverPath = self.serverMapFolder(resourceType, currentFolder) 
    444                 # Open the folders node 
    445                 s = "" 
    446                 s += """<Folders>""" 
    447                 for someObject in os.listdir(serverPath): 
    448                         someObjectPath = os.path.join(serverPath, someObject) 
    449                         if os.path.isdir(someObjectPath): 
    450                                 s += """<Folder name="%s" />""" % ( 
    451                                                 self.convertToXmlAttribute(someObject) 
    452                                                 ) 
    453                 # Close the folders node 
    454                 s += """</Folders>""" 
    455                 return s 
    456  
    457         """ 
    458         getFoldersAndFiles 
    459  
    460         Purpose: command to recieve a list of folders and files 
    461         """ 
    462         def getFoldersAndFiles(self, resourceType, currentFolder): 
    463                 if (self.isZope()): 
    464                         return self.getZopeFoldersAndFiles(resourceType, currentFolder) 
    465                 else: 
    466                         return self.getNonZopeFoldersAndFiles(resourceType, currentFolder) 
    467  
    468         def getNonZopeFoldersAndFiles(self, resourceType, currentFolder): 
    469                 # Map the virtual path to our local server 
    470                 serverPath = self.serverMapFolder(resourceType, currentFolder) 
    471                 # Open the folders / files node 
    472                 folders = """<Folders>""" 
    473                 files = """<Files>""" 
    474                 for someObject in os.listdir(serverPath): 
    475                         someObjectPath = os.path.join(serverPath, someObject) 
    476                         if os.path.isdir(someObjectPath): 
    477                                 folders += """<Folder name="%s" />""" % ( 
    478                                                 self.convertToXmlAttribute(someObject) 
    479                                                 ) 
    480                         elif os.path.isfile(someObjectPath): 
    481                                 size = os.path.getsize(someObjectPath) 
    482                                 files += """<File name="%s" size="%s" />""" % ( 
    483                                                 self.convertToXmlAttribute(someObject), 
    484                                                 os.path.getsize(someObjectPath) 
    485                                                 ) 
    486                 # Close the folders / files node 
    487                 folders += """</Folders>""" 
    488                 files += """</Files>""" 
    489                 # Return it 
    490                 s = folders + files 
    491                 return s 
    492  
    493         def getZopeFoldersAndFiles(self, resourceType, currentFolder): 
    494                 folders = self.getZopeFolders(resourceType, currentFolder) 
    495                 files = self.getZopeFiles(resourceType, currentFolder) 
    496                 s = folders + files 
    497                 return s 
    498  
    499         def getZopeFiles(self, resourceType, currentFolder): 
    500                 # Open the files node 
    501                 s = "" 
    502                 s += """<Files>""" 
    503                 zopeFolder = self.findZopeFolder(resourceType, currentFolder) 
    504                 for (name, o) in zopeFolder.objectItems(["File","Image"]): 
    505                         s += """<File name="%s" size="%s" />""" % ( 
    506                                         self.convertToXmlAttribute(name), 
    507                                         ((o.get_size() / 1024) + 1) 
    508                                         ) 
    509                 # Close the files node 
    510                 s += """</Files>""" 
    511                 return s 
    512  
    513         def findZopeFolder(self, resourceType, folderName): 
    514                 # returns the context of the resource / folder 
    515                 zopeFolder = self.getZopeUploadContext() 
    516                 folderName = self.removeFromStart(folderName, "/") 
    517                 folderName = self.removeFromEnd(folderName, "/") 
    518                 if (resourceType <> ""): 
    519                         try: 
    520                                 zopeFolder = zopeFolder[resourceType] 
    521                         except: 
    522                                 zopeFolder.manage_addProduct["OFSP"].manage_addFolder(id=resourceType, title=resourceType) 
    523                                 zopeFolder = zopeFolder[resourceType] 
    524                 if (folderName <> ""): 
    525                         folderNames = folderName.split("/") 
    526                         for folderName in folderNames: 
    527                                 zopeFolder = zopeFolder[folderName] 
    528                 return zopeFolder 
    529  
    530         """ 
    531         createFolder 
    532  
    533         Purpose: command to create a new folder 
    534         """ 
    535         def createFolder(self, resourceType, currentFolder): 
    536                 if (self.isZope()): 
    537                         return self.createZopeFolder(resourceType, currentFolder) 
    538                 else: 
    539                         return self.createNonZopeFolder(resourceType, currentFolder) 
    540  
    541         def createZopeFolder(self, resourceType, currentFolder): 
    542                 # Find out where we are 
    543                 zopeFolder = self.findZopeFolder(resourceType, currentFolder) 
    544                 errorNo = 0 
    545                 errorMsg = "" 
    546                 if self.request.has_key("NewFolderName"): 
    547                         newFolder = self.request.get("NewFolderName", None) 
    548                         zopeFolder.manage_addProduct["OFSP"].manage_addFolder(id=newFolder, title=newFolder) 
    549                 else: 
    550                         errorNo = 102 
    551                 error = """<Error number="%s" originalDescription="%s" />""" % ( 
    552                                 errorNo, 
    553                                 self.convertToXmlAttribute(errorMsg) 
    554                                 ) 
    555                 return error 
    556  
    557         def createNonZopeFolder(self, resourceType, currentFolder): 
    558                 errorNo = 0 
    559                 errorMsg = "" 
    560                 if self.request.has_key("NewFolderName"): 
    561                         newFolder = self.request.get("NewFolderName", None) 
    562                         currentFolderPath = self.serverMapFolder( 
    563                                         resourceType, 
    564                                         currentFolder 
    565                                         ) 
    566                         try: 
    567                                 newFolderPath = currentFolderPath + newFolder 
    568                                 errorMsg = self.createServerFolder(newFolderPath) 
    569                                 if (errorMsg is not None): 
    570                                         errorNo = 110 
    571                         except: 
    572                                 errorNo = 103 
    573                 else: 
    574                         errorNo = 102 
    575                 error = """<Error number="%s" originalDescription="%s" />""" % ( 
    576                                 errorNo, 
    577                                 self.convertToXmlAttribute(errorMsg) 
    578                                 ) 
    579                 return error 
    580  
    581         """ 
    582         getFileName 
    583  
    584         Purpose: helper function to extrapolate the filename 
    585         """ 
    586         def getFileName(self, filename): 
    587                 for splitChar in ["/", "\\"]: 
    588                         array = filename.split(splitChar) 
    589                         if (len(array) > 1): 
    590                                 filename = array[-1] 
    591                 return filename 
    592  
    593         """ 
    594         fileUpload 
    595  
    596         Purpose: command to upload files to server 
    597         """ 
    598         def fileUpload(self, resourceType, currentFolder): 
    599                 if (self.isZope()): 
    600                         return self.zopeFileUpload(resourceType, currentFolder) 
    601                 else: 
    602                         return self.nonZopeFileUpload(resourceType, currentFolder) 
    603  
    604         def zopeFileUpload(self, resourceType, currentFolder, count=None): 
    605                 zopeFolder = self.findZopeFolder(resourceType, currentFolder) 
    606                 file = self.request.get("NewFile", None) 
    607                 fileName = self.getFileName(file.filename) 
    608                 fileNameOnly = self.removeExtension(fileName) 
    609                 fileExtension = self.getExtension(fileName).lower() 
    610                 if (count): 
    611                         nid = "%s.%s.%s" % (fileNameOnly, count, fileExtension) 
    612                 else: 
    613                         nid = fileName 
    614                 title = nid 
    615                 try: 
    616                         zopeFolder.manage_addProduct['OFSP'].manage_addFile( 
    617                                         id=nid, 
    618                                         title=title, 
    619                                         file=file.read() 
    620                                         ) 
    621                 except: 
    622                         if (count): 
    623                                 count += 1 
    624                         else: 
    625                                 count = 1 
    626                         self.zopeFileUpload(resourceType, currentFolder, count) 
    627                 return 
    628  
    629         def nonZopeFileUpload(self, resourceType, currentFolder): 
    630                 errorNo = 0 
    631                 errorMsg = "" 
    632                 if self.request.has_key("NewFile"): 
    633                         # newFile has all the contents we need 
    634                         newFile = self.request.get("NewFile", "") 
    635                         # Get the file name 
    636                         newFileName = newFile.filename 
    637                         newFileNameOnly = self.removeExtension(newFileName) 
    638                         newFileExtension = self.getExtension(newFileName).lower() 
    639                         allowedExtensions = self.getAllowedExtensions(resourceType) 
    640                         deniedExtensions = self.getDeniedExtensions(resourceType) 
    641                         if (allowedExtensions is not None): 
    642                                 # Check for allowed 
    643                                 isAllowed = False 
    644                                 if (newFileExtension in allowedExtensions): 
    645                                         isAllowed = True 
    646                         elif (deniedExtensions is not None): 
    647                                 # Check for denied 
    648                                 isAllowed = True 
    649                                 if (newFileExtension in deniedExtensions): 
    650                                         isAllowed = False 
    651                         else: 
    652                                 # No extension limitations 
    653                                 isAllowed = True 
    654  
    655                         if (isAllowed): 
    656                                 if (self.isZope()): 
    657                                         # Upload into zope 
    658                                         self.zopeFileUpload(resourceType, currentFolder) 
    659                                 else: 
    660                                         # Upload to operating system 
    661                                         # Map the virtual path to the local server path 
    662                                         currentFolderPath = self.serverMapFolder( 
    663                                                         resourceType, 
    664                                                         currentFolder 
    665                                                         ) 
    666                                         i = 0 
    667                                         while (True): 
    668                                                 newFilePath = "%s%s" % ( 
    669                                                                 currentFolderPath, 
    670                                                                 newFileName 
    671                                                                 ) 
    672                                                 if os.path.exists(newFilePath): 
    673                                                         i += 1 
    674                                                         newFilePath = "%s%s(%s).%s" % ( 
    675                                                                         currentFolderPath, 
    676                                                                         newFileNameOnly, 
    677                                                                         i, 
    678                                                                         newFileExtension 
    679                                                                         ) 
    680                                                         errorNo = 201 
    681                                                         break 
    682                                                 else: 
    683                                                         fileHandle = open(newFilePath,'w') 
    684                                                         linecount = 0 
    685                                                         while (1): 
    686                                                                 #line = newFile.file.readline() 
    687                                                                 line = newFile.readline() 
    688                                                                 if not line: break 
    689                                                                 fileHandle.write("%s" % line) 
    690                                                                 linecount += 1 
    691                                                         os.chmod(newFilePath, 0777) 
    692                                                         break 
    693                         else: 
    694                                 newFileName = "Extension not allowed" 
    695                                 errorNo = 203 
    696                 else: 
    697                         newFileName = "No File" 
    698                         errorNo = 202 
    699  
    700                 string = """ 
    701 <script type="text/javascript"> 
    702 window.parent.frames["frmUpload"].OnUploadCompleted(%s,"%s"); 
    703 </script> 
    704                                 """ % ( 
    705                                                 errorNo, 
    706                                                 newFileName.replace('"',"'") 
    707                                                 ) 
    708                 return string 
    709  
    710         def run(self): 
    711                 s = "" 
    712                 try: 
    713                         # Check if this is disabled 
    714                         if not(self.enabled): 
    715                                 return self.sendError(1, "This connector is disabled.  Please check the connector configurations and try again") 
    716                         # Make sure we have valid inputs 
    717                         if not( 
    718                                         (self.request.has_key("Command")) and 
    719                                         (self.request.has_key("Type")) and 
    720                                         (self.request.has_key("CurrentFolder")) 
    721                                         ): 
    722                                 return 
    723                         # Get command 
    724                         command = self.request.get("Command", None) 
    725                         # Get resource type 
    726                         resourceType = self.request.get("Type", None) 
    727                         # folder syntax must start and end with "/" 
    728                         currentFolder = self.request.get("CurrentFolder", None) 
    729                         if (currentFolder[-1] <> "/"): 
    730                                 currentFolder += "/" 
    731                         if (currentFolder[0] <> "/"): 
    732                                 currentFolder = "/" + currentFolder 
    733                         # Check for invalid paths 
    734                         if (".." in currentFolder): 
    735                                 return self.sendError(102, "") 
    736                         # File upload doesn't have to return XML, so intercept 
    737                         # her:e 
    738                         if (command == "FileUpload"): 
    739                                 return self.fileUpload(resourceType, currentFolder) 
    740                         # Begin XML 
    741                         s += self.createXmlHeader(command, resourceType, currentFolder) 
    742                         # Execute the command 
    743                         if (command == "GetFolders"): 
    744                                 f = self.getFolders 
    745                         elif (command == "GetFoldersAndFiles"): 
    746                                 f = self.getFoldersAndFiles 
    747                         elif (command == "CreateFolder"): 
    748                                 f = self.createFolder 
    749                         else: 
    750                                 f = None 
    751                         if (f is not None): 
    752                                 s += f(resourceType, currentFolder) 
    753                         s += self.createXmlFooter() 
    754                 except Exception, e: 
    755                         s = "ERROR: %s" % e 
    756                 return s 
    757  
    758 # Running from command line 
     86                # File upload doesn't have to return XML, so intercept here 
     87                if (command == "FileUpload"): 
     88                        return self.uploadFile(resourceType, currentFolder) 
     89                 
     90                # Create Url 
     91                url = combinePaths( self.webUserFilesFolder, currentFolder ) 
     92                 
     93                # Begin XML 
     94                s += self.createXmlHeader(command, resourceType, currentFolder, url) 
     95                # Execute the command 
     96                selector = {"GetFolders": self.getFolders, 
     97                                        "GetFoldersAndFiles": self.getFoldersAndFiles, 
     98                                        "CreateFolder": self.createFolder, 
     99                                        } 
     100                s += selector[command](resourceType, currentFolder) 
     101                s += self.createXmlFooter() 
     102                return s         
     103         
     104# Running from command line (plain old CGI) 
    759105if __name__ == '__main__': 
    760         # To test the output, uncomment the standard headers 
    761         #print "Content-Type: text/html" 
    762         #print "" 
    763         print getFCKeditorConnector() 
    764  
    765 """ 
    766 Running from zope, you will need to modify this connector. 
    767 If you have uploaded the FCKeditor into Zope (like me), you need to 
    768 move this connector out of Zope, and replace the "connector" with an 
    769 alias as below.  The key to it is to pass the Zope context in, as 
    770 we then have a like to the Zope context. 
    771  
    772 ## Script (Python) "connector.py" 
    773 ##bind container=container 
    774 ##bind context=context 
    775 ##bind namespace= 
    776 ##bind script=script 
    777 ##bind subpath=traverse_subpath 
    778 ##parameters=*args, **kws 
    779 ##title=ALIAS 
    780 ## 
    781 import Products.connector as connector 
    782 return connector.getFCKeditorConnector(context=context).run() 
    783 """ 
    784  
    785  
     106        try: 
     107                # Create a Connector Instance 
     108                conn = FCKeditorConnector() 
     109                data = conn.doResponse() 
     110                for header in conn.headers: 
     111                        print '%s: %s' % header 
     112                print  
     113                print data 
     114        except: 
     115                print "Content-Type: text/plain" 
     116                print 
     117                import cgi 
     118                cgi.print_exception() 
  • FCKeditor/trunk/editor/filemanager/connectors/uploadtest.html

    r416 r591  
    9494                                                                        <option value="perl/upload.cgi">Perl</option> 
    9595                                                                        <option value="php/upload.php">PHP</option> 
     96                                                                        <option value="py/upload.py">Python</option> 
    9697                                                                        <option value="">(Custom)</option> 
    9798                                                                </select> 
  • FCKeditor/trunk/fckconfig.js

    r480 r591  
    189189// Custom implementations should just ignore it. 
    190190var _FileBrowserLanguage        = 'php' ;       // asp | aspx | cfm | lasso | perl | php | py 
    191 var _QuickUploadLanguage        = 'php' ;       // asp | aspx | cfm | lasso | perl | php 
     191var _QuickUploadLanguage        = 'php' ;       // asp | aspx | cfm | lasso | perl | php | py 
    192192 
    193193// Don't care about the following line. It just calculates the correct connector 
  • FCKeditor/trunk/_whatsnew.html

    r587 r591  
    5555                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/688">#688</a>] Now the Perl quick upload is  
    5656                        available.</li> 
     57                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/575">#575</a>] The Python connector has been  
     58                        rewritten as a WSGI app to be fully compatible with the latest python frameworks and servers. The  
     59                        QuickUpload feature has been added as well as all the features available in the PHP connector.  
     60                        Thanks to Mariano Reingart.</li> 
    5761                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/561">#561</a>] The asp connector provides an 
    5862                        AbsolutePath setting so it's possible to set the url to a full domain or a relative path and specify that