root / pykota / trunk / pykota / storages / ldapstorage.py @ 1081

Revision 1081, 33.8 kB (checked in by jalet, 21 years ago)

When adding an user only adds one object containing both the user and
its account balance instead of two objects.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2#
3# PyKota : Print Quotas for CUPS and LPRng
4#
5# (c) 2003 Jerome Alet <alet@librelogiciel.com>
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19#
20# $Id$
21#
22# $Log$
23# Revision 1.18  2003/07/11 14:23:13  jalet
24# When adding an user only adds one object containing both the user and
25# its account balance instead of two objects.
26#
27# Revision 1.17  2003/07/07 12:51:07  jalet
28# Small fix
29#
30# Revision 1.16  2003/07/07 12:11:13  jalet
31# Small fix
32#
33# Revision 1.15  2003/07/07 11:49:24  jalet
34# Lots of small fixes with the help of PyChecker
35#
36# Revision 1.14  2003/07/07 08:33:18  jalet
37# Bug fix due to a typo in LDAP code
38#
39# Revision 1.13  2003/07/05 07:46:50  jalet
40# The previous bug fix was incomplete.
41#
42# Revision 1.12  2003/06/30 13:54:21  jalet
43# Sorts by user / group name
44#
45# Revision 1.11  2003/06/25 14:10:01  jalet
46# Hey, it may work (edpykota --reset excepted) !
47#
48# Revision 1.10  2003/06/16 21:55:15  jalet
49# More work on LDAP, again. Problem detected.
50#
51# Revision 1.9  2003/06/16 11:59:09  jalet
52# More work on LDAP
53#
54# Revision 1.8  2003/06/15 22:26:52  jalet
55# More work on LDAP
56#
57# Revision 1.7  2003/06/14 22:44:21  jalet
58# More work on LDAP storage backend.
59#
60# Revision 1.6  2003/06/13 19:07:57  jalet
61# Two big bugs fixed, time to release something ;-)
62#
63# Revision 1.5  2003/06/10 16:37:54  jalet
64# Deletion of the second user which is not needed anymore.
65# Added a debug configuration field in /etc/pykota.conf
66# All queries can now be sent to the logger in debug mode, this will
67# greatly help improve performance when time for this will come.
68#
69# Revision 1.4  2003/06/10 10:45:32  jalet
70# Not implemented methods now raise an exception when called.
71#
72# Revision 1.3  2003/06/06 20:49:15  jalet
73# Very latest schema. UNTESTED.
74#
75# Revision 1.2  2003/06/06 14:21:08  jalet
76# New LDAP schema.
77# Small bug fixes.
78#
79# Revision 1.1  2003/06/05 11:19:13  jalet
80# More good work on LDAP storage.
81#
82#
83#
84
85#
86# My IANA assigned number, for
87# "Conseil Internet & Logiciels Libres, J�me Alet"
88# is 16868. Use this as a base to create the LDAP schema.
89#
90
91import time
92import md5
93
94from pykota.storage import PyKotaStorageError
95from pykota.storage import StorageObject,StorageUser,StorageGroup,StoragePrinter,StorageLastJob,StorageUserPQuota,StorageGroupPQuota
96
97try :
98    import ldap
99    from ldap import modlist
100except ImportError :   
101    import sys
102    # TODO : to translate or not to translate ?
103    raise PyKotaStorageError, "This python version (%s) doesn't seem to have the python-ldap module installed correctly." % sys.version.split()[0]
104   
105class Storage :
106    def __init__(self, pykotatool, host, dbname, user, passwd) :
107        """Opens the LDAP connection."""
108        # raise PyKotaStorageError, "Sorry, the LDAP backend for PyKota is not yet implemented !"
109        self.closed = 1
110        self.tool = pykotatool
111        self.debug = pykotatool.config.getDebug()
112        self.info = pykotatool.config.getLDAPInfo()
113        try :
114            self.database = ldap.initialize(host) 
115            self.database.simple_bind_s(user, passwd)
116            self.basedn = dbname
117        except ldap.SERVER_DOWN :   
118            raise PyKotaStorageError, "LDAP backend for PyKota seems to be down !" # TODO : translate
119        except ldap.LDAPError :   
120            raise PyKotaStorageError, "Unable to connect to LDAP server %s as %s." % (host, user) # TODO : translate
121        else :   
122            self.closed = 0
123            if self.debug :
124                self.tool.logger.log_message("Database opened (host=%s, dbname=%s, user=%s)" % (host, dbname, user), "debug")
125           
126    def __del__(self) :       
127        """Closes the database connection."""
128        if not self.closed :
129            del self.database
130            self.closed = 1
131            if self.debug :
132                self.tool.logger.log_message("Database closed.", "debug")
133       
134    def genUUID(self) :   
135        """Generates an unique identifier.
136       
137           TODO : this one is not unique accross several print servers, but should be sufficient for testing.
138        """
139        return md5.md5("%s" % time.time()).hexdigest()
140       
141    def beginTransaction(self) :   
142        """Starts a transaction."""
143        if self.debug :
144            self.tool.logger.log_message("Transaction begins... WARNING : No transactions in LDAP !", "debug")
145       
146    def commitTransaction(self) :   
147        """Commits a transaction."""
148        if self.debug :
149            self.tool.logger.log_message("Transaction committed. WARNING : No transactions in LDAP !", "debug")
150       
151    def rollbackTransaction(self) :     
152        """Rollbacks a transaction."""
153        if self.debug :
154            self.tool.logger.log_message("Transaction aborted. WARNING : No transaction in LDAP !", "debug")
155       
156    def doSearch(self, key, fields=None, base="", scope=ldap.SCOPE_SUBTREE) :
157        """Does an LDAP search query."""
158        try :
159            base = base or self.basedn
160            if self.debug :
161                self.tool.logger.log_message("QUERY : Filter : %s, BaseDN : %s, Scope : %s, Attributes : %s" % (key, base, scope, fields), "debug")
162            result = self.database.search_s(base or self.basedn, scope, key, fields)
163        except ldap.LDAPError :   
164            raise PyKotaStorageError, _("Search for %s(%s) from %s(scope=%s) returned no answer.") % (key, fields, base, scope)
165        else :     
166            if self.debug :
167                self.tool.logger.log_message("QUERY : Result : %s" % result, "debug")
168            return result
169           
170    def doAdd(self, dn, fields) :
171        """Adds an entry in the LDAP directory."""
172        try :
173            if self.debug :
174                self.tool.logger.log_message("QUERY : ADD(%s, %s)" % (dn, str(fields)), "debug")
175            self.database.add_s(dn, modlist.addModlist(fields))
176        except ldap.LDAPError :
177            raise PyKotaStorageError, _("Problem adding LDAP entry (%s, %s)") % (dn, str(fields))
178        else :
179            return dn
180           
181    def doDelete(self, dn) :
182        """Deletes an entry from the LDAP directory."""
183        try :
184            if self.debug :
185                self.tool.logger.log_message("QUERY : Delete(%s)" % dn, "debug")
186            self.database.delete_s(dn)
187        except ldap.LDAPError :
188            raise PyKotaStorageError, _("Problem deleting LDAP entry (%s)") % dn
189           
190    def doModify(self, dn, fields, ignoreold=1) :
191        """Modifies an entry in the LDAP directory."""
192        try :
193            oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE)
194            if self.debug :
195                self.tool.logger.log_message("QUERY : Modify(%s, %s ==> %s)" % (dn, oldentry[0][1], fields), "debug")
196            self.database.modify_s(dn, modlist.modifyModlist(oldentry[0][1], fields, ignore_oldexistent=ignoreold))
197        except ldap.LDAPError :
198            raise PyKotaStorageError, _("Problem modifying LDAP entry (%s, %s)") % (dn, fields)
199        else :
200            return dn
201           
202    def getUser(self, username) :   
203        """Extracts user information given its name."""
204        user = StorageUser(self, username)
205        result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaLimitBy"], base=self.info["userbase"])
206        if result :
207            fields = result[0][1]
208            user.ident = result[0][0]
209            user.LimitBy = fields.get("pykotaLimitBy")
210            if user.LimitBy is not None :
211                user.LimitBy = user.LimitBy[0]
212            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["balancerdn"], username), ["pykotaBalance", "pykotaLifeTimePaid"], base=self.info["balancebase"])
213            if result :
214                fields = result[0][1]
215                user.idbalance = result[0][0]
216                user.AccountBalance = fields.get("pykotaBalance")
217                if user.AccountBalance is not None :
218                    if user.AccountBalance[0].upper() == "NONE" :
219                        user.AccountBalance = None
220                    else :   
221                        user.AccountBalance = float(user.AccountBalance[0])
222                user.AccountBalance = user.AccountBalance or 0.0       
223                user.LifeTimePaid = fields.get("pykotaLifeTimePaid")
224                if user.LifeTimePaid is not None :
225                    if user.LifeTimePaid[0].upper() == "NONE" :
226                        user.LifeTimePaid = None
227                    else :   
228                        user.LifeTimePaid = float(user.LifeTimePaid[0])
229                user.LifeTimePaid = user.LifeTimePaid or 0.0       
230            user.Exists = 1
231        return user
232       
233    def getGroup(self, groupname) :   
234        """Extracts group information given its name."""
235        group = StorageGroup(self, groupname)
236        result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (groupname, self.info["grouprdn"], groupname), ["pykotaLimitBy"], base=self.info["groupbase"])
237        if result :
238            fields = result[0][1]
239            group.ident = result[0][0]
240            group.LimitBy = fields.get("pykotaLimitBy")
241            if group.LimitBy is not None :
242                group.LimitBy = group.LimitBy[0]
243            group.AccountBalance = 0.0
244            group.LifeTimePaid = 0.0
245            group.Members = self.getGroupMembers(group)
246            for member in group.Members :
247                if member.Exists :
248                    group.AccountBalance += member.AccountBalance
249                    group.LifeTimePaid += member.LifeTimePaid
250            group.Exists = 1
251        return group
252       
253    def getPrinter(self, printername) :       
254        """Extracts printer information given its name."""
255        printer = StoragePrinter(self, printername)
256        result = self.doSearch("(&(objectClass=pykotaPrinter)(|(pykotaPrinterName=%s)(%s=%s)))" % (printername, self.info["printerrdn"], printername), ["pykotaPricePerPage", "pykotaPricePerJob"], base=self.info["printerbase"])
257        if result :
258            fields = result[0][1]
259            printer.ident = result[0][0]
260            printer.PricePerJob = float(fields.get("pykotaPricePerJob")[0] or 0.0)
261            printer.PricePerPage = float(fields.get("pykotaPricePerPage")[0] or 0.0)
262            printer.LastJob = self.getPrinterLastJob(printer)
263            printer.Exists = 1
264        return printer   
265           
266    def getUserGroups(self, user) :       
267        """Returns the user's groups list."""
268        groups = []
269        result = self.doSearch("(&(objectClass=pykotaGroup)(%s=%s))" % (self.info["groupmembers"], user.Name), [self.info["grouprdn"]], base=self.info["groupbase"])
270        if result :
271            for (groupid, fields) in result :
272                groups.append(self.getGroup(fields.get(self.info["grouprdn"])[0]))
273        return groups       
274       
275    def getGroupMembers(self, group) :       
276        """Returns the group's members list."""
277        groupmembers = []
278        result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (group.Name, self.info["grouprdn"], group.Name), [self.info["groupmembers"]], base=self.info["groupbase"])
279        if result :
280            for username in result[0][1].get(self.info["groupmembers"], []) :
281                groupmembers.append(self.getUser(username))
282        return groupmembers       
283       
284    def getUserPQuota(self, user, printer) :       
285        """Extracts a user print quota."""
286        userpquota = StorageUserPQuota(self, user, printer)
287        if user.Exists :
288            result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s)(pykotaPrinterName=%s))" % (user.Name, printer.Name), ["pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=self.info["userquotabase"])
289            if result :
290                fields = result[0][1]
291                userpquota.ident = result[0][0]
292                userpquota.PageCounter = int(fields.get("pykotaPageCounter")[0] or 0)
293                userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter")[0] or 0)
294                userpquota.SoftLimit = fields.get("pykotaSoftLimit")
295                if userpquota.SoftLimit is not None :
296                    if userpquota.SoftLimit[0].upper() == "NONE" :
297                        userpquota.SoftLimit = None
298                    else :   
299                        userpquota.SoftLimit = int(userpquota.SoftLimit[0])
300                userpquota.HardLimit = fields.get("pykotaHardLimit")
301                if userpquota.HardLimit is not None :
302                    if userpquota.HardLimit[0].upper() == "NONE" :
303                        userpquota.HardLimit = None
304                    elif userpquota.HardLimit is not None :   
305                        userpquota.HardLimit = int(userpquota.HardLimit[0])
306                userpquota.DateLimit = fields.get("pykotaDateLimit")
307                if userpquota.DateLimit is not None :
308                    if userpquota.DateLimit[0].upper() == "NONE" : 
309                        userpquota.DateLimit = None
310                    else :   
311                        userpquota.DateLimit = userpquota.DateLimit[0]
312                userpquota.Exists = 1
313        return userpquota
314       
315    def getGroupPQuota(self, group, printer) :       
316        """Extracts a group print quota."""
317        grouppquota = StorageGroupPQuota(self, group, printer)
318        if group.Exists :
319            result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaGroupName=%s)(pykotaPrinterName=%s))" % (group.Name, printer.Name), ["pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=self.info["groupquotabase"])
320            if result :
321                fields = result[0][1]
322                grouppquota.ident = result[0][0]
323                grouppquota.SoftLimit = fields.get("pykotaSoftLimit")
324                if grouppquota.SoftLimit is not None :
325                    if grouppquota.SoftLimit[0].upper() == "NONE" :
326                        grouppquota.SoftLimit = None
327                    else :   
328                        grouppquota.SoftLimit = int(grouppquota.SoftLimit[0])
329                grouppquota.HardLimit = fields.get("pykotaHardLimit")
330                if grouppquota.HardLimit is not None :
331                    if grouppquota.HardLimit[0].upper() == "NONE" :
332                        grouppquota.HardLimit = None
333                    else :   
334                        grouppquota.HardLimit = int(grouppquota.HardLimit[0])
335                grouppquota.DateLimit = fields.get("pykotaDateLimit")
336                if grouppquota.DateLimit is not None :
337                    if grouppquota.DateLimit[0].upper() == "NONE" : 
338                        grouppquota.DateLimit = None
339                    else :   
340                        grouppquota.DateLimit = grouppquota.DateLimit[0]
341                grouppquota.PageCounter = 0
342                grouppquota.LifePageCounter = 0
343                if (not hasattr(group, "Members")) or (group.Members is None) :
344                    group.Members = self.getGroupMembers(group)
345                usernamesfilter = "".join(["(pykotaUserName=%s)" % member.Name for member in group.Members])
346                result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s)(|%s))" % (printer.Name, usernamesfilter), ["pykotaPageCounter", "pykotaLifePageCounter"], base=self.info["userquotabase"])
347                if result :
348                    for userpquota in result :   
349                        grouppquota.PageCounter += int(userpquota[1].get("pykotaPageCounter")[0] or 0)
350                        grouppquota.LifePageCounter += int(userpquota[1].get("pykotaLifePageCounter")[0] or 0)
351                grouppquota.Exists = 1
352        return grouppquota
353       
354    def getPrinterLastJob(self, printer) :       
355        """Extracts a printer's last job information."""
356        lastjob = StorageLastJob(self, printer)
357        result = self.doSearch("(&(objectClass=pykotaLastjob)(|(pykotaPrinterName=%s)(%s=%s)))" % (printer.Name, self.info["printerrdn"], printer.Name), ["pykotaLastJobIdent"], base=self.info["lastjobbase"])
358        if result :
359            lastjob.lastjobident = result[0][0]
360            lastjobident = result[0][1]["pykotaLastJobIdent"][0]
361            result = self.doSearch("objectClass=pykotaJob", ["pykotaUserName", "pykotaJobId", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "createTimestamp"], base="cn=%s,%s" % (lastjobident, self.info["jobbase"]), scope=ldap.SCOPE_BASE)
362            if result :
363                fields = result[0][1]
364                lastjob.ident = result[0][0]
365                lastjob.JobId = fields.get("pykotaJobId")[0]
366                lastjob.User = self.getUser(fields.get("pykotaUserName")[0])
367                lastjob.PrinterPageCounter = int(fields.get("pykotaPrinterPageCounter")[0] or 0)
368                lastjob.JobSize = int(fields.get("pykotaJobSize", [0])[0])
369                lastjob.JobAction = fields.get("pykotaAction")[0]
370                date = fields.get("createTimestamp")[0]
371                year = int(date[:4])
372                month = int(date[4:6])
373                day = int(date[6:8])
374                hour = int(date[8:10])
375                minute = int(date[10:12])
376                second = int(date[12:14])
377                lastjob.JobDate = "%04i-%02i-%02i %02i:%02i:%02i" % (year, month, day, hour, minute, second)
378                lastjob.Exists = 1
379        return lastjob
380       
381    def getMatchingPrinters(self, printerpattern) :
382        """Returns the list of all printers for which name matches a certain pattern."""
383        printers = []
384        # see comment at the same place in pgstorage.py
385        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", "pykotaPricePerPage", "pykotaPricePerJob"], base=self.info["printerbase"])
386        if result :
387            for (printerid, fields) in result :
388                printername = fields["pykotaPrinterName"][0]
389                if self.tool.matchString(printername, [ printerpattern ]) :
390                    printer = StoragePrinter(self, printername)
391                    printer.ident = printerid
392                    printer.PricePerJob = float(fields.get("pykotaPricePerJob")[0] or 0.0)
393                    printer.PricePerPage = float(fields.get("pykotaPricePerPage")[0] or 0.0)
394                    printer.LastJob = self.getPrinterLastJob(printer)
395                    printer.Exists = 1
396                    printers.append(printer)
397        return printers       
398       
399    def getPrinterUsersAndQuotas(self, printer, names=None) :       
400        """Returns the list of users who uses a given printer, along with their quotas."""
401        usersandquotas = []
402        result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s))" % printer.Name, ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=self.info["userquotabase"])
403        if result :
404            for (userquotaid, fields) in result :
405                user = self.getUser(fields["pykotaUserName"][0])
406                if (names is None) or self.tool.matchString(user.Name, names) :
407                    userpquota = StorageUserPQuota(self, user, printer)
408                    userpquota.ident = userquotaid
409                    userpquota.PageCounter = int(fields.get("pykotaPageCounter")[0] or 0)
410                    userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter")[0] or 0)
411                    userpquota.SoftLimit = fields.get("pykotaSoftLimit")
412                    if userpquota.SoftLimit is not None :
413                        if userpquota.SoftLimit[0].upper() == "NONE" :
414                            userpquota.SoftLimit = None
415                        else :   
416                            userpquota.SoftLimit = int(userpquota.SoftLimit[0])
417                    userpquota.HardLimit = fields.get("pykotaHardLimit")
418                    if userpquota.HardLimit is not None :
419                        if userpquota.HardLimit[0].upper() == "NONE" :
420                            userpquota.HardLimit = None
421                        elif userpquota.HardLimit is not None :   
422                            userpquota.HardLimit = int(userpquota.HardLimit[0])
423                    userpquota.DateLimit = fields.get("pykotaDateLimit")
424                    if userpquota.DateLimit is not None :
425                        if userpquota.DateLimit[0].upper() == "NONE" : 
426                            userpquota.DateLimit = None
427                        else :   
428                            userpquota.DateLimit = userpquota.DateLimit[0]
429                    userpquota.Exists = 1
430                    usersandquotas.append((user, userpquota))
431        usersandquotas.sort(lambda x, y : cmp(x[0].Name, y[0].Name))           
432        return usersandquotas
433               
434    def getPrinterGroupsAndQuotas(self, printer, names=None) :       
435        """Returns the list of groups which uses a given printer, along with their quotas."""
436        groupsandquotas = []
437        result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaPrinterName=%s))" % printer.Name, ["pykotaGroupName"], base=self.info["groupquotabase"])
438        if result :
439            for (groupquotaid, fields) in result :
440                group = self.getGroup(fields.get("pykotaGroupName")[0])
441                if (names is None) or self.tool.matchString(group.Name, names) :
442                    grouppquota = self.getGroupPQuota(group, printer)
443                    groupsandquotas.append((group, grouppquota))
444        groupsandquotas.sort(lambda x, y : cmp(x[0].Name, y[0].Name))           
445        return groupsandquotas
446       
447    def addPrinter(self, printername) :       
448        """Adds a printer to the quota storage, returns it."""
449        fields = { self.info["printerrdn"] : printername,
450                   "objectClass" : ["pykotaObject", "pykotaPrinter"],
451                   "cn" : printername,
452                   "pykotaPrinterName" : printername,
453                   "pykotaPricePerPage" : "0.0",
454                   "pykotaPricePerJob" : "0.0",
455                 } 
456        dn = "%s=%s,%s" % (self.info["printerrdn"], printername, self.info["printerbase"])
457        self.doAdd(dn, fields)
458        return self.getPrinter(printername)
459       
460    def addUser(self, user) :       
461        """Adds a user to the quota storage, returns it."""
462        fields = { self.info["userrdn"] : user.Name,
463                   "objectClass" : ["pykotaObject", "pykotaAccount", "pykotaAccountBalance"],
464                   "cn" : user.Name,
465                   "pykotaUserName" : user.Name,
466                   "pykotaLimitBY" : (user.LimitBy or "quota"),
467                   "pykotaBalance" : str(user.AccountBalance or 0.0),
468                   "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0),
469                 } 
470        dn = "%s=%s,%s" % (self.info["userrdn"], user.Name, self.info["userbase"])
471        self.doAdd(dn, fields)
472        return self.getUser(user.Name)
473       
474    def addGroup(self, group) :       
475        """Adds a group to the quota storage, returns it."""
476        fields = { self.info["grouprdn"] : group.Name,
477                   "objectClass" : ["pykotaObject", "pykotaGroup"],
478                   "cn" : group.Name,
479                   "pykotaGroupName" : group.Name,
480                   "pykotaLimitBY" : (group.LimitBy or "quota"),
481                 } 
482        dn = "%s=%s,%s" % (self.info["grouprdn"], group.Name, self.info["groupbase"])
483        self.doAdd(dn, fields)
484        return self.getGroup(group.Name)
485       
486    def addUserToGroup(self, user, group) :   
487        """Adds an user to a group."""
488        if user.Name not in [u.Name for u in group.Members] :
489            result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE)   
490            if result :
491                fields = result[0][1]
492                if not fields.has_key(self.info["groupmembers"]) :
493                    fields[self.info["groupmembers"]] = []
494                fields[self.info["groupmembers"]].append(user.Name)
495                self.doModify(group.ident, fields)
496                group.Members.append(user)
497               
498    def addUserPQuota(self, user, printer) :
499        """Initializes a user print quota on a printer."""
500        uuid = self.genUUID()
501        fields = { "cn" : uuid,
502                   "objectClass" : ["pykotaObject", "pykotaUserPQuota"],
503                   "pykotaUserName" : user.Name,
504                   "pykotaPrinterName" : printer.Name,
505                   "pykotaDateLimit" : "None",
506                   "pykotaPageCounter" : "0",
507                   "pykotaLifePageCounter" : "0",
508                 } 
509        dn = "cn=%s,%s" % (uuid, self.info["userquotabase"])
510        self.doAdd(dn, fields)
511        return self.getUserPQuota(user, printer)
512       
513    def addGroupPQuota(self, group, printer) :
514        """Initializes a group print quota on a printer."""
515        uuid = self.genUUID()
516        fields = { "cn" : uuid,
517                   "objectClass" : ["pykotaObject", "pykotaGroupPQuota"],
518                   "pykotaGroupName" : group.Name,
519                   "pykotaPrinterName" : printer.Name,
520                   "pykotaDateLimit" : "None",
521                 } 
522        dn = "cn=%s,%s" % (uuid, self.info["groupquotabase"])
523        self.doAdd(dn, fields)
524        return self.getGroupPQuota(group, printer)
525       
526    def writePrinterPrices(self, printer) :   
527        """Write the printer's prices back into the storage."""
528        fields = {
529                   "pykotaPricePerPage" : str(printer.PricePerPage),
530                   "pykotaPricePerJob" : str(printer.PricePerJob),
531                 }
532        self.doModify(printer.ident, fields)
533       
534    def writeUserLimitBy(self, user, limitby) :   
535        """Sets the user's limiting factor."""
536        fields = {
537                   "pykotaLimitBy" : limitby,
538                 }
539        self.doModify(user.ident, fields)         
540       
541    def writeGroupLimitBy(self, group, limitby) :   
542        """Sets the group's limiting factor."""
543        fields = {
544                   "pykotaLimitBy" : limitby,
545                 }
546        self.doModify(group.ident, fields)         
547       
548    def writeUserPQuotaDateLimit(self, userpquota, datelimit) :   
549        """Sets the date limit permanently for a user print quota."""
550        fields = {
551                   "pykotaDateLimit" : "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second),
552                 }
553        return self.doModify(userpquota.ident, fields)
554           
555    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :   
556        """Sets the date limit permanently for a group print quota."""
557        fields = {
558                   "pykotaDateLimit" : "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second),
559                 }
560        return self.doModify(grouppquota.ident, fields)
561       
562    def writeUserPQuotaPagesCounters(self, userpquota, newpagecounter, newlifepagecounter) :   
563        """Sets the new page counters permanently for a user print quota."""
564        fields = {
565                   "pykotaPageCounter" : str(newpagecounter),
566                   "pykotaLifePageCounter" : str(newlifepagecounter),
567                 } 
568        return self.doModify(userpquota.ident, fields)         
569       
570    def writeUserAccountBalance(self, user, newbalance, newlifetimepaid=None) :   
571        """Sets the new account balance and eventually new lifetime paid."""
572        fields = {
573                   "pykotaBalance" : str(newbalance),
574                 }
575        if newlifetimepaid is not None :
576            fields.update({ "pykotaLifeTimePaid" : str(newlifetimepaid) })
577        return self.doModify(user.idbalance, fields)         
578           
579    def writeLastJobSize(self, lastjob, jobsize) :       
580        """Sets the last job's size permanently."""
581        fields = {
582                   "pykotaJobSize" : str(jobsize),
583                 }
584        self.doModify(lastjob.ident, fields)         
585       
586    def writeJobNew(self, printer, user, jobid, pagecounter, action, jobsize=None) :   
587        """Adds a job in a printer's history."""
588        uuid = self.genUUID()
589        fields = {
590                   "objectClass" : ["pykotaObject", "pykotaJob"],
591                   "cn" : uuid,
592                   "pykotaUserName" : user.Name,
593                   "pykotaPrinterName" : printer.Name,
594                   "pykotaJobId" : jobid,
595                   "pykotaPrinterPageCounter" : str(pagecounter),
596                   "pykotaAction" : action,
597                 }
598        if jobsize is not None :         
599            fields.update({ "pykotaJobSize" : str(jobsize) })
600        dn = "cn=%s,%s" % (uuid, self.info["jobbase"])
601        self.doAdd(dn, fields)
602        if printer.LastJob.Exists :
603            fields = {
604                       "pykotaLastJobIdent" : uuid,
605                     }
606            self.doModify(printer.LastJob.lastjobident, fields)         
607        else :   
608            lastjuuid = self.genUUID()
609            lastjdn = "cn=%s,%s" % (lastjuuid, self.info["lastjobbase"])
610            fields = {
611                       "objectClass" : ["pykotaObject", "pykotaLastJob"],
612                       "cn" : lastjuuid,
613                       "pykotaPrinterName" : printer.Name,
614                       "pykotaLastJobIdent" : uuid,
615                     } 
616            self.doAdd(lastjdn, fields)         
617           
618    def writeUserPQuotaLimits(self, userpquota, softlimit, hardlimit) :
619        """Sets soft and hard limits for a user quota."""
620        fields = { 
621                   "pykotaSoftLimit" : str(softlimit),
622                   "pykotaHardLimit" : str(hardlimit),
623                 }
624        self.doModify(userpquota.ident, fields)
625       
626    def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) :
627        """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid)."""
628        fields = { 
629                   "pykotaSoftLimit" : str(softlimit),
630                   "pykotaHardLimit" : str(hardlimit),
631                 }
632        self.doModify(grouppquota.ident, fields)
633           
634    def deleteUser(self, user) :   
635        """Completely deletes an user from the Quota Storage."""
636        # TODO : What should we do if we delete the last person who used a given printer ?
637        # TODO : we can't reassign the last job to the previous one, because next user would be
638        # TODO : incorrectly charged (overcharged).
639        result = self.doSearch("(&(objectClass=pykotaLastJob)(pykotaUserName=%s))" % user.Name, base=self.info["lastjobbase"])
640        for (ident, fields) in result :
641            self.doDelete(ident)
642        result = self.doSearch("(&(objectClass=pykotaJob)(pykotaUserName=%s))" % user.Name, base=self.info["jobbase"])
643        for (ident, fields) in result :
644            self.doDelete(ident)
645        result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s))" % user.Name, ["pykotaUserName"], base=self.info["userquotabase"])
646        for (ident, fields) in result :
647            self.doDelete(ident)
648        result = self.doSearch("objectClass=pykotaAccount", None, base=user.ident, scope=ldap.SCOPE_BASE)   
649        if result :
650            fields = result[0][1]
651            for k in fields.keys() :
652                if k.startswith("pykota") :
653                    del fields[k]
654                elif k.lower() == "objectclass" :   
655                    todelete = []
656                    for i in range(len(fields[k])) :
657                        if fields[k][i].startswith("pykota") : 
658                            todelete.append(i)
659                    todelete.sort()       
660                    todelete.reverse()
661                    for i in todelete :
662                        del fields[k][i]
663            if fields.get("objectclass") :           
664                self.doModify(user.ident, fields, ignoreold=0)       
665            else :   
666                self.doDelete(user.ident)
667        result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % user.Name, ["pykotaUserName"], base=self.info["balancebase"])
668        for (ident, fields) in result :
669            self.doDelete(ident)
670       
671    def deleteGroup(self, group) :   
672        """Completely deletes a group from the Quota Storage."""
673        result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaGroupName=%s))" % group.Name, ["pykotaGroupName"], base=self.info["groupquotabase"])
674        for (ident, fields) in result :
675            self.doDelete(ident)
676        result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE)   
677        if result :
678            fields = result[0][1]
679            for k in fields.keys() :
680                if k.startswith("pykota") :
681                    del fields[k]
682                elif k.lower() == "objectclass" :   
683                    todelete = []
684                    for i in range(len(fields[k])) :
685                        if fields[k][i].startswith("pykota") : 
686                            todelete.append(i)
687                    todelete.sort()       
688                    todelete.reverse()
689                    for i in todelete :
690                        del fields[k][i]
691            if fields.get("objectclass") :           
692                self.doModify(group.ident, fields, ignoreold=0)       
693            else :   
694                self.doDelete(group.ident)
695           
Note: See TracBrowser for help on using the browser.