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

Revision 2450, 31.6 kB (checked in by jerome, 19 years ago)

Now deleted entries are flushed from the cache.
Modified entries are kept in the cache since we modify the attributes
by software anyway.

  • 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20#
21# $Id$
22#
23#
24
25from mx import DateTime
26
27class PyKotaStorageError(Exception):
28    """An exception for Quota Storage related stuff."""
29    def __init__(self, message = ""):
30        self.message = message
31        Exception.__init__(self, message)
32    def __repr__(self):
33        return self.message
34    __str__ = __repr__
35       
36class StorageObject :
37    """Object present in the Quota Storage."""
38    def __init__(self, parent) :
39        "Initialize minimal data."""
40        self.parent = parent
41        self.ident = None
42        self.Exists = 0
43       
44class StorageUser(StorageObject) :       
45    """User class."""
46    def __init__(self, parent, name) :
47        StorageObject.__init__(self, parent)
48        self.Name = name
49        self.LimitBy = None
50        self.AccountBalance = None
51        self.LifeTimePaid = None
52        self.Email = None
53        self.OverCharge = 1.0
54        self.Payments = [] # TODO : maybe handle this smartly for SQL, for now just don't retrieve them
55       
56    def consumeAccountBalance(self, amount) :     
57        """Consumes an amount of money from the user's account balance."""
58        self.parent.decreaseUserAccountBalance(self, amount)
59        self.AccountBalance = float(self.AccountBalance or 0.0) - amount
60       
61    def setAccountBalance(self, balance, lifetimepaid) :   
62        """Sets the user's account balance in case he pays more money."""
63        diff = float(lifetimepaid or 0.0) - float(self.LifeTimePaid or 0.0)
64        self.parent.beginTransaction()
65        try :
66            self.parent.writeUserAccountBalance(self, balance, lifetimepaid)
67            self.parent.writeNewPayment(self, diff)
68        except PyKotaStorageError, msg :   
69            self.parent.rollbackTransaction()
70            raise PyKotaStorageError, msg
71        else :   
72            self.parent.commitTransaction()
73            self.AccountBalance = balance
74            self.LifeTimePaid = lifetimepaid
75       
76    def setLimitBy(self, limitby) :   
77        """Sets the user's limiting factor."""
78        try :
79            limitby = limitby.lower()
80        except AttributeError :   
81            limitby = "quota"
82        if limitby in ["quota", "balance", "quota-then-balance", "balance-then-quota"] :
83            self.parent.writeUserLimitBy(self, limitby)
84            self.LimitBy = limitby
85       
86    def setOverChargeFactor(self, factor) :   
87        """Sets the user's overcharging coefficient."""
88        self.parent.writeUserOverCharge(self, factor)
89        self.OverCharge = factor
90       
91    def delete(self) :   
92        """Deletes an user from the Quota Storage."""
93        self.parent.beginTransaction()
94        try :
95            self.parent.deleteUser(self)
96        except PyKotaStorageError, msg :   
97            self.parent.rollbackTransaction()
98            raise PyKotaStorageError, msg
99        else :   
100            self.parent.commitTransaction()
101            self.parent.flushEntry("USERS", self.Name)
102            self.Exists = 0
103       
104class StorageGroup(StorageObject) :       
105    """User class."""
106    def __init__(self, parent, name) :
107        StorageObject.__init__(self, parent)
108        self.Name = name
109        self.LimitBy = None
110        self.AccountBalance = None
111        self.LifeTimePaid = None
112       
113    def setLimitBy(self, limitby) :   
114        """Sets the user's limiting factor."""
115        try :
116            limitby = limitby.lower()
117        except AttributeError :   
118            limitby = "quota"
119        if limitby in ["quota", "balance"] :
120            self.parent.writeGroupLimitBy(self, limitby)
121            self.LimitBy = limitby
122       
123    def delete(self) :   
124        """Deletes a group from the Quota Storage."""
125        self.parent.beginTransaction()
126        try :
127            self.parent.deleteGroup(self)
128        except PyKotaStorageError, msg :   
129            self.parent.rollbackTransaction()
130            raise PyKotaStorageError, msg
131        else :   
132            self.parent.commitTransaction()
133            self.parent.flushEntry("GROUPS", self.Name)
134            self.Exists = 0
135       
136class StoragePrinter(StorageObject) :
137    """Printer class."""
138    def __init__(self, parent, name) :
139        StorageObject.__init__(self, parent)
140        self.Name = name
141        self.PricePerPage = None
142        self.PricePerJob = None
143        self.Description = None
144        self.Coefficients = None
145       
146    def __getattr__(self, name) :   
147        """Delays data retrieval until it's really needed."""
148        if name == "LastJob" : 
149            self.LastJob = self.parent.getPrinterLastJob(self)
150            return self.LastJob
151        else :
152            raise AttributeError, name
153           
154    def addJobToHistory(self, jobid, user, pagecounter, action, jobsize=None, jobprice=None, filename=None, title=None, copies=None, options=None, clienthost=None, jobsizebytes=None, jobmd5sum=None, jobpages=None, jobbilling=None) :
155        """Adds a job to the printer's history."""
156        self.parent.writeJobNew(self, user, jobid, pagecounter, action, jobsize, jobprice, filename, title, copies, options, clienthost, jobsizebytes, jobmd5sum, jobpages, jobbilling)
157        # TODO : update LastJob object ? Probably not needed.
158       
159    def addPrinterToGroup(self, printer) :   
160        """Adds a printer to a printer group."""
161        if (printer not in self.parent.getParentPrinters(self)) and (printer.ident != self.ident) :
162            self.parent.writePrinterToGroup(self, printer)
163            # TODO : reset cached value for printer parents, or add new parent to cached value
164           
165    def delPrinterFromGroup(self, printer) :   
166        """Deletes a printer from a printer group."""
167        self.parent.removePrinterFromGroup(self, printer)
168        # TODO : reset cached value for printer parents, or add new parent to cached value
169       
170    def setPrices(self, priceperpage = None, priceperjob = None) :   
171        """Sets the printer's prices."""
172        if priceperpage is None :
173            priceperpage = self.PricePerPage or 0.0
174        else :   
175            self.PricePerPage = float(priceperpage)
176        if priceperjob is None :   
177            priceperjob = self.PricePerJob or 0.0
178        else :   
179            self.PricePerJob = float(priceperjob)
180        self.parent.writePrinterPrices(self)
181       
182    def setDescription(self, description=None) :
183        """Sets the printer's description."""
184        if description is None :
185            description = self.Description
186        else :   
187            self.Description = str(description)
188        self.parent.writePrinterDescription(self)
189       
190    def delete(self) :   
191        """Deletes a printer from the Quota Storage."""
192        self.parent.beginTransaction()
193        try :
194            self.parent.deletePrinter(self)
195        except PyKotaStorageError, msg :   
196            self.parent.rollbackTransaction()
197            raise PyKotaStorageError, msg
198        else :   
199            self.parent.commitTransaction()
200            self.parent.flushEntry("PRINTERS", self.Name)
201            self.Exists = 0   
202       
203class StorageUserPQuota(StorageObject) :
204    """User Print Quota class."""
205    def __init__(self, parent, user, printer) :
206        StorageObject.__init__(self, parent)
207        self.User = user
208        self.Printer = printer
209        self.PageCounter = None
210        self.LifePageCounter = None
211        self.SoftLimit = None
212        self.HardLimit = None
213        self.DateLimit = None
214        self.WarnCount = None
215       
216    def __getattr__(self, name) :   
217        """Delays data retrieval until it's really needed."""
218        if name == "ParentPrintersUserPQuota" : 
219            self.ParentPrintersUserPQuota = (self.User.Exists and self.Printer.Exists and self.parent.getParentPrintersUserPQuota(self)) or []
220            return self.ParentPrintersUserPQuota
221        else :
222            raise AttributeError, name
223       
224    def setDateLimit(self, datelimit) :   
225        """Sets the date limit for this quota."""
226        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)
227        self.parent.writeUserPQuotaDateLimit(self, date)
228        self.DateLimit = date
229       
230    def setLimits(self, softlimit, hardlimit) :   
231        """Sets the soft and hard limit for this quota."""
232        self.parent.writeUserPQuotaLimits(self, softlimit, hardlimit)
233        self.SoftLimit = softlimit
234        self.HardLimit = hardlimit
235        self.DateLimit = None
236        self.WarnCount = 0
237       
238    def setUsage(self, used) :
239        """Sets the PageCounter and LifePageCounter to used, or if used is + or - prefixed, changes the values of {Life,}PageCounter by that amount."""
240        vused = int(used)
241        if used.startswith("+") or used.startswith("-") :
242            self.parent.beginTransaction()
243            try :
244                self.parent.increaseUserPQuotaPagesCounters(self, vused)
245                self.parent.writeUserPQuotaDateLimit(self, None)
246                self.parent.writeUserPQuotaWarnCount(self, 0)
247            except PyKotaStorageError, msg :   
248                self.parent.rollbackTransaction()
249                raise PyKotaStorageError, msg
250            else :
251                self.parent.commitTransaction()
252            self.PageCounter += vused
253            self.LifePageCounter += vused
254        else :
255            self.parent.writeUserPQuotaPagesCounters(self, vused, vused)
256            self.PageCounter = self.LifePageCounter = vused
257        self.DateLimit = None
258        self.WarnCount = 0
259
260    def incDenyBannerCounter(self) :
261        """Increment the deny banner counter for this user quota."""
262        self.parent.increaseUserPQuotaWarnCount(self)
263        self.WarnCount = (self.WarnCount or 0) + 1
264       
265    def resetDenyBannerCounter(self) :
266        """Resets the deny banner counter for this user quota."""
267        self.parent.writeUserPQuotaWarnCount(self, 0)
268        self.WarnCount = 0
269       
270    def reset(self) :   
271        """Resets page counter to 0."""
272        self.parent.writeUserPQuotaPagesCounters(self, 0, int(self.LifePageCounter or 0))
273        self.PageCounter = 0
274        self.DateLimit = None
275       
276    def hardreset(self) :   
277        """Resets actual and life time page counters to 0."""
278        self.parent.writeUserPQuotaPagesCounters(self, 0, 0)
279        self.PageCounter = self.LifePageCounter = 0
280        self.DateLimit = None
281       
282    def computeJobPrice(self, jobsize) :   
283        """Computes the job price as the sum of all parent printers' prices + current printer's ones."""
284        totalprice = 0.0   
285        if jobsize :
286            if self.User.OverCharge != 0.0 :    # optimization, but TODO : beware of rounding errors
287                for upq in [ self ] + self.ParentPrintersUserPQuota :
288                    price = (float(upq.Printer.PricePerPage or 0.0) * jobsize) + float(upq.Printer.PricePerJob or 0.0)
289                    totalprice += price
290        if self.User.OverCharge != 1.0 : # TODO : beware of rounding errors
291            overcharged = totalprice * self.User.OverCharge       
292            self.parent.tool.printInfo("Overcharging %s by a factor of %s ===> User %s will be charged for %s units." % (totalprice, self.User.OverCharge, self.User.Name, overcharged))
293            return overcharged
294        else :   
295            return totalprice
296           
297    def increasePagesUsage(self, jobsize) :
298        """Increase the value of used pages and money."""
299        jobprice = self.computeJobPrice(jobsize)
300        if jobsize :
301            if jobprice :
302                self.User.consumeAccountBalance(jobprice)
303            for upq in [ self ] + self.ParentPrintersUserPQuota :
304                self.parent.increaseUserPQuotaPagesCounters(upq, jobsize)
305                upq.PageCounter = int(upq.PageCounter or 0) + jobsize
306                upq.LifePageCounter = int(upq.LifePageCounter or 0) + jobsize
307        return jobprice
308       
309class StorageGroupPQuota(StorageObject) :
310    """Group Print Quota class."""
311    def __init__(self, parent, group, printer) :
312        StorageObject.__init__(self, parent)
313        self.Group = group
314        self.Printer = printer
315        self.PageCounter = None
316        self.LifePageCounter = None
317        self.SoftLimit = None
318        self.HardLimit = None
319        self.DateLimit = None
320       
321    def __getattr__(self, name) :   
322        """Delays data retrieval until it's really needed."""
323        if name == "ParentPrintersGroupPQuota" : 
324            self.ParentPrintersGroupPQuota = (self.Group.Exists and self.Printer.Exists and self.parent.getParentPrintersGroupPQuota(self)) or []
325            return self.ParentPrintersGroupPQuota
326        else :
327            raise AttributeError, name
328       
329    def reset(self) :   
330        """Resets page counter to 0."""
331        self.parent.beginTransaction()
332        try :
333            for user in self.parent.getGroupMembers(self.Group) :
334                uq = self.parent.getUserPQuota(user, self.Printer)
335                uq.reset()
336            self.parent.writeGroupPQuotaDateLimit(self, None)
337        except PyKotaStorageError, msg :   
338            self.parent.rollbackTransaction()
339            raise PyKotaStorageError, msg
340        else :   
341            self.parent.commitTransaction()
342        self.PageCounter = 0
343        self.DateLimit = None
344       
345    def hardreset(self) :   
346        """Resets actual and life time page counters to 0."""
347        self.parent.beginTransaction()
348        try :
349            for user in self.parent.getGroupMembers(self.Group) :
350                uq = self.parent.getUserPQuota(user, self.Printer)
351                uq.hardreset()
352            self.parent.writeGroupPQuotaDateLimit(self, None)
353        except PyKotaStorageError, msg :   
354            self.parent.rollbackTransaction()
355            raise PyKotaStorageError, msg
356        else :   
357            self.parent.commitTransaction()
358        self.PageCounter = self.LifePageCounter = 0
359        self.DateLimit = None
360       
361    def setDateLimit(self, datelimit) :   
362        """Sets the date limit for this quota."""
363        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, \
364                                                  datelimit.month, \
365                                                  datelimit.day, \
366                                                  datelimit.hour, \
367                                                  datelimit.minute, \
368                                                  datelimit.second)
369        self.parent.writeGroupPQuotaDateLimit(self, date)
370        self.DateLimit = date
371       
372    def setLimits(self, softlimit, hardlimit) :   
373        """Sets the soft and hard limit for this quota."""
374        self.parent.writeGroupPQuotaLimits(self, softlimit, hardlimit)
375        self.SoftLimit = softlimit
376        self.HardLimit = hardlimit
377        self.DateLimit = None
378       
379class StorageJob(StorageObject) :
380    """Printer's Job class."""
381    def __init__(self, parent) :
382        StorageObject.__init__(self, parent)
383        self.UserName = None
384        self.PrinterName = None
385        self.JobId = None
386        self.PrinterPageCounter = None
387        self.JobSizeBytes = None
388        self.JobSize = None
389        self.JobAction = None
390        self.JobDate = None
391        self.JobPrice = None
392        self.JobFileName = None
393        self.JobTitle = None
394        self.JobCopies = None
395        self.JobOptions = None
396        self.JobHostName = None
397        self.JobMD5Sum = None
398        self.JobPages = None
399        self.JobBillingCode = None
400       
401    def __getattr__(self, name) :   
402        """Delays data retrieval until it's really needed."""
403        if name == "User" : 
404            self.User = self.parent.getUser(self.UserName)
405            return self.User
406        elif name == "Printer" :   
407            self.Printer = self.parent.getPrinter(self.PrinterName)
408            return self.Printer
409        else :
410            raise AttributeError, name
411       
412class StorageLastJob(StorageJob) :
413    """Printer's Last Job class."""
414    def __init__(self, parent, printer) :
415        StorageJob.__init__(self, parent)
416        self.PrinterName = printer.Name # not needed
417        self.Printer = printer
418       
419class StorageBillingCode(StorageObject) :
420    """Billing code class."""
421    def __init__(self, parent, name) :
422        StorageObject.__init__(self, parent)
423        self.BillingCode = name
424        self.Description = None
425        self.PageCounter = None
426        self.Balance = None
427       
428    def delete(self) :   
429        """Deletes the billing code from the database."""
430        self.parent.deleteBillingCode(self)
431        self.parent.flushEntry("BILLINGCODES", self.BillingCode)
432        self.Exists = 0
433       
434    def reset(self, balance=0.0, pagecounter=0) :   
435        """Resets the pagecounter and balance for this billing code."""
436        self.parent.setBillingCodeValues(self, pagecounter, balance)
437        self.Balance = balance
438        self.PageCounter = pagecounter
439       
440    def setDescription(self, description=None) :
441        """Modifies the description for this billing code."""
442        if description is None :
443            description = self.Description
444        else :   
445            self.Description = str(description)
446        self.parent.writeBillingCodeDescription(self)
447       
448    def consume(self, pages, price) :
449        """Consumes some pages and credits for this billing code."""
450        if pages :
451           self.parent.consumeBillingCode(self, pages, price)
452           self.PageCounter += pages
453           self.Balance -= price
454       
455class BaseStorage :
456    def __init__(self, pykotatool) :
457        """Opens the storage connection."""
458        self.closed = 1
459        self.tool = pykotatool
460        self.usecache = pykotatool.config.getCaching()
461        self.disablehistory = pykotatool.config.getDisableHistory()
462        self.privacy = pykotatool.config.getPrivacy()
463        if self.privacy :
464            pykotatool.logdebug("Jobs' title, filename and options will be hidden because of privacy concerns.")
465        if self.usecache :
466            self.tool.logdebug("Caching enabled.")
467            self.caches = { "USERS" : {}, \
468                            "GROUPS" : {}, \
469                            "PRINTERS" : {}, \
470                            "USERPQUOTAS" : {}, \
471                            "GROUPPQUOTAS" : {}, \
472                            "JOBS" : {}, \
473                            "LASTJOBS" : {}, \
474                            "BILLINGCODES" : {} }
475       
476    def close(self) :   
477        """Must be overriden in children classes."""
478        raise RuntimeError, "BaseStorage.close() must be overriden !"
479       
480    def __del__(self) :       
481        """Ensures that the database connection is closed."""
482        self.close()
483       
484    def getFromCache(self, cachetype, key) :
485        """Tries to extract something from the cache."""
486        if self.usecache :
487            entry = self.caches[cachetype].get(key)
488            if entry is not None :
489                self.tool.logdebug("Cache hit (%s->%s)" % (cachetype, key))
490            else :   
491                self.tool.logdebug("Cache miss (%s->%s)" % (cachetype, key))
492            return entry   
493           
494    def cacheEntry(self, cachetype, key, value) :       
495        """Puts an entry in the cache."""
496        if self.usecache and getattr(value, "Exists", 0) :
497            self.caches[cachetype][key] = value
498            self.tool.logdebug("Cache store (%s->%s)" % (cachetype, key))
499           
500    def flushEntry(self, cachetype, key) :       
501        """Removes an entry from the cache."""
502        if self.usecache :
503            try :
504                del self.caches[cachetype][key]
505            except KeyError :   
506                pass
507            else :   
508                self.tool.logdebug("Cache flush (%s->%s)" % (cachetype, key))
509           
510    def getUser(self, username) :       
511        """Returns the user from cache."""
512        user = self.getFromCache("USERS", username)
513        if user is None :
514            user = self.getUserFromBackend(username)
515            self.cacheEntry("USERS", username, user)
516        return user   
517       
518    def getGroup(self, groupname) :       
519        """Returns the group from cache."""
520        group = self.getFromCache("GROUPS", groupname)
521        if group is None :
522            group = self.getGroupFromBackend(groupname)
523            self.cacheEntry("GROUPS", groupname, group)
524        return group   
525       
526    def getPrinter(self, printername) :       
527        """Returns the printer from cache."""
528        printer = self.getFromCache("PRINTERS", printername)
529        if printer is None :
530            printer = self.getPrinterFromBackend(printername)
531            self.cacheEntry("PRINTERS", printername, printer)
532        return printer   
533       
534    def getUserPQuota(self, user, printer) :       
535        """Returns the user quota information from cache."""
536        useratprinter = "%s@%s" % (user.Name, printer.Name)
537        upquota = self.getFromCache("USERPQUOTAS", useratprinter)
538        if upquota is None :
539            upquota = self.getUserPQuotaFromBackend(user, printer)
540            self.cacheEntry("USERPQUOTAS", useratprinter, upquota)
541        return upquota   
542       
543    def getGroupPQuota(self, group, printer) :       
544        """Returns the group quota information from cache."""
545        groupatprinter = "%s@%s" % (group.Name, printer.Name)
546        gpquota = self.getFromCache("GROUPPQUOTAS", groupatprinter)
547        if gpquota is None :
548            gpquota = self.getGroupPQuotaFromBackend(group, printer)
549            self.cacheEntry("GROUPPQUOTAS", groupatprinter, gpquota)
550        return gpquota   
551       
552    def getPrinterLastJob(self, printer) :       
553        """Extracts last job information for a given printer from cache."""
554        lastjob = self.getFromCache("LASTJOBS", printer.Name)
555        if lastjob is None :
556            lastjob = self.getPrinterLastJobFromBackend(printer)
557            self.cacheEntry("LASTJOBS", printer.Name, lastjob)
558        return lastjob   
559       
560    def getBillingCode(self, label) :       
561        """Returns the user from cache."""
562        code = self.getFromCache("BILLINGCODES", label)
563        if code is None :
564            code = self.getBillingCodeFromBackend(label)
565            self.cacheEntry("BILLINGCODES", label, code)
566        return code
567       
568    def getParentPrinters(self, printer) :   
569        """Extracts parent printers information for a given printer from cache."""
570        if self.usecache :
571            if not hasattr(printer, "Parents") :
572                self.tool.logdebug("Cache miss (%s->Parents)" % printer.Name)
573                printer.Parents = self.getParentPrintersFromBackend(printer)
574                self.tool.logdebug("Cache store (%s->Parents)" % printer.Name)
575            else :
576                self.tool.logdebug("Cache hit (%s->Parents)" % printer.Name)
577        else :       
578            printer.Parents = self.getParentPrintersFromBackend(printer)
579        for parent in printer.Parents[:] :   
580            printer.Parents.extend(self.getParentPrinters(parent))
581        uniquedic = {}   
582        for parent in printer.Parents :
583            uniquedic[parent.Name] = parent
584        printer.Parents = uniquedic.values()   
585        return printer.Parents
586       
587    def getGroupMembers(self, group) :       
588        """Returns the group's members list from in-group cache."""
589        if self.usecache :
590            if not hasattr(group, "Members") :
591                self.tool.logdebug("Cache miss (%s->Members)" % group.Name)
592                group.Members = self.getGroupMembersFromBackend(group)
593                self.tool.logdebug("Cache store (%s->Members)" % group.Name)
594            else :
595                self.tool.logdebug("Cache hit (%s->Members)" % group.Name)
596        else :       
597            group.Members = self.getGroupMembersFromBackend(group)
598        return group.Members   
599       
600    def getUserGroups(self, user) :       
601        """Returns the user's groups list from in-user cache."""
602        if self.usecache :
603            if not hasattr(user, "Groups") :
604                self.tool.logdebug("Cache miss (%s->Groups)" % user.Name)
605                user.Groups = self.getUserGroupsFromBackend(user)
606                self.tool.logdebug("Cache store (%s->Groups)" % user.Name)
607            else :
608                self.tool.logdebug("Cache hit (%s->Groups)" % user.Name)
609        else :       
610            user.Groups = self.getUserGroupsFromBackend(user)
611        return user.Groups   
612       
613    def getParentPrintersUserPQuota(self, userpquota) :     
614        """Returns all user print quota on the printer and all its parents recursively."""
615        upquotas = [ ]
616        for printer in self.getParentPrinters(userpquota.Printer) :
617            upq = self.getUserPQuota(userpquota.User, printer)
618            if upq.Exists :
619                upquotas.append(upq)
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            gpq = self.getGroupPQuota(grouppquota.Group, printer)
627            if gpq.Exists :
628                gpquotas.append(gpq)
629        return gpquotas       
630       
631    def databaseToUserCharset(self, text) :
632        """Converts from database format (UTF-8) to user's charset."""
633        if text is not None :
634            try :
635                return unicode(text, "UTF-8").encode(self.tool.getCharset()) 
636            except UnicodeError :   
637                try :
638                    # Incorrect locale settings ?
639                    return unicode(text, "UTF-8").encode("ISO-8859-15") 
640                except UnicodeError :   
641                    pass
642        return text
643       
644    def userCharsetToDatabase(self, text) :
645        """Converts from user's charset to database format (UTF-8)."""
646        if text is not None :
647            try :
648                return unicode(text, self.tool.getCharset()).encode("UTF-8") 
649            except UnicodeError :   
650                try :
651                    # Incorrect locale settings ?
652                    return unicode(text, "ISO-8859-15").encode("UTF-8") 
653                except UnicodeError :   
654                    pass
655        return text
656       
657    def cleanDates(self, startdate, enddate) :   
658        """Clean the dates to create a correct filter."""
659        if startdate is None :
660            startdate = enddate
661        if enddate is None :   
662            enddate = startdate
663        if (startdate is None) and (enddate is None) :   
664            return (None, None)
665           
666        now = DateTime.now()   
667        nameddates = ('yesterday', 'today', 'now', 'tomorrow')
668        datedict = { "start" : startdate.lower(), "end" : enddate.lower() }   
669        for limit in datedict.keys() :
670            dateval = datedict[limit]
671            for name in nameddates :
672                if dateval.startswith(name) :
673                    try :
674                        offset = int(dateval[len(name):])
675                    except :   
676                        offset = 0
677                    dateval = dateval[:len(name)]   
678                    if limit == "start" :
679                        if dateval == "yesterday" :
680                            dateval = (now - 1 + offset).Format("%Y%m%d000000")
681                        elif dateval == "today" :
682                            dateval = (now + offset).Format("%Y%m%d000000")
683                        elif dateval == "now" :
684                            dateval = (now + offset).Format("%Y%m%d%H%M%S")
685                        else : # tomorrow
686                            dateval = (now + 1 + offset).Format("%Y%m%d000000")
687                    else :
688                        if dateval == "yesterday" :
689                            dateval = (now - 1 + offset).Format("%Y%m%d235959")
690                        elif dateval == "today" :
691                            dateval = (now + offset).Format("%Y%m%d235959")
692                        elif dateval == "now" :
693                            dateval = (now + offset).Format("%Y%m%d%H%M%S")
694                        else : # tomorrow
695                            dateval = (now + 1 + offset).Format("%Y%m%d235959")
696                    break
697                   
698            if not dateval.isdigit() :
699                dateval = None
700            else :   
701                lgdateval = len(dateval)
702                if lgdateval == 4 :
703                    if limit == "start" : 
704                        dateval = "%s0101 00:00:00" % dateval
705                    else : 
706                        dateval = "%s1231 23:59:59" % dateval
707                elif lgdateval == 6 :
708                    if limit == "start" : 
709                        dateval = "%s01 00:00:00" % dateval
710                    else : 
711                        mxdate = DateTime.ISO.ParseDateTime("%s01 00:00:00" % dateval)
712                        dateval = "%s%02i 23:59:59" % (dateval, mxdate.days_in_month)
713                elif lgdateval == 8 :
714                    if limit == "start" : 
715                        dateval = "%s 00:00:00" % dateval
716                    else : 
717                        dateval = "%s 23:59:59" % dateval
718                elif lgdateval == 10 :
719                    if limit == "start" : 
720                        dateval = "%s %s:00:00" % (dateval[:8], dateval[8:])
721                    else : 
722                        dateval = "%s %s:59:59" % (dateval[:8], dateval[8:])
723                elif lgdateval == 12 :
724                    if limit == "start" : 
725                        dateval = "%s %s:%s:00" % (dateval[:8], dateval[8:10], dateval[10:])
726                    else : 
727                        dateval = "%s %s:%s:59" % (dateval[:8], dateval[8:10], dateval[10:])
728                elif lgdateval == 14 :       
729                    dateval = "%s %s:%s:%s" % (dateval[:8], dateval[8:10], dateval[10:12], dateval[12:])
730                else :   
731                    dateval = None
732                try :   
733                    DateTime.ISO.ParseDateTime(dateval)
734                except :   
735                    dateval = None
736            datedict[limit] = dateval   
737        (start, end) = (datedict["start"], datedict["end"])
738        if start > end :
739            (start, end) = (end, start)
740        return (start, end)   
741       
742def openConnection(pykotatool) :
743    """Returns a connection handle to the appropriate Quota Storage Database."""
744    backendinfo = pykotatool.config.getStorageBackend()
745    backend = backendinfo["storagebackend"]
746    try :
747        exec "from pykota.storages import %s as storagebackend" % backend.lower()
748    except ImportError :
749        raise PyKotaStorageError, _("Unsupported quota storage backend %s") % backend
750    else :   
751        host = backendinfo["storageserver"]
752        database = backendinfo["storagename"]
753        admin = backendinfo["storageadmin"] or backendinfo["storageuser"]
754        adminpw = backendinfo["storageadminpw"] or backendinfo["storageuserpw"]
755        return storagebackend.Storage(pykotatool, host, database, admin, adminpw)
Note: See TracBrowser for help on using the browser.