root / pykota / trunk / pykota / storage.py @ 1376

Revision 1376, 24.8 kB (checked in by jalet, 20 years ago)

Pre and Post hooks should now work in the pykota filter too.
The pykota filter doesn't check the last user's quota anymore
when delayed hardware accounting is used : this will be checked
anyway the next time the last user will print

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2# -*- coding: ISO-8859-15 -*-
3#
4# PyKota : Print Quotas for CUPS and LPRng
5#
6# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20#
21# $Id$
22#
23# $Log$
24# Revision 1.49  2004/03/01 15:06:51  jalet
25# Pre and Post hooks should now work in the pykota filter too.
26# The pykota filter doesn't check the last user's quota anymore
27# when delayed hardware accounting is used : this will be checked
28# anyway the next time the last user will print
29#
30# Revision 1.48  2004/02/27 13:50:12  jalet
31# Hopefully the final fix for groups (users and printers)
32#
33# Revision 1.47  2004/02/27 09:30:33  jalet
34# datelimit wasn't reset when modifying soft and hard limits with the LDAP backend
35#
36# Revision 1.46  2004/02/26 14:18:07  jalet
37# Should fix the remaining bugs wrt printers groups and users groups.
38#
39# Revision 1.45  2004/02/26 10:40:40  jalet
40# Fixed nested printer groups accounting.
41#
42# Revision 1.44  2004/02/25 19:09:24  jalet
43# Fix for LDAP problem when job price was 0.
44#
45# Revision 1.43  2004/02/25 12:36:34  jalet
46# Avoids a database query even if caching was disabled.
47#
48# Revision 1.42  2004/02/23 22:53:21  jalet
49# Don't retrieve data when it's not needed, to avoid database queries
50#
51# Revision 1.41  2004/02/04 17:12:33  jalet
52# Removing a printer from a printers group should work now.
53#
54# Revision 1.40  2004/02/04 13:24:41  jalet
55# pkprinters can now remove printers from printers groups.
56#
57# Revision 1.39  2004/02/04 11:16:59  jalet
58# pkprinters command line tool added.
59#
60# Revision 1.38  2004/01/12 22:43:40  jalet
61# New formula to compute a job's price
62#
63# Revision 1.37  2004/01/12 14:35:01  jalet
64# Printing history added to CGI script.
65#
66# Revision 1.36  2004/01/10 09:44:02  jalet
67# Fixed potential accuracy problem if a user printed on several printers at
68# the very same time.
69#
70# Revision 1.35  2004/01/08 16:33:27  jalet
71# Additionnal check to not create a circular printers group.
72#
73# Revision 1.34  2004/01/08 16:24:49  jalet
74# edpykota now supports adding printers to printer groups.
75#
76# Revision 1.33  2004/01/08 14:10:32  jalet
77# Copyright year changed.
78#
79# Revision 1.32  2004/01/06 16:02:57  jalet
80# This time printer groups caching works.
81#
82# Revision 1.31  2004/01/06 15:51:24  jalet
83# Fixed caching of printer groups
84#
85# Revision 1.30  2004/01/06 14:24:59  jalet
86# Printer groups should be cached now, if caching is enabled.
87#
88# Revision 1.29  2003/12/27 16:49:25  uid67467
89# Should be ok now.
90#
91# Revision 1.28  2003/11/25 23:46:40  jalet
92# Don't try to verify if module name is valid, Python does this better than us.
93#
94# Revision 1.27  2003/11/23 19:01:36  jalet
95# Job price added to history
96#
97# Revision 1.26  2003/11/21 14:28:45  jalet
98# More complete job history.
99#
100# Revision 1.25  2003/10/08 21:12:27  jalet
101# Do not cache anymore entries which don't exist.
102#
103# Revision 1.24  2003/10/07 22:06:05  jalet
104# Preliminary code to disable job history
105#
106# Revision 1.23  2003/10/07 09:07:28  jalet
107# Character encoding added to please latest version of Python
108#
109# Revision 1.22  2003/10/06 13:12:27  jalet
110# More work on caching
111#
112# Revision 1.21  2003/10/03 09:02:20  jalet
113# Logs cache store actions too
114#
115# Revision 1.20  2003/10/02 20:23:18  jalet
116# Storage caching mechanism added.
117#
118# Revision 1.19  2003/07/16 21:53:07  jalet
119# Really big modifications wrt new configuration file's location and content.
120#
121# Revision 1.18  2003/07/07 08:33:18  jalet
122# Bug fix due to a typo in LDAP code
123#
124# Revision 1.17  2003/07/05 07:46:50  jalet
125# The previous bug fix was incomplete.
126#
127# Revision 1.16  2003/06/25 19:52:31  jalet
128# Should be ready for testing :-)
129#
130# Revision 1.15  2003/06/25 14:10:58  jalet
131# Exception raising for now.
132#
133# Revision 1.14  2003/06/25 14:10:01  jalet
134# Hey, it may work (edpykota --reset excepted) !
135#
136# Revision 1.13  2003/06/10 16:37:54  jalet
137# Deletion of the second user which is not needed anymore.
138# Added a debug configuration field in /etc/pykota.conf
139# All queries can now be sent to the logger in debug mode, this will
140# greatly help improve performance when time for this will come.
141#
142# Revision 1.12  2003/04/23 22:13:57  jalet
143# Preliminary support for LPRng added BUT STILL UNTESTED.
144#
145# Revision 1.11  2003/04/10 21:47:20  jalet
146# Job history added. Upgrade script neutralized for now !
147#
148# Revision 1.10  2003/03/29 13:45:27  jalet
149# GPL paragraphs were incorrectly (from memory) copied into the sources.
150# Two README files were added.
151# Upgrade script for PostgreSQL pre 1.01 schema was added.
152#
153# Revision 1.9  2003/02/17 22:55:01  jalet
154# More options can now be set per printer or globally :
155#
156#       admin
157#       adminmail
158#       gracedelay
159#       requester
160#
161# the printer option has priority when both are defined.
162#
163# Revision 1.8  2003/02/17 22:05:50  jalet
164# Storage backend now supports admin and user passwords (untested)
165#
166# Revision 1.7  2003/02/10 12:07:31  jalet
167# Now repykota should output the recorded total page number for each printer too.
168#
169# Revision 1.6  2003/02/09 13:05:43  jalet
170# Internationalization continues...
171#
172# Revision 1.5  2003/02/08 22:39:46  jalet
173# --reset command line option added
174#
175# Revision 1.4  2003/02/08 09:59:59  jalet
176# Added preliminary base class for all storages
177#
178# Revision 1.3  2003/02/05 22:10:29  jalet
179# Typos
180#
181# Revision 1.2  2003/02/05 22:02:22  jalet
182# __import__ statement didn't work as expected
183#
184# Revision 1.1  2003/02/05 21:28:17  jalet
185# Initial import into CVS
186#
187#
188#
189
190class PyKotaStorageError(Exception):
191    """An exception for Quota Storage related stuff."""
192    def __init__(self, message = ""):
193        self.message = message
194        Exception.__init__(self, message)
195    def __repr__(self):
196        return self.message
197    __str__ = __repr__
198       
199class StorageObject :
200    """Object present in the Quota Storage."""
201    def __init__(self, parent) :
202        "Initialize minimal data."""
203        self.parent = parent
204        self.ident = None
205        self.Exists = 0
206       
207class StorageUser(StorageObject) :       
208    """User class."""
209    def __init__(self, parent, name) :
210        StorageObject.__init__(self, parent)
211        self.Name = name
212        self.LimitBy = None
213        self.AccountBalance = None
214        self.LifeTimePaid = None
215        self.Email = None
216       
217    def consumeAccountBalance(self, amount) :     
218        """Consumes an amount of money from the user's account balance."""
219        self.parent.decreaseUserAccountBalance(self, amount)
220        self.AccountBalance = float(self.AccountBalance or 0.0) - amount
221       
222    def setAccountBalance(self, balance, lifetimepaid) :   
223        """Sets the user's account balance in case he pays more money."""
224        self.parent.writeUserAccountBalance(self, balance, lifetimepaid)
225        self.AccountBalance = balance
226        self.LifeTimePaid = lifetimepaid
227       
228    def setLimitBy(self, limitby) :   
229        """Sets the user's limiting factor."""
230        try :
231            limitby = limitby.lower()
232        except AttributeError :   
233            limitby = "quota"
234        if limitby in ["quota", "balance"] :
235            self.parent.writeUserLimitBy(self, limitby)
236            self.LimitBy = limitby
237       
238    def delete(self) :   
239        """Deletes an user from the Quota Storage."""
240        self.parent.beginTransaction()
241        try :
242            self.parent.deleteUser(self)
243        except PyKotaStorageError, msg :   
244            self.parent.rollbackTransaction()
245            raise PyKotaStorageError, msg
246        else :   
247            self.parent.commitTransaction()
248       
249class StorageGroup(StorageObject) :       
250    """User class."""
251    def __init__(self, parent, name) :
252        StorageObject.__init__(self, parent)
253        self.Name = name
254        self.LimitBy = None
255        self.AccountBalance = None
256        self.LifeTimePaid = None
257       
258    def setLimitBy(self, limitby) :   
259        """Sets the user's limiting factor."""
260        try :
261            limitby = limitby.lower()
262        except AttributeError :   
263            limitby = "quota"
264        if limitby in ["quota", "balance"] :
265            self.parent.writeGroupLimitBy(self, limitby)
266            self.LimitBy = limitby
267       
268    def delete(self) :   
269        """Deletes a group from the Quota Storage."""
270        self.parent.beginTransaction()
271        try :
272            self.parent.deleteGroup(self)
273        except PyKotaStorageError, msg :   
274            self.parent.rollbackTransaction()
275            raise PyKotaStorageError, msg
276        else :   
277            self.parent.commitTransaction()
278       
279class StoragePrinter(StorageObject) :
280    """Printer class."""
281    def __init__(self, parent, name) :
282        StorageObject.__init__(self, parent)
283        self.Name = name
284        self.PricePerPage = None
285        self.PricePerJob = None
286       
287    def __getattr__(self, name) :   
288        """Delays data retrieval until it's really needed."""
289        if name == "LastJob" : 
290            self.LastJob = self.parent.getPrinterLastJob(self)
291            return self.LastJob
292        else :
293            raise AttributeError, name
294           
295    def addJobToHistory(self, jobid, user, pagecounter, action, jobsize=None, jobprice=None, filename=None, title=None, copies=None, options=None) :
296        """Adds a job to the printer's history."""
297        self.parent.writeJobNew(self, user, jobid, pagecounter, action, jobsize, jobprice, filename, title, copies, options)
298        # TODO : update LastJob object ? Probably not needed.
299       
300    def addPrinterToGroup(self, printer) :   
301        """Adds a printer to a printer group."""
302        if (printer not in self.parent.getParentPrinters(self)) and (printer.ident != self.ident) :
303            self.parent.writePrinterToGroup(self, printer)
304            # TODO : reset cached value for printer parents, or add new parent to cached value
305           
306    def delPrinterFromGroup(self, printer) :   
307        """Deletes a printer from a printer group."""
308        self.parent.removePrinterFromGroup(self, printer)
309        # TODO : reset cached value for printer parents, or add new parent to cached value
310       
311    def setPrices(self, priceperpage = None, priceperjob = None) :   
312        """Sets the printer's prices."""
313        if priceperpage is None :
314            priceperpage = self.PricePerPage
315        else :   
316            self.PricePerPage = float(priceperpage)
317        if priceperjob is None :   
318            priceperjob = self.PricePerJob
319        else :   
320            self.PricePerJob = float(priceperjob)
321        self.parent.writePrinterPrices(self)
322       
323    def delete(self) :   
324        """Deletes a printer from the Quota Storage."""
325        self.parent.beginTransaction()
326        try :
327            self.parent.deletePrinter(self)
328        except PyKotaStorageError, msg :   
329            self.parent.rollbackTransaction()
330            raise PyKotaStorageError, msg
331        else :   
332            self.parent.commitTransaction()
333       
334class StorageUserPQuota(StorageObject) :
335    """User Print Quota class."""
336    def __init__(self, parent, user, printer) :
337        StorageObject.__init__(self, parent)
338        self.User = user
339        self.Printer = printer
340        self.PageCounter = None
341        self.LifePageCounter = None
342        self.SoftLimit = None
343        self.HardLimit = None
344        self.DateLimit = None
345       
346    def __getattr__(self, name) :   
347        """Delays data retrieval until it's really needed."""
348        if name == "ParentPrintersUserPQuota" : 
349            self.ParentPrintersUserPQuota = (self.User.Exists and self.Printer.Exists and self.parent.getParentPrintersUserPQuota(self)) or []
350            return self.ParentPrintersUserPQuota
351        else :
352            raise AttributeError, name
353       
354    def setDateLimit(self, datelimit) :   
355        """Sets the date limit for this quota."""
356        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)
357        self.parent.writeUserPQuotaDateLimit(self, date)
358        self.DateLimit = date
359       
360    def setLimits(self, softlimit, hardlimit) :   
361        """Sets the soft and hard limit for this quota."""
362        self.parent.writeUserPQuotaLimits(self, softlimit, hardlimit)
363        self.SoftLimit = softlimit
364        self.HardLimit = hardlimit
365        self.DateLimit = None
366       
367    def reset(self) :   
368        """Resets page counter to 0."""
369        self.parent.writeUserPQuotaPagesCounters(self, 0, int(self.LifePageCounter or 0))
370        self.PageCounter = 0
371       
372    def computeJobPrice(self, jobsize) :   
373        """Computes the job price as the sum of all parent printers' prices + current printer's ones."""
374        totalprice = 0.0   
375        if jobsize :
376            for upq in [ self ] + self.ParentPrintersUserPQuota :
377                price = (float(upq.Printer.PricePerPage or 0.0) * jobsize) + float(upq.Printer.PricePerJob or 0.0)
378                totalprice += price
379        return totalprice   
380           
381    def increasePagesUsage(self, jobsize) :
382        """Increase the value of used pages and money."""
383        jobprice = self.computeJobPrice(jobsize)
384        if jobsize :
385            self.parent.beginTransaction()
386            try :
387                if jobprice :
388                    self.User.consumeAccountBalance(jobprice)
389                for upq in [ self ] + self.ParentPrintersUserPQuota :
390                    self.parent.increaseUserPQuotaPagesCounters(upq, jobsize)
391                    upq.PageCounter = int(upq.PageCounter or 0) + jobsize
392                    upq.LifePageCounter = int(upq.LifePageCounter or 0) + jobsize
393            except PyKotaStorageError, msg :   
394                self.parent.rollbackTransaction()
395                raise PyKotaStorageError, msg
396            else :   
397                self.parent.commitTransaction()
398        return jobprice
399       
400class StorageGroupPQuota(StorageObject) :
401    """Group Print Quota class."""
402    def __init__(self, parent, group, printer) :
403        StorageObject.__init__(self, parent)
404        self.Group = group
405        self.Printer = printer
406        self.PageCounter = None
407        self.LifePageCounter = None
408        self.SoftLimit = None
409        self.HardLimit = None
410        self.DateLimit = None
411       
412    def __getattr__(self, name) :   
413        """Delays data retrieval until it's really needed."""
414        if name == "ParentPrintersGroupPQuota" : 
415            self.ParentPrintersGroupPQuota = (self.Group.Exists and self.Printer.Exists and self.parent.getParentPrintersGroupPQuota(self)) or []
416            return self.ParentPrintersGroupPQuota
417        else :
418            raise AttributeError, name
419       
420    def setDateLimit(self, datelimit) :   
421        """Sets the date limit for this quota."""
422        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)
423        self.parent.writeGroupPQuotaDateLimit(self, date)
424        self.DateLimit = date
425       
426    def setLimits(self, softlimit, hardlimit) :   
427        """Sets the soft and hard limit for this quota."""
428        self.parent.writeGroupPQuotaLimits(self, softlimit, hardlimit)
429        self.SoftLimit = softlimit
430        self.HardLimit = hardlimit
431        self.DateLimit = None
432       
433class StorageJob(StorageObject) :
434    """Printer's Last Job class."""
435    def __init__(self, parent) :
436        StorageObject.__init__(self, parent)
437        self.UserName = None
438        self.PrinterName = None
439        self.JobId = None
440        self.PrinterPageCounter = None
441        self.JobSize = None
442        self.JobAction = None
443        self.JobDate = None
444        self.JobPrice = None
445        self.JobFileName = None
446        self.JobTitle = None
447        self.JobCopies = None
448        self.JobOptions = None
449       
450    def __getattr__(self, name) :   
451        """Delays data retrieval until it's really needed."""
452        if name == "User" : 
453            self.User = self.parent.getUser(self.UserName)
454            return self.User
455        elif name == "Printer" :   
456            self.Printer = self.parent.getPrinter(self.PrinterName)
457            return self.Printer
458        else :
459            raise AttributeError, name
460       
461class StorageLastJob(StorageJob) :
462    """Printer's Last Job class."""
463    def __init__(self, parent, printer) :
464        StorageJob.__init__(self, parent)
465        self.PrinterName = printer.Name # not needed
466        self.Printer = printer
467       
468    def __getattr__(self, name) :   
469        """Delays data retrieval until it's really needed."""
470        if name == "User" : 
471            self.User = self.parent.getUser(self.UserName)
472            return self.User
473        else :   
474            raise AttributeError, name
475       
476    def setSize(self, userpquota, jobsize) :
477        """Sets the last job's size."""
478        jobprice = userpquota.computeJobPrice(jobsize)
479        self.parent.writeLastJobSize(self, jobsize, jobprice)
480        self.JobSize = jobsize
481        self.JobPrice = jobprice
482        return jobprice
483       
484class BaseStorage :
485    def __init__(self, pykotatool) :
486        """Opens the LDAP connection."""
487        # raise PyKotaStorageError, "Sorry, the LDAP backend for PyKota is not yet implemented !"
488        self.closed = 1
489        self.tool = pykotatool
490        self.usecache = pykotatool.config.getCaching()
491        self.disablehistory = pykotatool.config.getDisableHistory()
492        if self.usecache :
493            self.tool.logdebug("Caching enabled.")
494            self.caches = { "USERS" : {}, "GROUPS" : {}, "PRINTERS" : {}, "USERPQUOTAS" : {}, "GROUPPQUOTAS" : {}, "JOBS" : {}, "LASTJOBS" : {} }
495       
496    def close(self) :   
497        """Must be overriden in children classes."""
498        raise RuntimeError, "BaseStorage.close() must be overriden !"
499       
500    def __del__(self) :       
501        """Ensures that the database connection is closed."""
502        self.close()
503       
504    def getFromCache(self, cachetype, key) :
505        """Tries to extract something from the cache."""
506        if self.usecache :
507            entry = self.caches[cachetype].get(key)
508            if entry is not None :
509                self.tool.logdebug("Cache hit (%s->%s)" % (cachetype, key))
510            else :   
511                self.tool.logdebug("Cache miss (%s->%s)" % (cachetype, key))
512            return entry   
513           
514    def cacheEntry(self, cachetype, key, value) :       
515        """Puts an entry in the cache."""
516        if self.usecache and getattr(value, "Exists", 0) :
517            self.caches[cachetype][key] = value
518            self.tool.logdebug("Cache store (%s->%s)" % (cachetype, key))
519           
520    def getUser(self, username) :       
521        """Returns the user from cache."""
522        user = self.getFromCache("USERS", username)
523        if user is None :
524            user = self.getUserFromBackend(username)
525            self.cacheEntry("USERS", username, user)
526        return user   
527       
528    def getGroup(self, groupname) :       
529        """Returns the group from cache."""
530        group = self.getFromCache("GROUPS", groupname)
531        if group is None :
532            group = self.getGroupFromBackend(groupname)
533            self.cacheEntry("GROUPS", groupname, group)
534        return group   
535       
536    def getPrinter(self, printername) :       
537        """Returns the printer from cache."""
538        printer = self.getFromCache("PRINTERS", printername)
539        if printer is None :
540            printer = self.getPrinterFromBackend(printername)
541            self.cacheEntry("PRINTERS", printername, printer)
542        return printer   
543       
544    def getUserPQuota(self, user, printer) :       
545        """Returns the user quota information from cache."""
546        useratprinter = "%s@%s" % (user.Name, printer.Name)
547        upquota = self.getFromCache("USERPQUOTAS", useratprinter)
548        if upquota is None :
549            upquota = self.getUserPQuotaFromBackend(user, printer)
550            self.cacheEntry("USERPQUOTAS", useratprinter, upquota)
551        return upquota   
552       
553    def getGroupPQuota(self, group, printer) :       
554        """Returns the group quota information from cache."""
555        groupatprinter = "%s@%s" % (group.Name, printer.Name)
556        gpquota = self.getFromCache("GROUPPQUOTAS", groupatprinter)
557        if gpquota is None :
558            gpquota = self.getGroupPQuotaFromBackend(group, printer)
559            self.cacheEntry("GROUPPQUOTAS", groupatprinter, gpquota)
560        return gpquota   
561       
562    def getPrinterLastJob(self, printer) :       
563        """Extracts last job information for a given printer from cache."""
564        lastjob = self.getFromCache("LASTJOBS", printer.Name)
565        if lastjob is None :
566            lastjob = self.getPrinterLastJobFromBackend(printer)
567            self.cacheEntry("LASTJOBS", printer.Name, lastjob)
568        return lastjob   
569       
570    def getParentPrinters(self, printer) :   
571        """Extracts parent printers information for a given printer from cache."""
572        if self.usecache :
573            if not hasattr(printer, "Parents") :
574                self.tool.logdebug("Cache miss (%s->Parents)" % printer.Name)
575                printer.Parents = self.getParentPrintersFromBackend(printer)
576                self.tool.logdebug("Cache store (%s->Parents)" % printer.Name)
577            else :
578                self.tool.logdebug("Cache hit (%s->Parents)" % printer.Name)
579        else :       
580            printer.Parents = self.getParentPrintersFromBackend(printer)
581        for parent in printer.Parents[:] :   
582            printer.Parents.extend(self.getParentPrinters(parent))
583        uniquedic = {}   
584        for parent in printer.Parents :
585            uniquedic[parent.Name] = parent
586        printer.Parents = uniquedic.values()   
587        return printer.Parents
588       
589    def getGroupMembers(self, group) :       
590        """Returns the group's members list from in-group cache."""
591        if self.usecache :
592            if not hasattr(group, "Members") :
593                self.tool.logdebug("Cache miss (%s->Members)" % group.Name)
594                group.Members = self.getGroupMembersFromBackend(group)
595                self.tool.logdebug("Cache store (%s->Members)" % group.Name)
596            else :
597                self.tool.logdebug("Cache hit (%s->Members)" % group.Name)
598        else :       
599            group.Members = self.getGroupMembersFromBackend(group)
600        return group.Members   
601       
602    def getUserGroups(self, user) :       
603        """Returns the user's groups list from in-user cache."""
604        if self.usecache :
605            if not hasattr(user, "Groups") :
606                self.tool.logdebug("Cache miss (%s->Groups)" % user.Name)
607                user.Groups = self.getUserGroupsFromBackend(user)
608                self.tool.logdebug("Cache store (%s->Groups)" % user.Name)
609            else :
610                self.tool.logdebug("Cache hit (%s->Groups)" % user.Name)
611        else :       
612            user.Groups = self.getUserGroupsFromBackend(user)
613        return user.Groups   
614       
615    def getParentPrintersUserPQuota(self, userpquota) :     
616        """Returns all user print quota on the printer and all its parents recursively."""
617        upquotas = [ ]
618        for printer in self.getParentPrinters(userpquota.Printer) :
619            upquotas.append(self.getUserPQuota(userpquota.User, printer))
620        return upquotas       
621       
622    def getParentPrintersGroupPQuota(self, grouppquota) :     
623        """Returns all group print quota on the printer and all its parents recursively."""
624        gpquotas = [ ]
625        for printer in self.getParentPrinters(grouppquota.Printer) :
626            gpquotas.append(self.getGroupPQuota(grouppquota.Group, printer))
627        return gpquotas       
628       
629def openConnection(pykotatool) :
630    """Returns a connection handle to the appropriate Quota Storage Database."""
631    backendinfo = pykotatool.config.getStorageBackend()
632    backend = backendinfo["storagebackend"]
633    try :
634        exec "from pykota.storages import %s as storagebackend" % backend.lower()
635    except ImportError :
636        raise PyKotaStorageError, _("Unsupported quota storage backend %s") % backend
637    else :   
638        host = backendinfo["storageserver"]
639        database = backendinfo["storagename"]
640        admin = backendinfo["storageadmin"] or backendinfo["storageuser"]
641        adminpw = backendinfo["storageadminpw"] or backendinfo["storageuserpw"]
642        return storagebackend.Storage(pykotatool, host, database, admin, adminpw)
Note: See TracBrowser for help on using the browser.