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

Revision 2342, 30.9 kB (checked in by jerome, 19 years ago)

The pkbcodes command line tool now works fine with the PostgreSQL
backend. The dumpykota command can now dump billing codes too.
Still no code for LDAP though.
NB : a database upgrade is necessary AGAIN !
Severity : no need to play with this until there's LDAP support.

  • 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.Exists = 0
102       
103class StorageGroup(StorageObject) :       
104    """User class."""
105    def __init__(self, parent, name) :
106        StorageObject.__init__(self, parent)
107        self.Name = name
108        self.LimitBy = None
109        self.AccountBalance = None
110        self.LifeTimePaid = None
111       
112    def setLimitBy(self, limitby) :   
113        """Sets the user's limiting factor."""
114        try :
115            limitby = limitby.lower()
116        except AttributeError :   
117            limitby = "quota"
118        if limitby in ["quota", "balance"] :
119            self.parent.writeGroupLimitBy(self, limitby)
120            self.LimitBy = limitby
121       
122    def delete(self) :   
123        """Deletes a group from the Quota Storage."""
124        self.parent.beginTransaction()
125        try :
126            self.parent.deleteGroup(self)
127        except PyKotaStorageError, msg :   
128            self.parent.rollbackTransaction()
129            raise PyKotaStorageError, msg
130        else :   
131            self.parent.commitTransaction()
132            self.Exists = 0
133       
134class StoragePrinter(StorageObject) :
135    """Printer class."""
136    def __init__(self, parent, name) :
137        StorageObject.__init__(self, parent)
138        self.Name = name
139        self.PricePerPage = None
140        self.PricePerJob = None
141        self.Description = None
142        self.Coefficients = None
143       
144    def __getattr__(self, name) :   
145        """Delays data retrieval until it's really needed."""
146        if name == "LastJob" : 
147            self.LastJob = self.parent.getPrinterLastJob(self)
148            return self.LastJob
149        else :
150            raise AttributeError, name
151           
152    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) :
153        """Adds a job to the printer's history."""
154        self.parent.writeJobNew(self, user, jobid, pagecounter, action, jobsize, jobprice, filename, title, copies, options, clienthost, jobsizebytes, jobmd5sum, jobpages, jobbilling)
155        # TODO : update LastJob object ? Probably not needed.
156       
157    def addPrinterToGroup(self, printer) :   
158        """Adds a printer to a printer group."""
159        if (printer not in self.parent.getParentPrinters(self)) and (printer.ident != self.ident) :
160            self.parent.writePrinterToGroup(self, printer)
161            # TODO : reset cached value for printer parents, or add new parent to cached value
162           
163    def delPrinterFromGroup(self, printer) :   
164        """Deletes a printer from a printer group."""
165        self.parent.removePrinterFromGroup(self, printer)
166        # TODO : reset cached value for printer parents, or add new parent to cached value
167       
168    def setPrices(self, priceperpage = None, priceperjob = None) :   
169        """Sets the printer's prices."""
170        if priceperpage is None :
171            priceperpage = self.PricePerPage or 0.0
172        else :   
173            self.PricePerPage = float(priceperpage)
174        if priceperjob is None :   
175            priceperjob = self.PricePerJob or 0.0
176        else :   
177            self.PricePerJob = float(priceperjob)
178        self.parent.writePrinterPrices(self)
179       
180    def setDescription(self, description=None) :
181        """Sets the printer's description."""
182        if description is None :
183            description = self.Description
184        else :   
185            self.Description = str(description)
186        self.parent.writePrinterDescription(self)
187       
188    def delete(self) :   
189        """Deletes a printer from the Quota Storage."""
190        self.parent.beginTransaction()
191        try :
192            self.parent.deletePrinter(self)
193        except PyKotaStorageError, msg :   
194            self.parent.rollbackTransaction()
195            raise PyKotaStorageError, msg
196        else :   
197            self.parent.commitTransaction()
198            self.Exists = 0   
199       
200class StorageUserPQuota(StorageObject) :
201    """User Print Quota class."""
202    def __init__(self, parent, user, printer) :
203        StorageObject.__init__(self, parent)
204        self.User = user
205        self.Printer = printer
206        self.PageCounter = None
207        self.LifePageCounter = None
208        self.SoftLimit = None
209        self.HardLimit = None
210        self.DateLimit = None
211        self.WarnCount = None
212       
213    def __getattr__(self, name) :   
214        """Delays data retrieval until it's really needed."""
215        if name == "ParentPrintersUserPQuota" : 
216            self.ParentPrintersUserPQuota = (self.User.Exists and self.Printer.Exists and self.parent.getParentPrintersUserPQuota(self)) or []
217            return self.ParentPrintersUserPQuota
218        else :
219            raise AttributeError, name
220       
221    def setDateLimit(self, datelimit) :   
222        """Sets the date limit for this quota."""
223        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)
224        self.parent.writeUserPQuotaDateLimit(self, date)
225        self.DateLimit = date
226       
227    def setLimits(self, softlimit, hardlimit) :   
228        """Sets the soft and hard limit for this quota."""
229        self.parent.writeUserPQuotaLimits(self, softlimit, hardlimit)
230        self.SoftLimit = softlimit
231        self.HardLimit = hardlimit
232        self.DateLimit = None
233        self.WarnCount = 0
234       
235    def setUsage(self, used) :
236        """Sets the PageCounter and LifePageCounter to used, or if used is + or - prefixed, changes the values of {Life,}PageCounter by that amount."""
237        vused = int(used)
238        if used.startswith("+") or used.startswith("-") :
239            self.parent.beginTransaction()
240            try :
241                self.parent.increaseUserPQuotaPagesCounters(self, vused)
242                self.parent.writeUserPQuotaDateLimit(self, None)
243                self.parent.writeUserPQuotaWarnCount(self, 0)
244            except PyKotaStorageError, msg :   
245                self.parent.rollbackTransaction()
246                raise PyKotaStorageError, msg
247            else :
248                self.parent.commitTransaction()
249            self.PageCounter += vused
250            self.LifePageCounter += vused
251        else :
252            self.parent.writeUserPQuotaPagesCounters(self, vused, vused)
253            self.PageCounter = self.LifePageCounter = vused
254        self.DateLimit = None
255        self.WarnCount = 0
256
257    def incDenyBannerCounter(self) :
258        """Increment the deny banner counter for this user quota."""
259        self.parent.increaseUserPQuotaWarnCount(self)
260        self.WarnCount = (self.WarnCount or 0) + 1
261       
262    def resetDenyBannerCounter(self) :
263        """Resets the deny banner counter for this user quota."""
264        self.parent.writeUserPQuotaWarnCount(self, 0)
265        self.WarnCount = 0
266       
267    def reset(self) :   
268        """Resets page counter to 0."""
269        self.parent.writeUserPQuotaPagesCounters(self, 0, int(self.LifePageCounter or 0))
270        self.PageCounter = 0
271        self.DateLimit = None
272       
273    def hardreset(self) :   
274        """Resets actual and life time page counters to 0."""
275        self.parent.writeUserPQuotaPagesCounters(self, 0, 0)
276        self.PageCounter = self.LifePageCounter = 0
277        self.DateLimit = None
278       
279    def computeJobPrice(self, jobsize) :   
280        """Computes the job price as the sum of all parent printers' prices + current printer's ones."""
281        totalprice = 0.0   
282        if jobsize :
283            if self.User.OverCharge != 0.0 :    # optimization, but TODO : beware of rounding errors
284                for upq in [ self ] + self.ParentPrintersUserPQuota :
285                    price = (float(upq.Printer.PricePerPage or 0.0) * jobsize) + float(upq.Printer.PricePerJob or 0.0)
286                    totalprice += price
287        if self.User.OverCharge != 1.0 : # TODO : beware of rounding errors
288            overcharged = totalprice * self.User.OverCharge       
289            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))
290            return overcharged
291        else :   
292            return totalprice
293           
294    def increasePagesUsage(self, jobsize) :
295        """Increase the value of used pages and money."""
296        jobprice = self.computeJobPrice(jobsize)
297        if jobsize :
298            self.parent.beginTransaction()
299            try :
300                if jobprice :
301                    self.User.consumeAccountBalance(jobprice)
302                for upq in [ self ] + self.ParentPrintersUserPQuota :
303                    self.parent.increaseUserPQuotaPagesCounters(upq, jobsize)
304                    upq.PageCounter = int(upq.PageCounter or 0) + jobsize
305                    upq.LifePageCounter = int(upq.LifePageCounter or 0) + jobsize
306                # TODO : consume from the billing code as well
307            except PyKotaStorageError, msg :   
308                self.parent.rollbackTransaction()
309                raise PyKotaStorageError, msg
310            else :   
311                self.parent.commitTransaction()
312        return jobprice
313       
314class StorageGroupPQuota(StorageObject) :
315    """Group Print Quota class."""
316    def __init__(self, parent, group, printer) :
317        StorageObject.__init__(self, parent)
318        self.Group = group
319        self.Printer = printer
320        self.PageCounter = None
321        self.LifePageCounter = None
322        self.SoftLimit = None
323        self.HardLimit = None
324        self.DateLimit = None
325       
326    def __getattr__(self, name) :   
327        """Delays data retrieval until it's really needed."""
328        if name == "ParentPrintersGroupPQuota" : 
329            self.ParentPrintersGroupPQuota = (self.Group.Exists and self.Printer.Exists and self.parent.getParentPrintersGroupPQuota(self)) or []
330            return self.ParentPrintersGroupPQuota
331        else :
332            raise AttributeError, name
333       
334    def reset(self) :   
335        """Resets page counter to 0."""
336        self.parent.beginTransaction()
337        try :
338            for user in self.parent.getGroupMembers(self.Group) :
339                uq = self.parent.getUserPQuota(user, self.Printer)
340                uq.reset()
341            self.parent.writeGroupPQuotaDateLimit(self, None)
342        except PyKotaStorageError, msg :   
343            self.parent.rollbackTransaction()
344            raise PyKotaStorageError, msg
345        else :   
346            self.parent.commitTransaction()
347        self.PageCounter = 0
348        self.DateLimit = None
349       
350    def hardreset(self) :   
351        """Resets actual and life time page counters to 0."""
352        self.parent.beginTransaction()
353        try :
354            for user in self.parent.getGroupMembers(self.Group) :
355                uq = self.parent.getUserPQuota(user, self.Printer)
356                uq.hardreset()
357            self.parent.writeGroupPQuotaDateLimit(self, None)
358        except PyKotaStorageError, msg :   
359            self.parent.rollbackTransaction()
360            raise PyKotaStorageError, msg
361        else :   
362            self.parent.commitTransaction()
363        self.PageCounter = self.LifePageCounter = 0
364        self.DateLimit = None
365       
366    def setDateLimit(self, datelimit) :   
367        """Sets the date limit for this quota."""
368        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, 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.Exists = 0
432       
433    def reset(self, balance=0.0, pagecounter=0) :   
434        """Resets the pagecounter and balance for this billing code."""
435        self.parent.setBillingCodeValues(self, balance, pagecounter)
436        self.Balance = balance
437        self.PageCounter = pagecounter
438       
439    def setDescription(self, description=None) :
440        """Modifies the description for this billing code."""
441        if description is None :
442            description = self.Description
443        else :   
444            self.Description = str(description)
445        self.parent.writeBillingCodeDescription(self)
446       
447    def consume(self, pages, price) :
448        """Consumes some pages and credits for this billing code."""
449        if pages :
450           self.parent.consumeBillingCode(self, pages, price)
451           self.PageCounter += pages
452           self.Balance -= price
453       
454class BaseStorage :
455    def __init__(self, pykotatool) :
456        """Opens the storage connection."""
457        self.closed = 1
458        self.tool = pykotatool
459        self.usecache = pykotatool.config.getCaching()
460        self.disablehistory = pykotatool.config.getDisableHistory()
461        self.privacy = pykotatool.config.getPrivacy()
462        if self.privacy :
463            pykotatool.logdebug("Jobs' title, filename and options will be hidden because of privacy concerns.")
464        if self.usecache :
465            self.tool.logdebug("Caching enabled.")
466            self.caches = { "USERS" : {}, "GROUPS" : {}, "PRINTERS" : {}, "USERPQUOTAS" : {}, "GROUPPQUOTAS" : {}, "JOBS" : {}, "LASTJOBS" : {}, "BILLINGCODES" : {} }
467       
468    def close(self) :   
469        """Must be overriden in children classes."""
470        raise RuntimeError, "BaseStorage.close() must be overriden !"
471       
472    def __del__(self) :       
473        """Ensures that the database connection is closed."""
474        self.close()
475       
476    def getFromCache(self, cachetype, key) :
477        """Tries to extract something from the cache."""
478        if self.usecache :
479            entry = self.caches[cachetype].get(key)
480            if entry is not None :
481                self.tool.logdebug("Cache hit (%s->%s)" % (cachetype, key))
482            else :   
483                self.tool.logdebug("Cache miss (%s->%s)" % (cachetype, key))
484            return entry   
485           
486    def cacheEntry(self, cachetype, key, value) :       
487        """Puts an entry in the cache."""
488        if self.usecache and getattr(value, "Exists", 0) :
489            self.caches[cachetype][key] = value
490            self.tool.logdebug("Cache store (%s->%s)" % (cachetype, key))
491           
492    def getUser(self, username) :       
493        """Returns the user from cache."""
494        user = self.getFromCache("USERS", username)
495        if user is None :
496            user = self.getUserFromBackend(username)
497            self.cacheEntry("USERS", username, user)
498        return user   
499       
500    def getGroup(self, groupname) :       
501        """Returns the group from cache."""
502        group = self.getFromCache("GROUPS", groupname)
503        if group is None :
504            group = self.getGroupFromBackend(groupname)
505            self.cacheEntry("GROUPS", groupname, group)
506        return group   
507       
508    def getPrinter(self, printername) :       
509        """Returns the printer from cache."""
510        printer = self.getFromCache("PRINTERS", printername)
511        if printer is None :
512            printer = self.getPrinterFromBackend(printername)
513            self.cacheEntry("PRINTERS", printername, printer)
514        return printer   
515       
516    def getUserPQuota(self, user, printer) :       
517        """Returns the user quota information from cache."""
518        useratprinter = "%s@%s" % (user.Name, printer.Name)
519        upquota = self.getFromCache("USERPQUOTAS", useratprinter)
520        if upquota is None :
521            upquota = self.getUserPQuotaFromBackend(user, printer)
522            self.cacheEntry("USERPQUOTAS", useratprinter, upquota)
523        return upquota   
524       
525    def getGroupPQuota(self, group, printer) :       
526        """Returns the group quota information from cache."""
527        groupatprinter = "%s@%s" % (group.Name, printer.Name)
528        gpquota = self.getFromCache("GROUPPQUOTAS", groupatprinter)
529        if gpquota is None :
530            gpquota = self.getGroupPQuotaFromBackend(group, printer)
531            self.cacheEntry("GROUPPQUOTAS", groupatprinter, gpquota)
532        return gpquota   
533       
534    def getPrinterLastJob(self, printer) :       
535        """Extracts last job information for a given printer from cache."""
536        lastjob = self.getFromCache("LASTJOBS", printer.Name)
537        if lastjob is None :
538            lastjob = self.getPrinterLastJobFromBackend(printer)
539            self.cacheEntry("LASTJOBS", printer.Name, lastjob)
540        return lastjob   
541       
542    def getBillingCode(self, label) :       
543        """Returns the user from cache."""
544        code = self.getFromCache("BILLINGCODES", label)
545        if code is None :
546            code = self.getBillingCodeFromBackend(label)
547            self.cacheEntry("BILLINGCODES", label, code)
548        return code
549       
550    def getParentPrinters(self, printer) :   
551        """Extracts parent printers information for a given printer from cache."""
552        if self.usecache :
553            if not hasattr(printer, "Parents") :
554                self.tool.logdebug("Cache miss (%s->Parents)" % printer.Name)
555                printer.Parents = self.getParentPrintersFromBackend(printer)
556                self.tool.logdebug("Cache store (%s->Parents)" % printer.Name)
557            else :
558                self.tool.logdebug("Cache hit (%s->Parents)" % printer.Name)
559        else :       
560            printer.Parents = self.getParentPrintersFromBackend(printer)
561        for parent in printer.Parents[:] :   
562            printer.Parents.extend(self.getParentPrinters(parent))
563        uniquedic = {}   
564        for parent in printer.Parents :
565            uniquedic[parent.Name] = parent
566        printer.Parents = uniquedic.values()   
567        return printer.Parents
568       
569    def getGroupMembers(self, group) :       
570        """Returns the group's members list from in-group cache."""
571        if self.usecache :
572            if not hasattr(group, "Members") :
573                self.tool.logdebug("Cache miss (%s->Members)" % group.Name)
574                group.Members = self.getGroupMembersFromBackend(group)
575                self.tool.logdebug("Cache store (%s->Members)" % group.Name)
576            else :
577                self.tool.logdebug("Cache hit (%s->Members)" % group.Name)
578        else :       
579            group.Members = self.getGroupMembersFromBackend(group)
580        return group.Members   
581       
582    def getUserGroups(self, user) :       
583        """Returns the user's groups list from in-user cache."""
584        if self.usecache :
585            if not hasattr(user, "Groups") :
586                self.tool.logdebug("Cache miss (%s->Groups)" % user.Name)
587                user.Groups = self.getUserGroupsFromBackend(user)
588                self.tool.logdebug("Cache store (%s->Groups)" % user.Name)
589            else :
590                self.tool.logdebug("Cache hit (%s->Groups)" % user.Name)
591        else :       
592            user.Groups = self.getUserGroupsFromBackend(user)
593        return user.Groups   
594       
595    def getParentPrintersUserPQuota(self, userpquota) :     
596        """Returns all user print quota on the printer and all its parents recursively."""
597        upquotas = [ ]
598        for printer in self.getParentPrinters(userpquota.Printer) :
599            upq = self.getUserPQuota(userpquota.User, printer)
600            if upq.Exists :
601                upquotas.append(upq)
602        return upquotas       
603       
604    def getParentPrintersGroupPQuota(self, grouppquota) :     
605        """Returns all group print quota on the printer and all its parents recursively."""
606        gpquotas = [ ]
607        for printer in self.getParentPrinters(grouppquota.Printer) :
608            gpq = self.getGroupPQuota(grouppquota.Group, printer)
609            if gpq.Exists :
610                gpquotas.append(gpq)
611        return gpquotas       
612       
613    def databaseToUserCharset(self, text) :
614        """Converts from database format (UTF-8) to user's charset."""
615        if text is not None :
616            try :
617                return unicode(text, "UTF-8").encode(self.tool.getCharset()) 
618            except UnicodeError :   
619                try :
620                    # Incorrect locale settings ?
621                    return unicode(text, "UTF-8").encode("ISO-8859-15") 
622                except UnicodeError :   
623                    pass
624        return text
625       
626    def userCharsetToDatabase(self, text) :
627        """Converts from user's charset to database format (UTF-8)."""
628        if text is not None :
629            try :
630                return unicode(text, self.tool.getCharset()).encode("UTF-8") 
631            except UnicodeError :   
632                try :
633                    # Incorrect locale settings ?
634                    return unicode(text, "ISO-8859-15").encode("UTF-8") 
635                except UnicodeError :   
636                    pass
637        return text
638       
639    def cleanDates(self, startdate, enddate) :   
640        """Clean the dates to create a correct filter."""
641        if startdate is None :
642            startdate = enddate
643        if enddate is None :   
644            enddate = startdate
645        if (startdate is None) and (enddate is None) :   
646            return (None, None)
647           
648        now = DateTime.now()   
649        nameddates = ('yesterday', 'today', 'now', 'tomorrow')
650        datedict = { "start" : startdate.lower(), "end" : enddate.lower() }   
651        for limit in datedict.keys() :
652            dateval = datedict[limit]
653            for name in nameddates :
654                if dateval.startswith(name) :
655                    try :
656                        offset = int(dateval[len(name):])
657                    except :   
658                        offset = 0
659                    dateval = dateval[:len(name)]   
660                    if limit == "start" :
661                        if dateval == "yesterday" :
662                            dateval = (now - 1 + offset).Format("%Y%m%d000000")
663                        elif dateval == "today" :
664                            dateval = (now + offset).Format("%Y%m%d000000")
665                        elif dateval == "now" :
666                            dateval = (now + offset).Format("%Y%m%d%H%M%S")
667                        else : # tomorrow
668                            dateval = (now + 1 + offset).Format("%Y%m%d000000")
669                    else :
670                        if dateval == "yesterday" :
671                            dateval = (now - 1 + offset).Format("%Y%m%d235959")
672                        elif dateval == "today" :
673                            dateval = (now + offset).Format("%Y%m%d235959")
674                        elif dateval == "now" :
675                            dateval = (now + offset).Format("%Y%m%d%H%M%S")
676                        else : # tomorrow
677                            dateval = (now + 1 + offset).Format("%Y%m%d235959")
678                    break
679                   
680            if not dateval.isdigit() :
681                dateval = None
682            else :   
683                lgdateval = len(dateval)
684                if lgdateval == 4 :
685                    if limit == "start" : 
686                        dateval = "%s0101 00:00:00" % dateval
687                    else : 
688                        dateval = "%s1231 23:59:59" % dateval
689                elif lgdateval == 6 :
690                    if limit == "start" : 
691                        dateval = "%s01 00:00:00" % dateval
692                    else : 
693                        mxdate = DateTime.ISO.ParseDateTime("%s01 00:00:00" % dateval)
694                        dateval = "%s%02i 23:59:59" % (dateval, mxdate.days_in_month)
695                elif lgdateval == 8 :
696                    if limit == "start" : 
697                        dateval = "%s 00:00:00" % dateval
698                    else : 
699                        dateval = "%s 23:59:59" % dateval
700                elif lgdateval == 10 :
701                    if limit == "start" : 
702                        dateval = "%s %s:00:00" % (dateval[:8], dateval[8:])
703                    else : 
704                        dateval = "%s %s:59:59" % (dateval[:8], dateval[8:])
705                elif lgdateval == 12 :
706                    if limit == "start" : 
707                        dateval = "%s %s:%s:00" % (dateval[:8], dateval[8:10], dateval[10:])
708                    else : 
709                        dateval = "%s %s:%s:59" % (dateval[:8], dateval[8:10], dateval[10:])
710                elif lgdateval == 14 :       
711                    dateval = "%s %s:%s:%s" % (dateval[:8], dateval[8:10], dateval[10:12], dateval[12:])
712                else :   
713                    dateval = None
714                try :   
715                    DateTime.ISO.ParseDateTime(dateval)
716                except :   
717                    dateval = None
718            datedict[limit] = dateval   
719        (start, end) = (datedict["start"], datedict["end"])
720        if start > end :
721            (start, end) = (end, start)
722        return (start, end)   
723       
724def openConnection(pykotatool) :
725    """Returns a connection handle to the appropriate Quota Storage Database."""
726    backendinfo = pykotatool.config.getStorageBackend()
727    backend = backendinfo["storagebackend"]
728    try :
729        exec "from pykota.storages import %s as storagebackend" % backend.lower()
730    except ImportError :
731        raise PyKotaStorageError, _("Unsupported quota storage backend %s") % backend
732    else :   
733        host = backendinfo["storageserver"]
734        database = backendinfo["storagename"]
735        admin = backendinfo["storageadmin"] or backendinfo["storageuser"]
736        adminpw = backendinfo["storageadminpw"] or backendinfo["storageuserpw"]
737        return storagebackend.Storage(pykotatool, host, database, admin, adminpw)
Note: See TracBrowser for help on using the browser.