This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/servers/UploadFilesServer/UploadFilesServer.py

465 lines
20 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
__doc__ = """Glasnost Upload Files Server"""
__version__ = '$Revision$'[11:-2]
import fcntl
import cStringIO
import os
from stat import *
import sys
import mimetypes
# From Python Imaging Library.
try:
import Image as PILImage
except ImportError:
PILImage = None
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)
import glasnost
from glasnost.common.UploadFilesCommon import *
import glasnost.common.faults as faults
import glasnost.common.xhtmlgenerator as X
from glasnost.server.ObjectsServer import register, ObjectServerMixin, \
AdminServerMixin, ObjectsServer
from glasnost.server.tools import *
from glasnost.proxy.CacheProxy import invalidateValue
from glasnost.proxy.DispatcherProxy import getApplicationId
applicationName = 'UploadFilesServer'
applicationRole = 'uploadfiles'
dispatcher = None
class AdminUploadFiles(AdminServerMixin, AdminUploadFilesCommon):
pass
register(AdminUploadFiles)
class UploadFile(ObjectServerMixin, UploadFileCommon):
def acquireNonCore(self, objectDirectoryPath = None,
dataDirectoryPath = None, parentSlot = None):
ObjectServerMixin.acquireNonCore(
self, objectDirectoryPath = objectDirectoryPath,
dataDirectoryPath = dataDirectoryPath, parentSlot = parentSlot)
self.loadData()
def loadData(self):
virtualServerId = self.getServer().computeVirtualServerId(self.id)
virtualServer = self.getServer().getVirtualServer(virtualServerId)
uploadFilesDirectoryPath = os.path.join(
virtualServer.dataDirectoryPath, self.getServer().applicationRole)
serverHostNameAndPort, serverRole, localId = splitId(self.id)
dataFilePath = os.path.join(uploadFilesDirectoryPath, localId)
try:
dataFile = open(dataFilePath, 'rb')
except IOError:
if self.__dict__.has_key('data'):
del self.data
if self.__dict__.has_key('height'):
del self.height
if self.__dict__.has_key('width'):
del self.width
if self.__dict__.has_key('size'):
del self.size
else:
fcntl.lockf(dataFile, fcntl.LOCK_SH)
self.data = dataFile.read()
fcntl.lockf(dataFile, fcntl.LOCK_UN)
dataFile.close()
# XMLRPC doesn't implements the handling of long integers.
self.size = int(os.stat(dataFilePath)[ST_SIZE])
if self.isType('image') and PILImage:
uploadFileFile = cStringIO.StringIO(self.data)
try:
uploadFileObject = PILImage.open(uploadFileFile)
except IOError:
pass
else:
self.width, self.height = uploadFileObject.size
def releaseNonCore(self, parentSlot = None):
if self.__dict__.has_key('data'):
del self.data
ObjectServerMixin.releaseNonCore(self, parentSlot)
def removeDataFile(self):
virtualServerId = self.getServer().computeVirtualServerId(self.id)
virtualServer = self.getServer().getVirtualServer(virtualServerId)
uploadFilesDirectoryPath = os.path.join(
virtualServer.dataDirectoryPath, self.getServer().applicationRole)
serverHostNameAndPort, serverRole, localId = splitId(self.id)
dataFilePath = os.path.join(uploadFilesDirectoryPath, localId)
try:
os.remove(dataFilePath)
except OSError, error:
# Ignore 'No such file or directory' error.
if error.errno != 2:
raise
def removeNonCore(self, objectDirectoryPath = None,
dataDirectoryPath = None, parentSlot = None):
ObjectServerMixin.removeNonCore(
self, objectDirectoryPath = objectDirectoryPath,
dataDirectoryPath = dataDirectoryPath, parentSlot = parentSlot)
self.removeDataFile()
def saveData(self):
if self.data is None:
self.removeDataFile()
return
virtualServerId = self.getServer().computeVirtualServerId(self.id)
virtualServer = self.getServer().getVirtualServer(virtualServerId)
uploadFilesDirectoryPath = os.path.join(
virtualServer.dataDirectoryPath, self.getServer().applicationRole)
if not os.access(virtualServer.dataDirectoryPath, os.F_OK):
os.mkdir(virtualServer.dataDirectoryPath)
os.chmod(virtualServer.dataDirectoryPath, 0750)
if not os.access(uploadFilesDirectoryPath, os.F_OK):
os.mkdir(uploadFilesDirectoryPath)
os.chmod(uploadFilesDirectoryPath, 0750)
serverHostNameAndPort, serverRole, localId = splitId(self.id)
dataFilePath = os.path.join(uploadFilesDirectoryPath, localId)
dataFile = open(dataFilePath, 'wb')
os.chmod(dataFilePath, 0640)
fcntl.lockf(dataFile, fcntl.LOCK_EX)
dataFile.write(self.data)
fcntl.lockf(dataFile, fcntl.LOCK_UN)
dataFile.close()
# XMLRPC doesn't implements the handling of long integers.
self.size = int(os.stat(dataFilePath)[ST_SIZE])
if self.isType('image') and PILImage:
uploadFileFile = cStringIO.StringIO(self.data)
try:
uploadFileObject = PILImage.open(uploadFileFile)
except IOError:
pass
else:
self.width, self.height = uploadFileObject.size
def saveNonCore(self, objectDirectoryPath = None, dataDirectoryPath = None,
parentSlot = None):
ObjectServerMixin.saveNonCore(
self, objectDirectoryPath = objectDirectoryPath,
dataDirectoryPath = dataDirectoryPath, parentSlot = parentSlot)
self.saveData()
register(UploadFile)
class UploadFilesServer(UploadFilesCommonMixin, ObjectsServer):
def addObjectXmlRpc(self, objectImport):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = commonTools.importThing(objectImport)
if not object.dataType:
object.dataType = 'application/octet-stream'
# FIXME: We should move this to a new kind for mime types.
if object.dataFileName \
and (object.dataType == 'application/octet-stream'):
mimeType = mimetypes.guess_type(object.dataFileName)
if mimeType[0] is not None:
object.dataType = mimeType[0]
if not self.isAdmin() and not (
getProxyForServerRole('authentication').setContainsUser(
self.getAdminCore().writersSet)
and getProxyForServerRole('authentication').setContainsUser(
object.writersSet)):
if not object.canBeCreatedByClient():
raise faults.UserAccessDenied()
object.checkAddIsPossible()
object.setAutomaticalSlots()
virtualServer.objects[object.id] = object
object.saveNonCore()
object.releaseNonCore()
virtualServer.markObjectAsDirty(object)
virtualServer.markCoreAsDirty()
return object.id
def convertVirtualServersIds(
self, sourceDispatcherId, destinationDispatcherId):
exitCode = ObjectsServer.convertVirtualServersIds(
self, sourceDispatcherId, destinationDispatcherId)
if exitCode is not None:
return exitCode
destinationVirtualServerId = '%s/%s' % (
destinationDispatcherId, self.applicationRole)
virtualServer = self.virtualServers[destinationVirtualServerId]
sourceHostName = extractApplicationHostName(sourceDispatcherId)
destinationHostName = extractApplicationHostName(
destinationDispatcherId)
sourceVirtualServerDataDirectoryPath = os.path.join(
self.dataDirectoryPath, sourceHostName)
destinationVirtualServerDataDirectoryPath = os.path.join(
self.dataDirectoryPath, destinationHostName)
sourceObjectsDirectoryPath = os.path.join(
sourceVirtualServerDataDirectoryPath, self.applicationRole)
destinationObjectsDirectoryPath = os.path.join(
destinationVirtualServerDataDirectoryPath, self.applicationRole)
for id in virtualServer.objects.keys():
serverHostNameAndPortNotUsed, serverRoleNotUsed, localId = \
splitId(id)
sourceDataFilePath = os.path.join(
sourceObjectsDirectoryPath, localId)
destinationDataFilePath = os.path.join(
destinationObjectsDirectoryPath, localId)
if not os.access(sourceDataFilePath, os.F_OK):
continue
if not os.access(
destinationVirtualServerDataDirectoryPath, os.F_OK):
os.mkdir(destinationVirtualServerDataDirectoryPath)
os.chmod(destinationVirtualServerDataDirectoryPath, 0750)
if not os.access(destinationObjectsDirectoryPath, os.F_OK):
os.mkdir(destinationObjectsDirectoryPath)
os.chmod(destinationObjectsDirectoryPath, 0750)
sourceDataFile = open(sourceDataFilePath, 'rb')
destinationDataFile = open(destinationDataFilePath, 'wb')
os.chmod(destinationDataFilePath, 0640)
destinationDataFile.write(sourceDataFile.read())
sourceDataFile.close()
destinationDataFile.close()
return None
def exportVirtualServer(self, virtualServerId, exportDirectoryPath):
exitCode = ObjectsServer.exportVirtualServer(
self, virtualServerId, exportDirectoryPath)
if exitCode is not None:
return exitCode
virtualServer = self.virtualServers[virtualServerId]
hostName = extractApplicationHostName(virtualServerId)
virtualServerDataDirectoryPath = os.path.join(
self.dataDirectoryPath, hostName)
objectsDirectoryPath = os.path.join(
virtualServerDataDirectoryPath, self.applicationRole)
exportObjectsDirectoryPath = os.path.join(
exportDirectoryPath, self.applicationRole)
for id in virtualServer.objects.keys():
serverHostNameAndPortNotUsed, serverRoleNotUsed, localId = \
splitId(id)
sourceBodyFilePath = os.path.join(
objectsDirectoryPath, localId)
exportBodyFilePath = os.path.join(
exportObjectsDirectoryPath, localId)
if not os.access(sourceBodyFilePath, os.F_OK):
continue
if not os.access(exportDirectoryPath, os.F_OK):
os.mkdir(exportDirectoryPath)
os.chmod(exportDirectoryPath, 0750)
if not os.access(exportObjectsDirectoryPath, os.F_OK):
os.mkdir(exportObjectsDirectoryPath)
os.chmod(exportObjectsDirectoryPath, 0750)
sourceBodyFile = open(sourceBodyFilePath, 'rb')
exportBodyFile = open(exportBodyFilePath, 'wb')
os.chmod(exportBodyFilePath, 0640)
exportBodyFile.write(sourceBodyFile.read())
sourceBodyFile.close()
exportBodyFile.close()
return None
def getObjectThumbnailXmlRpc(self, objectId, width, height):
object = self.getObjectCore(objectId)
object.acquireNonCore()
try:
if object.data:
if object.isType('image') and PILImage:
objectFile = cStringIO.StringIO(object.data)
try:
objectObject = PILImage.open(objectFile)
except IOError:
pass
else:
objectObject.thumbnail((width, height))
thumbnailFile = cStringIO.StringIO()
objectObject.save(
thumbnailFile, objectObject.format)
object.data = thumbnailFile.getvalue()
object.width, object.height = objectObject.size
result = object.exportToXmlRpc()
finally:
object.releaseNonCore()
return result
def importVirtualServer(self, virtualServerId, importDirectoryPath):
virtualServer = ObjectsServer.importVirtualServer(
self, virtualServerId, importDirectoryPath)
if virtualServer is None:
return None
hostName = extractApplicationHostName(virtualServerId)
virtualServerDataDirectoryPath = os.path.join(
self.dataDirectoryPath, hostName)
importObjectsDirectoryPath = os.path.join(
importDirectoryPath, self.applicationRole)
objectsDirectoryPath = os.path.join(
virtualServerDataDirectoryPath, self.applicationRole)
for id in virtualServer.objects.keys():
serverHostNameAndPortNotUsed, serverRoleNotUsed, localId = \
splitId(id)
importBodyFilePath = os.path.join(
importObjectsDirectoryPath, localId)
destinationBodyFilePath = os.path.join(
objectsDirectoryPath, localId)
if not os.access(importBodyFilePath, os.F_OK):
continue
if not os.access(virtualServerDataDirectoryPath, os.F_OK):
os.mkdir(virtualServerDataDirectoryPath)
os.chmod(virtualServerDataDirectoryPath, 0750)
if not os.access(objectsDirectoryPath, os.F_OK):
os.mkdir(objectsDirectoryPath)
os.chmod(objectsDirectoryPath, 0750)
importBodyFile = open(importBodyFilePath, 'rb')
destinationBodyFile = open(destinationBodyFilePath, 'wb')
os.chmod(destinationBodyFilePath, 0640)
destinationBodyFile.write(importBodyFile.read())
importBodyFile.close()
destinationBodyFile.close()
return virtualServer
def modifyObjectXmlRpc(self, objectImport):
objectChanges = commonTools.importThing(objectImport)
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectChanges.id)
object.acquireNonCore()
try:
if not object.canBeModified():
raise faults.ReadOnlyObject()
if not self.canModifyObject(object.id) or not (
self.isAdmin()
or not objectChanges.hasSlotName('writersSet')
or getProxyForServerRole('authentication'
).setContainsUser(
objectChanges.getSlot('writersSet').getValue())):
if not object.canBeModifiedByClient():
raise faults.UserAccessDenied()
object.checkModifyIsPossible(objectChanges)
oldData = object.data
object.modify(objectChanges)
# FIXME: We should move this to a new kind for mime types.
if object.dataFileName and \
object.dataType == 'application/octet-stream':
mimeType = mimetypes.guess_type(object.dataFileName)
if mimeType[0] is not None:
object.dataType = mimeType[0]
object.saveNonCore()
finally:
object.releaseNonCore()
virtualServer.markObjectAsDirty(object)
invalidateValue(object.id)
return object.version
def registerPublicMethods(self):
ObjectsServer.registerPublicMethods(self)
self.registerPublicMethod('getObjectThumbnail',
self.getObjectThumbnailXmlRpc)
def repairVirtualServer(self, virtualServer, version):
changed = 0
if version < 4000:
changed = virtualServer.admin.repair(4000) or changed
for id, object in virtualServer.objects.items():
newId = repairId(id)
if newId:
changed = 1
del virtualServer.objects[id]
virtualServer.objects[newId] = object
changed = object.repair(4000) or changed
if not object.__dict__.has_key('language'):
changed = 1
object.language = 'fr'
if version < 5004:
for id, object in virtualServer.objects.items():
if type(object.dataType) == type(()):
changed = 1
del object.dataType
if object.dataFileName and \
object.dataType == 'application/octet-stream':
mimeType = mimetypes.guess_type(object.dataFileName)
if mimeType[0] is not None:
changed = 1
object.dataType = mimeType[0]
if version < 5004:
changed = virtualServer.admin.repair(5004) or changed
for id, object in virtualServer.objects.items():
changed = object.repair(5004) or changed
if version <= 1018000:
admin = virtualServer.admin
if admin.id is None:
changed = 1
admin.id = '%s/__admin__' % virtualServer.virtualServerId
if version <= 1037000:
# cleaning dateFileName
for id, object in virtualServer.objects.items():
filename = object.dataFileName
if not filename:
continue
if '\\' in filename:
object.dataFileName == filename[ filename.rindex('\\')+1: ]
changed = 1
elif '/' in filename:
object.dataFileName == filename[ filename.rindex('/')+1: ]
changed = 1
if version <= 1039000:
# filling empty mime-types with application/octet-stream
for id, object in virtualServer.objects.items():
if not object.dataType:
object.dataType = 'application/octet-stream'
changed = 1
if changed:
virtualServer.markAllAsDirtyFIXME()
uploadFilesServer = UploadFilesServer()
if __name__ == "__main__":
uploadFilesServer.launch(applicationName, applicationRole)