[bin] backup.py: remove Data.fs.old before packing the ZODB to avoid disk space problems; [checkldap] added a param to define the scope of the LDAP query (base, onelevel or subtree); [shared] xml_parser: convert nbsp entity to the equivalent utf-8 char.

This commit is contained in:
Gaetan Delannay 2013-09-05 10:42:19 +02:00
parent 528cca9aa0
commit 1be7d9f0ab
8 changed files with 83 additions and 22 deletions

View file

@ -61,6 +61,21 @@ class ZodbBackuper:
fileName = self.storageLocation + fileSuffix fileName = self.storageLocation + fileSuffix
os.system('chown %s %s' % (self.zopeUser, fileName)) os.system('chown %s %s' % (self.zopeUser, fileName))
def removeDataFsOld(self):
'''Removes the file Data.fs.old if it exists.
In the process of packing the ZODB, an additional file Data.fs.pack
is created, and renamed to Data.fs once finished. It means that, when
we pack the ZODB, 3 copies of the DB can be present at the same time:
Data.fs, Data.fs.old and Data.fs.pack. We prefer to remove the
Data.fs.old copy to avoid missing disk space if the DB is big.
'''
old = self.storageLocation + '.old'
if os.path.exists(old):
self.log('Removing %s...' % old)
os.remove(old)
self.log('Done.')
folderCreateError = 'Could not create backup folder. Backup of log ' \ folderCreateError = 'Could not create backup folder. Backup of log ' \
'files will not take place. %s' 'files will not take place. %s'
def backupLogs(self): def backupLogs(self):
@ -190,6 +205,8 @@ class ZodbBackuper:
self.executeCommand('%s stop' % self.zopectl) self.executeCommand('%s stop' % self.zopectl)
# If we are on the "full backup day", let's pack the ZODB first # If we are on the "full backup day", let's pack the ZODB first
if time.asctime().startswith(self.options.dayFullBackup): if time.asctime().startswith(self.options.dayFullBackup):
# As a preamble to packing the ZODB, remove Data.fs.old if present.
self.removeDataFsOld()
w('> Day is "%s", packing the ZODB...' % self.options.dayFullBackup) w('> Day is "%s", packing the ZODB...' % self.options.dayFullBackup)
self.packZodb() self.packZodb()
w('> Make a backup of log files...') w('> Make a backup of log files...')

View file

@ -12,18 +12,22 @@ class LdapTester:
attrs is a comma-separated list of attrs we will retrieve in the LDAP, attrs is a comma-separated list of attrs we will retrieve in the LDAP,
ie "uid,login" ie "uid,login"
filter is the query filter, ie "(&(attr1=Geez*)(status=OK))" filter is the query filter, ie "(&(attr1=Geez*)(status=OK))"
scope is the scope of the search, and can be:
BASE To search the object itself on base
ONELEVEL To search base's immediate children
SUBTREE To search base and all its descendants
''' '''
def __init__(self): def __init__(self):
# Get params from shell args. # Get params from shell args.
if len(sys.argv) != 7: if len(sys.argv) != 8:
print(LdapTester.__doc__) print(LdapTester.__doc__)
sys.exit(0) sys.exit(0)
s = self s = self
s.uri, s.login, s.password, s.base, s.attrs, s.filter = sys.argv[1:] s.uri,s.login,s.password,s.base,s.attrs,s.filter,s.scope = sys.argv[1:]
self.attrs = self.attrs.split(',') self.attrs = self.attrs.split(',')
self.tentatives = 5 self.tentatives = 5
self.timeout = 5 self.timeout = 5
self.attrList = ['cfwbV2cn', 'logindisabled'] self.attrList = ['cn']
self.ssl = False self.ssl = False
def test(self): def test(self):
@ -38,8 +42,9 @@ class LdapTester:
for i in range(self.tentatives): for i in range(self.tentatives):
try: try:
print('Done. Performing a simple query on %s...'% self.base) print('Done. Performing a simple query on %s...'% self.base)
res = server.search_st( res = server.search_st(self.base,
self.base, ldap.SCOPE_ONELEVEL, filterstr=self.filter, getattr(ldap, 'SCOPE_%s' % self.scope),
filterstr=self.filter,
attrlist=self.attrs, timeout=5) attrlist=self.attrs, timeout=5)
print('Got %d entries' % len(res)) print('Got %d entries' % len(res))
break break

View file

@ -369,15 +369,22 @@ class User(Model):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class LdapConfig: class LdapConfig:
'''Parameters for authenticating users to an external LDAP.''' '''Parameters for authenticating users to an external LDAP.'''
server = '' # Name of the LDAP server def __init__(self):
port = None # Port for this server. self.server = '' # Name of the LDAP server
# Login and password of the technical power user that the Appy application self.port = None # Port for this server.
# will use to connect to the LDAP. # Login and password of the technical power user that the Appy
adminLogin = '' # application will use to connect to the LDAP.
adminPassword = '' self.adminLogin = ''
# LDAP attribute to use as login for authenticating users. self.adminPassword = ''
loginAttribute = 'dn' # Can also be "mail", "sAMAccountName", "cn" # LDAP attribute to use as login for authenticating users.
baseDn = '' # Base distinguished name where to find users in the LDAP. self.loginAttribute = 'dn' # Can also be "mail", "sAMAccountName", "cn"
self.baseDn = '' # Base distinguished name where to find users.
def getServerUri(self):
'''Returns the complete URI for accessing the LDAP, ie
"ldap://some.ldap.server:389".'''
port = self.port or 389
return 'ldap://%s:%d' % (self.server, port)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Config: class Config:

View file

@ -25,12 +25,11 @@ def traverseWrapper(self, path, response=None, validated_hook=None):
'''This function is called every time a users gets a URL, this is used for '''This function is called every time a users gets a URL, this is used for
tracking user activity. self is a BaseRequest''' tracking user activity. self is a BaseRequest'''
res = originalTraverse(self, path, response, validated_hook) res = originalTraverse(self, path, response, validated_hook)
t = time.time()
if os.path.splitext(path)[-1].lower() not in doNotTrack: if os.path.splitext(path)[-1].lower() not in doNotTrack:
# Do nothing when the user gets non-pages # Do nothing when the user gets non-pages.
userId, dummy = gutils.readCookie(self) userId, dummy = gutils.readCookie(self)
if userId: if userId:
loggedUsers[userId] = t loggedUsers[userId] = time.time()
# "Touch" the SESSION object. Else, expiration won't occur. # "Touch" the SESSION object. Else, expiration won't occur.
session = self.SESSION session = self.SESSION
return res return res

View file

@ -1,5 +1,34 @@
# ------------------------------------------------------------------------------
try:
import ldap
except ImportError:
# For people that do not care about ldap.
ldap = None
# ------------------------------------------------------------------------------
def connect(serverUri, login, password):
'''Tries to connect to some LDAP server whose UIR is p_serverUri, using
p_login and p_password as credentials.'''
try:
server = ldap.initialize(serverUri)
server.simple_bind(login, password)
return True, server, None
except ldap.LDAPError, le:
return False, None, str(le)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def authenticate(login, password, ldapConfig, tool): def authenticate(login, password, ldapConfig, tool):
'''Tries to authenticate user p_login in the LDAP.''' '''Tries to authenticate user p_login in the LDAP.'''
return # Connect to the ldap server.
serverUri = cfg.getServerUri()
success, server, msg = connect(serverUri, cfg.adminLogin, cfg.adminPassword)
# Manage a connection error.
if not success:
tool.log('%s: connect error (%s).' % (serverUri, msg))
return
# Do p_login and p_password correspond to a user in the LDAP?
try:
pass
except:
pass
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -1051,6 +1051,7 @@ class ToolMixin(BaseMixin):
# a is the object the object was accessed through # a is the object the object was accessed through
# c is the physical container of the object # c is the physical container of the object
a, c, n, v = self._getobcontext(v, request) a, c, n, v = self._getobcontext(v, request)
print c
# Try to get user name and password from basic authentication # Try to get user name and password from basic authentication
login, password = self.identify(auth) login, password = self.identify(auth)
if not login: if not login:

View file

@ -330,7 +330,7 @@ class XhtmlEnvironment(XmlEnvironment):
'''Dumps content that was temporarily stored in self.currentContent '''Dumps content that was temporarily stored in self.currentContent
into the result.''' into the result.'''
contentSize = 0 contentSize = 0
if self.currentContent.strip(): if self.currentContent.strip(' \n\r\t'): # NBSP must not be in this list
# Manage missing elements # Manage missing elements
currentElem = self.getCurrentElement() currentElem = self.getCurrentElement()
if self.anElementIsMissing(currentElem, None): if self.anElementIsMissing(currentElem, None):

View file

@ -61,7 +61,7 @@ HTML_ENTITIES = {
'ntilde':'ñ', 'ograve':'ò', 'oacute':'ó', 'ocirc':'ô', 'otilde':'õ', 'ntilde':'ñ', 'ograve':'ò', 'oacute':'ó', 'ocirc':'ô', 'otilde':'õ',
'ouml':'ö', 'divide':'÷', 'oslash':'ø', 'ugrave':'ù', 'uacute':'ú', 'ouml':'ö', 'divide':'÷', 'oslash':'ø', 'ugrave':'ù', 'uacute':'ú',
'ucirc':'û', 'uuml':'ü', 'yacute':'ý', 'thorn':'þ', 'yuml':'ÿ', 'ucirc':'û', 'uuml':'ü', 'yacute':'ý', 'thorn':'þ', 'yuml':'ÿ',
'euro':'', 'nbsp':' ', "rsquo":"'", "lsquo":"'", "ldquo":"'", 'euro':'', 'nbsp':' ', "rsquo":"'", "lsquo":"'", "ldquo":"'",
"rdquo":"'", 'ndash': '', 'mdash': '', 'oelig':'oe', 'quot': "'", "rdquo":"'", 'ndash': '', 'mdash': '', 'oelig':'oe', 'quot': "'",
'mu': 'µ'} 'mu': 'µ'}
import htmlentitydefs import htmlentitydefs
@ -1135,7 +1135,10 @@ class XhtmlCleaner(XmlParser):
# between tags. # between tags.
if not self.env.currentContent or \ if not self.env.currentContent or \
self.env.currentContent[-1] in ('\n', ' '): self.env.currentContent[-1] in ('\n', ' '):
toAdd = content.lstrip() # I give here to lstrip an explicit list of what is to be considered
# as blank chars, because I do not want unicode NBSP chars to be in
# this list.
toAdd = content.lstrip(u' \n\r\t')
else: else:
toAdd = content toAdd = content
# Re-transform XML special chars to entities. # Re-transform XML special chars to entities.