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

Revision 2953, 32.5 kB (checked in by jerome, 18 years ago)

Fixed date formatting problems with MySQL.

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