root / pykota / trunk / pykota / storages / sql.py @ 3142

Revision 3142, 53.9 kB (checked in by jerome, 17 years ago)

Make start= and end= filters also work with payments. For an unknown
reason it didn't already work (not implemented !)...
Ensures that these filters are only allowed for payments and
history, otherwise an SQL syntax error could have occured.

  • 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, 2007 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 pykota.storage import StorageUser, StorageGroup, StoragePrinter, \
26                           StorageJob, StorageLastJob, StorageUserPQuota, \
27                           StorageGroupPQuota, StorageBillingCode
28
29class SQLStorage :
30    def storageUserFromRecord(self, username, record) :
31        """Returns a StorageUser instance from a database record."""
32        user = StorageUser(self, username)
33        user.ident = record.get("uid", record.get("userid", record.get("id")))
34        user.LimitBy = record.get("limitby") or "quota"
35        user.AccountBalance = record.get("balance")
36        user.LifeTimePaid = record.get("lifetimepaid")
37        user.Email = record.get("email")
38        user.Description = self.databaseToUserCharset(record.get("description"))
39        user.OverCharge = record.get("overcharge", 1.0)
40        user.Exists = True
41        return user
42       
43    def storageGroupFromRecord(self, groupname, record) :
44        """Returns a StorageGroup instance from a database record."""
45        group = StorageGroup(self, groupname)
46        group.ident = record.get("id")
47        group.LimitBy = record.get("limitby") or "quota"
48        group.AccountBalance = record.get("balance")
49        group.LifeTimePaid = record.get("lifetimepaid")
50        group.Description = self.databaseToUserCharset(record.get("description"))
51        group.Exists = True
52        return group
53       
54    def storagePrinterFromRecord(self, printername, record) :
55        """Returns a StoragePrinter instance from a database record."""
56        printer = StoragePrinter(self, printername)
57        printer.ident = record.get("id")
58        printer.PricePerJob = record.get("priceperjob") or 0.0
59        printer.PricePerPage = record.get("priceperpage") or 0.0
60        printer.MaxJobSize = record.get("maxjobsize") or 0
61        printer.PassThrough = record.get("passthrough") or 0
62        if printer.PassThrough in (1, "1", "t", "true", "TRUE", "True") :
63            printer.PassThrough = True
64        else :
65            printer.PassThrough = False
66        printer.Description = self.databaseToUserCharset(record.get("description") or "") # TODO : is 'or ""' still needed ?
67        printer.Exists = True
68        return printer
69       
70    def setJobAttributesFromRecord(self, job, record) :   
71        """Sets the attributes of a job from a database record."""
72        job.ident = record.get("id")
73        job.JobId = record.get("jobid")
74        job.PrinterPageCounter = record.get("pagecounter")
75        job.JobSize = record.get("jobsize")
76        job.JobPrice = record.get("jobprice")
77        job.JobAction = record.get("action")
78        job.JobFileName = self.databaseToUserCharset(record.get("filename") or "") 
79        job.JobTitle = self.databaseToUserCharset(record.get("title") or "") 
80        job.JobCopies = record.get("copies")
81        job.JobOptions = self.databaseToUserCharset(record.get("options") or "") 
82        job.JobDate = record.get("jobdate")
83        job.JobHostName = record.get("hostname")
84        job.JobSizeBytes = record.get("jobsizebytes")
85        job.JobMD5Sum = record.get("md5sum")
86        job.JobPages = record.get("pages")
87        job.JobBillingCode = self.databaseToUserCharset(record.get("billingcode") or "")
88        job.PrecomputedJobSize = record.get("precomputedjobsize")
89        job.PrecomputedJobPrice = record.get("precomputedjobprice")
90        job.UserName = self.databaseToUserCharset(record.get("username"))
91        job.PrinterName = self.databaseToUserCharset(record.get("printername"))
92        if job.JobTitle == job.JobFileName == job.JobOptions == "hidden" :
93            (job.JobTitle, job.JobFileName, job.JobOptions) = (_("Hidden because of privacy concerns"),) * 3
94        job.Exists = True
95       
96    def storageJobFromRecord(self, record) :
97        """Returns a StorageJob instance from a database record."""
98        job = StorageJob(self)
99        self.setJobAttributesFromRecord(job, record)
100        return job
101       
102    def storageLastJobFromRecord(self, printer, record) :
103        """Returns a StorageLastJob instance from a database record."""
104        lastjob = StorageLastJob(self, printer)
105        self.setJobAttributesFromRecord(lastjob, record)
106        return lastjob
107       
108    def storageUserPQuotaFromRecord(self, user, printer, record) :
109        """Returns a StorageUserPQuota instance from a database record."""
110        userpquota = StorageUserPQuota(self, user, printer)
111        userpquota.ident = record.get("id")
112        userpquota.PageCounter = record.get("pagecounter")
113        userpquota.LifePageCounter = record.get("lifepagecounter")
114        userpquota.SoftLimit = record.get("softlimit")
115        userpquota.HardLimit = record.get("hardlimit")
116        userpquota.DateLimit = record.get("datelimit")
117        userpquota.WarnCount = record.get("warncount") or 0
118        userpquota.Exists = True
119        return userpquota
120       
121    def storageGroupPQuotaFromRecord(self, group, printer, record) :
122        """Returns a StorageGroupPQuota instance from a database record."""
123        grouppquota = StorageGroupPQuota(self, group, printer)
124        grouppquota.ident = record.get("id")
125        grouppquota.SoftLimit = record.get("softlimit")
126        grouppquota.HardLimit = record.get("hardlimit")
127        grouppquota.DateLimit = record.get("datelimit")
128        result = self.doSearch("SELECT SUM(lifepagecounter) AS lifepagecounter, SUM(pagecounter) AS pagecounter FROM userpquota WHERE printerid=%s AND userid IN (SELECT userid FROM groupsmembers WHERE groupid=%s)" \
129                      % (self.doQuote(printer.ident), self.doQuote(group.ident)))
130        if result :
131            grouppquota.PageCounter = result[0].get("pagecounter") or 0
132            grouppquota.LifePageCounter = result[0].get("lifepagecounter") or 0
133        grouppquota.Exists = True
134        return grouppquota
135       
136    def storageBillingCodeFromRecord(self, billingcode, record) :
137        """Returns a StorageBillingCode instance from a database record."""
138        code = StorageBillingCode(self, billingcode)
139        code.ident = record.get("id")
140        code.Description = self.databaseToUserCharset(record.get("description") or "") # TODO : is 'or ""' still needed ?
141        code.Balance = record.get("balance") or 0.0
142        code.PageCounter = record.get("pagecounter") or 0
143        code.Exists = True
144        return code
145       
146    def createFilter(self, only) :   
147        """Returns the appropriate SQL filter."""
148        if only :
149            expressions = []
150            for (k, v) in only.items() :
151                expressions.append("%s=%s" % (k, self.doQuote(self.userCharsetToDatabase(v))))
152            return " AND ".join(expressions)     
153        return ""       
154       
155    def extractPrinters(self, extractonly={}) :
156        """Extracts all printer records."""
157        thefilter = self.createFilter(extractonly)
158        if thefilter :
159            thefilter = "WHERE %s" % thefilter
160        result = self.doRawSearch("SELECT * FROM printers %s ORDER BY id ASC" % thefilter)
161        return self.prepareRawResult(result)
162       
163    def extractUsers(self, extractonly={}) :
164        """Extracts all user records."""
165        thefilter = self.createFilter(extractonly)
166        if thefilter :
167            thefilter = "WHERE %s" % thefilter
168        result = self.doRawSearch("SELECT * FROM users %s ORDER BY id ASC" % thefilter)
169        return self.prepareRawResult(result)
170       
171    def extractBillingcodes(self, extractonly={}) :
172        """Extracts all billing codes records."""
173        thefilter = self.createFilter(extractonly)
174        if thefilter :
175            thefilter = "WHERE %s" % thefilter
176        result = self.doRawSearch("SELECT * FROM billingcodes %s ORDER BY id ASC" % thefilter)
177        return self.prepareRawResult(result)
178       
179    def extractGroups(self, extractonly={}) :
180        """Extracts all group records."""
181        thefilter = self.createFilter(extractonly)
182        if thefilter :
183            thefilter = "WHERE %s" % thefilter
184        result = self.doRawSearch("SELECT groups.*,COALESCE(SUM(balance), 0) AS balance, COALESCE(SUM(lifetimepaid), 0) as lifetimepaid FROM groups LEFT OUTER JOIN users ON users.id IN (SELECT userid FROM groupsmembers WHERE groupid=groups.id) %s GROUP BY groups.id,groups.groupname,groups.limitby,groups.description ORDER BY groups.id ASC" % thefilter)
185        return self.prepareRawResult(result)
186       
187    def extractPayments(self, extractonly={}) :
188        """Extracts all payment records."""
189        startdate = extractonly.get("start")
190        enddate = extractonly.get("end")
191        for limit in ("start", "end") :
192            try :
193                del extractonly[limit]
194            except KeyError :   
195                pass
196        thefilter = self.createFilter(extractonly)
197        if thefilter :
198            thefilter = "AND %s" % thefilter
199        (startdate, enddate) = self.cleanDates(startdate, enddate)
200        if startdate : 
201            thefilter = "%s AND date>=%s" % (thefilter, self.doQuote(startdate))
202        if enddate : 
203            thefilter = "%s AND date<=%s" % (thefilter, self.doQuote(enddate))
204        result = self.doRawSearch("SELECT username,payments.* FROM users,payments WHERE users.id=payments.userid %s ORDER BY payments.id ASC" % thefilter)
205        return self.prepareRawResult(result)
206       
207    def extractUpquotas(self, extractonly={}) :
208        """Extracts all userpquota records."""
209        thefilter = self.createFilter(extractonly)
210        if thefilter :
211            thefilter = "AND %s" % thefilter
212        result = self.doRawSearch("SELECT users.username,printers.printername,userpquota.* FROM users,printers,userpquota WHERE users.id=userpquota.userid AND printers.id=userpquota.printerid %s ORDER BY userpquota.id ASC" % thefilter)
213        return self.prepareRawResult(result)
214       
215    def extractGpquotas(self, extractonly={}) :
216        """Extracts all grouppquota records."""
217        thefilter = self.createFilter(extractonly)
218        if thefilter :
219            thefilter = "AND %s" % thefilter
220        result = self.doRawSearch("SELECT groups.groupname,printers.printername,grouppquota.*,coalesce(sum(pagecounter), 0) AS pagecounter,coalesce(sum(lifepagecounter), 0) AS lifepagecounter FROM groups,printers,grouppquota,userpquota WHERE groups.id=grouppquota.groupid AND printers.id=grouppquota.printerid AND userpquota.printerid=grouppquota.printerid AND userpquota.userid IN (SELECT userid FROM groupsmembers WHERE groupsmembers.groupid=grouppquota.groupid) %s GROUP BY grouppquota.id,grouppquota.groupid,grouppquota.printerid,grouppquota.softlimit,grouppquota.hardlimit,grouppquota.datelimit,grouppquota.maxjobsize,groups.groupname,printers.printername ORDER BY grouppquota.id" % thefilter)
221        return self.prepareRawResult(result)
222       
223    def extractUmembers(self, extractonly={}) :
224        """Extracts all user groups members."""
225        thefilter = self.createFilter(extractonly)
226        if thefilter :
227            thefilter = "AND %s" % thefilter
228        result = self.doRawSearch("SELECT groups.groupname, users.username, groupsmembers.* FROM groups,users,groupsmembers WHERE users.id=groupsmembers.userid AND groups.id=groupsmembers.groupid %s ORDER BY groupsmembers.groupid, groupsmembers.userid ASC" % thefilter)
229        return self.prepareRawResult(result)
230       
231    def extractPmembers(self, extractonly={}) :
232        """Extracts all printer groups members."""
233        for (k, v) in extractonly.items() :
234            if k == "pgroupname" :
235                del extractonly[k]
236                extractonly["p1.printername"] = v
237            elif k == "printername" :
238                del extractonly[k]
239                extractonly["p2.printername"] = v
240        thefilter = self.createFilter(extractonly)
241        if thefilter :
242            thefilter = "AND %s" % thefilter
243        result = self.doRawSearch("SELECT p1.printername as pgroupname, p2.printername as printername, printergroupsmembers.* FROM printers p1, printers p2, printergroupsmembers WHERE p1.id=printergroupsmembers.groupid AND p2.id=printergroupsmembers.printerid %s ORDER BY printergroupsmembers.groupid, printergroupsmembers.printerid ASC" % thefilter)
244        return self.prepareRawResult(result)
245       
246    def extractHistory(self, extractonly={}) :
247        """Extracts all jobhistory records."""
248        startdate = extractonly.get("start")
249        enddate = extractonly.get("end")
250        for limit in ("start", "end") :
251            try :
252                del extractonly[limit]
253            except KeyError :   
254                pass
255        thefilter = self.createFilter(extractonly)
256        if thefilter :
257            thefilter = "AND %s" % thefilter
258        (startdate, enddate) = self.cleanDates(startdate, enddate)
259        if startdate : 
260            thefilter = "%s AND jobdate>=%s" % (thefilter, self.doQuote(startdate))
261        if enddate : 
262            thefilter = "%s AND jobdate<=%s" % (thefilter, self.doQuote(enddate))
263        result = self.doRawSearch("SELECT users.username,printers.printername,jobhistory.* FROM users,printers,jobhistory WHERE users.id=jobhistory.userid AND printers.id=jobhistory.printerid %s ORDER BY jobhistory.id ASC" % thefilter)
264        return self.prepareRawResult(result)
265           
266    def filterNames(self, records, attribute, patterns=None) :
267        """Returns a list of 'attribute' from a list of records.
268       
269           Logs any missing attribute.
270        """   
271        result = []
272        for record in records :
273            attrval = record.get(attribute, [None])
274            if attrval is None :
275                self.tool.printInfo("Object %s has no %s attribute !" % (repr(record), attribute), "error")
276            else :
277                attrval = self.databaseToUserCharset(attrval)
278                if patterns :
279                    if (not isinstance(patterns, type([]))) and (not isinstance(patterns, type(()))) :
280                        patterns = [ patterns ]
281                    if self.tool.matchString(attrval, patterns) :
282                        result.append(attrval)
283                else :   
284                    result.append(attrval)
285        return result   
286               
287    def getAllBillingCodes(self, billingcode=None) :   
288        """Extracts all billing codes or only the billing codes matching the optional parameter."""
289        result = self.doSearch("SELECT billingcode FROM billingcodes")
290        if result :
291            return self.filterNames(result, "billingcode", billingcode)
292        else :   
293            return []
294       
295    def getAllPrintersNames(self, printername=None) :   
296        """Extracts all printer names or only the printers' names matching the optional parameter."""
297        result = self.doSearch("SELECT printername FROM printers")
298        if result :
299            return self.filterNames(result, "printername", printername)
300        else :   
301            return []
302   
303    def getAllUsersNames(self, username=None) :   
304        """Extracts all user names."""
305        result = self.doSearch("SELECT username FROM users")
306        if result :
307            return self.filterNames(result, "username", username)
308        else :   
309            return []
310       
311    def getAllGroupsNames(self, groupname=None) :   
312        """Extracts all group names."""
313        result = self.doSearch("SELECT groupname FROM groups")
314        if result :
315            return self.filterNames(result, "groupname", groupname)
316        else :
317            return []
318       
319    def getUserNbJobsFromHistory(self, user) :
320        """Returns the number of jobs the user has in history."""
321        result = self.doSearch("SELECT COUNT(*) FROM jobhistory WHERE userid=%s" % self.doQuote(user.ident))
322        if result :
323            return result[0]["count"]
324        return 0
325       
326    def getUserFromBackend(self, username) :   
327        """Extracts user information given its name."""
328        result = self.doSearch("SELECT * FROM users WHERE username=%s LIMIT 1"\
329                      % self.doQuote(self.userCharsetToDatabase(username)))
330        if result :
331            return self.storageUserFromRecord(username, result[0])
332        else :   
333            return StorageUser(self, username)
334       
335    def getGroupFromBackend(self, groupname) :   
336        """Extracts group information given its name."""
337        result = self.doSearch("SELECT groups.*,COALESCE(SUM(balance), 0.0) AS balance, COALESCE(SUM(lifetimepaid), 0.0) AS lifetimepaid FROM groups LEFT OUTER JOIN users ON users.id IN (SELECT userid FROM groupsmembers WHERE groupid=groups.id) WHERE groupname=%s GROUP BY groups.id,groups.groupname,groups.limitby,groups.description LIMIT 1" \
338                      % self.doQuote(self.userCharsetToDatabase(groupname)))
339        if result :
340            return self.storageGroupFromRecord(groupname, result[0])
341        else :   
342            return StorageGroup(self, groupname)
343       
344    def getPrinterFromBackend(self, printername) :       
345        """Extracts printer information given its name."""
346        result = self.doSearch("SELECT * FROM printers WHERE printername=%s LIMIT 1" \
347                      % self.doQuote(self.userCharsetToDatabase(printername)))
348        if result :
349            return self.storagePrinterFromRecord(printername, result[0])
350        else :   
351            return StoragePrinter(self, printername)
352       
353    def getBillingCodeFromBackend(self, label) :       
354        """Extracts a billing code information given its name."""
355        result = self.doSearch("SELECT * FROM billingcodes WHERE billingcode=%s LIMIT 1" \
356                      % self.doQuote(self.userCharsetToDatabase(label)))
357        if result :
358            return self.storageBillingCodeFromRecord(label, result[0])
359        else :   
360            return StorageBillingCode(self, label)
361       
362    def getUserPQuotaFromBackend(self, user, printer) :       
363        """Extracts a user print quota."""
364        if printer.Exists and user.Exists :
365            result = self.doSearch("SELECT * FROM userpquota WHERE userid=%s AND printerid=%s;" \
366                          % (self.doQuote(user.ident), self.doQuote(printer.ident)))
367            if result :
368                return self.storageUserPQuotaFromRecord(user, printer, result[0])
369        return StorageUserPQuota(self, user, printer)
370       
371    def getGroupPQuotaFromBackend(self, group, printer) :       
372        """Extracts a group print quota."""
373        if printer.Exists and group.Exists :
374            result = self.doSearch("SELECT * FROM grouppquota WHERE groupid=%s AND printerid=%s" \
375                          % (self.doQuote(group.ident), self.doQuote(printer.ident)))
376            if result :
377                return self.storageGroupPQuotaFromRecord(group, printer, result[0])
378        return StorageGroupPQuota(self, group, printer)
379       
380    def getPrinterLastJobFromBackend(self, printer) :       
381        """Extracts a printer's last job information."""
382        result = self.doSearch("SELECT jobhistory.id, jobid, userid, username, pagecounter, jobsize, jobprice, filename, title, copies, options, hostname, jobdate, md5sum, pages, billingcode, precomputedjobsize, precomputedjobprice FROM jobhistory, users WHERE printerid=%s AND userid=users.id ORDER BY jobdate DESC LIMIT 1" % self.doQuote(printer.ident))
383        if result :
384            return self.storageLastJobFromRecord(printer, result[0])
385        else :   
386            return StorageLastJob(self, printer)
387           
388    def getGroupMembersFromBackend(self, group) :       
389        """Returns the group's members list."""
390        groupmembers = []
391        result = self.doSearch("SELECT * FROM groupsmembers JOIN users ON groupsmembers.userid=users.id WHERE groupid=%s" % self.doQuote(group.ident))
392        if result :
393            for record in result :
394                user = self.storageUserFromRecord(self.databaseToUserCharset(record.get("username")), \
395                                                  record)
396                groupmembers.append(user)
397                self.cacheEntry("USERS", user.Name, user)
398        return groupmembers       
399       
400    def getUserGroupsFromBackend(self, user) :       
401        """Returns the user's groups list."""
402        groups = []
403        result = self.doSearch("SELECT groupname FROM groupsmembers JOIN groups ON groupsmembers.groupid=groups.id WHERE userid=%s" % self.doQuote(user.ident))
404        if result :
405            for record in result :
406                groups.append(self.getGroup(self.databaseToUserCharset(record.get("groupname"))))
407        return groups       
408       
409    def getParentPrintersFromBackend(self, printer) :   
410        """Get all the printer groups this printer is a member of."""
411        pgroups = []
412        result = self.doSearch("SELECT groupid,printername FROM printergroupsmembers JOIN printers ON groupid=id WHERE printerid=%s" % self.doQuote(printer.ident))
413        if result :
414            for record in result :
415                if record["groupid"] != printer.ident : # in case of integrity violation
416                    parentprinter = self.getPrinter(self.databaseToUserCharset(record.get("printername")))
417                    if parentprinter.Exists :
418                        pgroups.append(parentprinter)
419        return pgroups
420       
421    def getMatchingPrinters(self, printerpattern) :
422        """Returns the list of all printers for which name matches a certain pattern."""
423        printers = []
424        # We 'could' do a SELECT printername FROM printers WHERE printername LIKE ...
425        # but we don't because other storages semantics may be different, so every
426        # storage should use fnmatch to match patterns and be storage agnostic
427        result = self.doSearch("SELECT * FROM printers")
428        if result :
429            patterns = printerpattern.split(",")
430            try :
431                patdict = {}.fromkeys(patterns)
432            except AttributeError :   
433                # Python v2.2 or earlier
434                patdict = {}
435                for p in patterns :
436                    patdict[p] = None
437            for record in result :
438                pname = self.databaseToUserCharset(record["printername"])
439                if patdict.has_key(pname) or self.tool.matchString(pname, patterns) :
440                    printer = self.storagePrinterFromRecord(pname, record)
441                    printers.append(printer)
442                    self.cacheEntry("PRINTERS", printer.Name, printer)
443        return printers       
444       
445    def getMatchingUsers(self, userpattern) :
446        """Returns the list of all users for which name matches a certain pattern."""
447        users = []
448        # We 'could' do a SELECT username FROM users WHERE username LIKE ...
449        # but we don't because other storages semantics may be different, so every
450        # storage should use fnmatch to match patterns and be storage agnostic
451        result = self.doSearch("SELECT * FROM users")
452        if result :
453            patterns = userpattern.split(",")
454            try :
455                patdict = {}.fromkeys(patterns)
456            except AttributeError :   
457                # Python v2.2 or earlier
458                patdict = {}
459                for p in patterns :
460                    patdict[p] = None
461            for record in result :
462                uname = self.databaseToUserCharset(record["username"])
463                if patdict.has_key(uname) or self.tool.matchString(uname, patterns) :
464                    user = self.storageUserFromRecord(uname, record)
465                    users.append(user)
466                    self.cacheEntry("USERS", user.Name, user)
467        return users       
468       
469    def getMatchingGroups(self, grouppattern) :
470        """Returns the list of all groups for which name matches a certain pattern."""
471        groups = []
472        # We 'could' do a SELECT groupname FROM groups WHERE groupname LIKE ...
473        # but we don't because other storages semantics may be different, so every
474        # storage should use fnmatch to match patterns and be storage agnostic
475        result = self.doSearch("SELECT groups.*,COALESCE(SUM(balance), 0.0) AS balance, COALESCE(SUM(lifetimepaid), 0.0) AS lifetimepaid FROM groups LEFT OUTER JOIN users ON users.id IN (SELECT userid FROM groupsmembers WHERE groupid=groups.id) GROUP BY groups.id,groups.groupname,groups.limitby,groups.description")
476        if result :
477            patterns = grouppattern.split(",")
478            try :
479                patdict = {}.fromkeys(patterns)
480            except AttributeError :   
481                # Python v2.2 or earlier
482                patdict = {}
483                for p in patterns :
484                    patdict[p] = None
485            for record in result :
486                gname = self.databaseToUserCharset(record["groupname"])
487                if patdict.has_key(gname) or self.tool.matchString(gname, patterns) :
488                    group = self.storageGroupFromRecord(gname, record)
489                    groups.append(group)
490                    self.cacheEntry("GROUPS", group.Name, group)
491        return groups       
492       
493    def getMatchingBillingCodes(self, billingcodepattern) :
494        """Returns the list of all billing codes for which the label matches a certain pattern."""
495        codes = []
496        result = self.doSearch("SELECT * FROM billingcodes")
497        if result :
498            patterns = billingcodepattern.split(",")
499            try :
500                patdict = {}.fromkeys(patterns)
501            except AttributeError :   
502                # Python v2.2 or earlier
503                patdict = {}
504                for p in patterns :
505                    patdict[p] = None
506            for record in result :
507                codename = self.databaseToUserCharset(record["billingcode"])
508                if patdict.has_key(codename) or self.tool.matchString(codename, patterns) :
509                    code = self.storageBillingCodeFromRecord(codename, record)
510                    codes.append(code)
511                    self.cacheEntry("BILLINGCODES", code.BillingCode, code)
512        return codes       
513       
514    def getPrinterUsersAndQuotas(self, printer, names=["*"]) :       
515        """Returns the list of users who uses a given printer, along with their quotas."""
516        usersandquotas = []
517        result = self.doSearch("SELECT users.id as uid,username,description,balance,lifetimepaid,limitby,email,overcharge,userpquota.id,lifepagecounter,pagecounter,softlimit,hardlimit,datelimit,warncount FROM users JOIN userpquota ON users.id=userpquota.userid AND printerid=%s ORDER BY username ASC" % self.doQuote(printer.ident))
518        if result :
519            for record in result :
520                uname = self.databaseToUserCharset(record.get("username"))
521                if self.tool.matchString(uname, names) :
522                    user = self.storageUserFromRecord(uname, record)
523                    userpquota = self.storageUserPQuotaFromRecord(user, printer, record)
524                    usersandquotas.append((user, userpquota))
525                    self.cacheEntry("USERS", user.Name, user)
526                    self.cacheEntry("USERPQUOTAS", "%s@%s" % (user.Name, printer.Name), userpquota)
527        return usersandquotas
528               
529    def getPrinterGroupsAndQuotas(self, printer, names=["*"]) :       
530        """Returns the list of groups which uses a given printer, along with their quotas."""
531        groupsandquotas = []
532        result = self.doSearch("SELECT groupname FROM groups JOIN grouppquota ON groups.id=grouppquota.groupid AND printerid=%s ORDER BY groupname ASC" % self.doQuote(printer.ident))
533        if result :
534            for record in result :
535                gname = self.databaseToUserCharset(record.get("groupname"))
536                if self.tool.matchString(gname, names) :
537                    group = self.getGroup(gname)
538                    grouppquota = self.getGroupPQuota(group, printer)
539                    groupsandquotas.append((group, grouppquota))
540        return groupsandquotas
541       
542    def addPrinter(self, printer) :       
543        """Adds a printer to the quota storage, returns the old value if it already exists."""
544        oldentry = self.getPrinter(printer.Name)
545        if oldentry.Exists :
546            return oldentry
547        self.doModify("INSERT INTO printers (printername, passthrough, maxjobsize, description, priceperpage, priceperjob) VALUES (%s, %s, %s, %s, %s, %s)" \
548                          % (self.doQuote(self.userCharsetToDatabase(printer.Name)), \
549                             self.doQuote((printer.PassThrough and "t") or "f"), \
550                             self.doQuote(printer.MaxJobSize or 0), \
551                             self.doQuote(self.userCharsetToDatabase(printer.Description)), \
552                             self.doQuote(printer.PricePerPage or 0.0), \
553                             self.doQuote(printer.PricePerJob or 0.0)))
554        printer.isDirty = False
555        return None # the entry created doesn't need further modification
556       
557    def addBillingCode(self, bcode) :
558        """Adds a billing code to the quota storage, returns the old value if it already exists."""
559        oldentry = self.getBillingCode(bcode.BillingCode)
560        if oldentry.Exists :
561            return oldentry
562        self.doModify("INSERT INTO billingcodes (billingcode, balance, pagecounter, description) VALUES (%s, %s, %s, %s)" \
563                           % (self.doQuote(self.userCharsetToDatabase(bcode.BillingCode)), 
564                              self.doQuote(bcode.Balance or 0.0), \
565                              self.doQuote(bcode.PageCounter or 0), \
566                              self.doQuote(self.userCharsetToDatabase(bcode.Description))))
567        bcode.isDirty = False
568        return None # the entry created doesn't need further modification
569       
570    def addUser(self, user) :       
571        """Adds a user to the quota storage, returns the old value if it already exists."""
572        oldentry = self.getUser(user.Name)
573        if oldentry.Exists :
574            return oldentry
575        self.doModify("INSERT INTO users (username, limitby, balance, lifetimepaid, email, overcharge, description) VALUES (%s, %s, %s, %s, %s, %s, %s)" % \
576                                     (self.doQuote(self.userCharsetToDatabase(user.Name)), \
577                                      self.doQuote(user.LimitBy or 'quota'), \
578                                      self.doQuote(user.AccountBalance or 0.0), \
579                                      self.doQuote(user.LifeTimePaid or 0.0), \
580                                      self.doQuote(user.Email), \
581                                      self.doQuote(user.OverCharge), \
582                                      self.doQuote(self.userCharsetToDatabase(user.Description))))
583        if user.PaymentsBacklog :
584            for (value, comment) in user.PaymentsBacklog :
585                self.writeNewPayment(user, value, comment)
586            user.PaymentsBacklog = []
587        user.isDirty = False
588        return None # the entry created doesn't need further modification
589       
590    def addGroup(self, group) :       
591        """Adds a group to the quota storage, returns the old value if it already exists."""
592        oldentry = self.getGroup(group.Name)
593        if oldentry.Exists :
594            return oldentry
595        self.doModify("INSERT INTO groups (groupname, limitby, description) VALUES (%s, %s, %s)" % \
596                              (self.doQuote(self.userCharsetToDatabase(group.Name)), \
597                               self.doQuote(group.LimitBy or "quota"), \
598                               self.doQuote(self.userCharsetToDatabase(group.Description))))
599        group.isDirty = False
600        return None # the entry created doesn't need further modification
601
602    def addUserToGroup(self, user, group) :   
603        """Adds an user to a group."""
604        result = self.doSearch("SELECT COUNT(*) AS mexists FROM groupsmembers WHERE groupid=%s AND userid=%s" % (self.doQuote(group.ident), self.doQuote(user.ident)))
605        try :
606            mexists = int(result[0].get("mexists"))
607        except (IndexError, TypeError) :   
608            mexists = 0
609        if not mexists :   
610            self.doModify("INSERT INTO groupsmembers (groupid, userid) VALUES (%s, %s)" % (self.doQuote(group.ident), self.doQuote(user.ident)))
611           
612    def delUserFromGroup(self, user, group) :   
613        """Removes an user from a group."""
614        self.doModify("DELETE FROM groupsmembers WHERE groupid=%s AND userid=%s" % \
615                       (self.doQuote(group.ident), self.doQuote(user.ident)))
616           
617    def addUserPQuota(self, upq) :
618        """Initializes a user print quota on a printer."""
619        oldentry = self.getUserPQuota(upq.User, upq.Printer)
620        if oldentry.Exists :
621            return oldentry
622        self.doModify("INSERT INTO userpquota (userid, printerid, softlimit, hardlimit, warncount, datelimit, pagecounter, lifepagecounter, maxjobsize) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" \
623                          % (self.doQuote(upq.User.ident), \
624                             self.doQuote(upq.Printer.ident), \
625                             self.doQuote(upq.SoftLimit), \
626                             self.doQuote(upq.HardLimit), \
627                             self.doQuote(upq.WarnCount or 0), \
628                             self.doQuote(upq.DateLimit), \
629                             self.doQuote(upq.PageCounter or 0), \
630                             self.doQuote(upq.LifePageCounter or 0), \
631                             self.doQuote(upq.MaxJobSize)))
632        upq.isDirty = False
633        return None # the entry created doesn't need further modification
634       
635    def addGroupPQuota(self, gpq) :
636        """Initializes a group print quota on a printer."""
637        oldentry = self.getGroupPQuota(gpq.Group, gpq.Printer)
638        if oldentry.Exists :
639            return oldentry
640        self.doModify("INSERT INTO grouppquota (groupid, printerid, softlimit, hardlimit, datelimit, maxjobsize) VALUES (%s, %s, %s, %s, %s, %s)" \
641                          % (self.doQuote(gpq.Group.ident), \
642                             self.doQuote(gpq.Printer.ident), \
643                             self.doQuote(gpq.SoftLimit), \
644                             self.doQuote(gpq.HardLimit), \
645                             self.doQuote(gpq.DateLimit), \
646                             self.doQuote(gpq.MaxJobSize)))
647        gpq.isDirty = False
648        return None # the entry created doesn't need further modification
649       
650    def savePrinter(self, printer) :   
651        """Saves the printer to the database in a single operation."""
652        self.doModify("UPDATE printers SET passthrough=%s, maxjobsize=%s, description=%s, priceperpage=%s, priceperjob=%s WHERE id=%s" \
653                              % (self.doQuote((printer.PassThrough and "t") or "f"), \
654                                 self.doQuote(printer.MaxJobSize or 0), \
655                                 self.doQuote(self.userCharsetToDatabase(printer.Description)), \
656                                 self.doQuote(printer.PricePerPage or 0.0), \
657                                 self.doQuote(printer.PricePerJob or 0.0), \
658                                 self.doQuote(printer.ident)))
659                                 
660    def saveUser(self, user) :       
661        """Saves the user to the database in a single operation."""
662        self.doModify("UPDATE users SET limitby=%s, balance=%s, lifetimepaid=%s, email=%s, overcharge=%s, description=%s WHERE id=%s" \
663                               % (self.doQuote(user.LimitBy or 'quota'), \
664                                  self.doQuote(user.AccountBalance or 0.0), \
665                                  self.doQuote(user.LifeTimePaid or 0.0), \
666                                  self.doQuote(user.Email), \
667                                  self.doQuote(user.OverCharge), \
668                                  self.doQuote(self.userCharsetToDatabase(user.Description)), \
669                                  self.doQuote(user.ident)))
670                                 
671    def saveGroup(self, group) :       
672        """Saves the group to the database in a single operation."""
673        self.doModify("UPDATE groups SET limitby=%s, description=%s WHERE id=%s" \
674                               % (self.doQuote(group.LimitBy or 'quota'), \
675                                  self.doQuote(self.userCharsetToDatabase(group.Description)), \
676                                  self.doQuote(group.ident)))
677       
678    def writeUserPQuotaDateLimit(self, userpquota, datelimit) :   
679        """Sets the date limit permanently for a user print quota."""
680        self.doModify("UPDATE userpquota SET datelimit=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(userpquota.ident)))
681           
682    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :   
683        """Sets the date limit permanently for a group print quota."""
684        self.doModify("UPDATE grouppquota SET datelimit=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(grouppquota.ident)))
685       
686    def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) :   
687        """Increase page counters for a user print quota."""
688        self.doModify("UPDATE userpquota SET pagecounter=pagecounter + %s,lifepagecounter=lifepagecounter + %s WHERE id=%s" % (self.doQuote(nbpages), self.doQuote(nbpages), self.doQuote(userpquota.ident)))
689       
690    def saveBillingCode(self, bcode) :   
691        """Saves the billing code to the database."""
692        self.doModify("UPDATE billingcodes SET balance=%s, pagecounter=%s, description=%s WHERE id=%s" \
693                            % (self.doQuote(bcode.Balance or 0.0), \
694                               self.doQuote(bcode.PageCounter or 0), \
695                               self.doQuote(self.userCharsetToDatabase(bcode.Description)), \
696                               self.doQuote(bcode.ident)))
697       
698    def consumeBillingCode(self, bcode, pagecounter, balance) :
699        """Consumes from a billing code."""
700        self.doModify("UPDATE billingcodes SET balance=balance + %s, pagecounter=pagecounter + %s WHERE id=%s" % (self.doQuote(balance), self.doQuote(pagecounter), self.doQuote(bcode.ident)))
701       
702    def refundJob(self, jobident) :   
703        """Marks a job as refunded in the history."""
704        self.doModify("UPDATE jobhistory SET action='REFUND' WHERE id=%s;" % self.doQuote(jobident))
705       
706    def decreaseUserAccountBalance(self, user, amount) :   
707        """Decreases user's account balance from an amount."""
708        self.doModify("UPDATE users SET balance=balance - %s WHERE id=%s" % (self.doQuote(amount), self.doQuote(user.ident)))
709       
710    def writeNewPayment(self, user, amount, comment="") :
711        """Adds a new payment to the payments history."""
712        if user.ident is not None :
713            self.doModify("INSERT INTO payments (userid, amount, description) VALUES (%s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(amount), self.doQuote(self.userCharsetToDatabase(comment))))
714        else :   
715            self.doModify("INSERT INTO payments (userid, amount, description) VALUES ((SELECT id FROM users WHERE username=%s), %s, %s)" % (self.doQuote(self.userCharsetToDatabase(user.Name)), self.doQuote(amount), self.doQuote(self.userCharsetToDatabase(comment))))
716       
717    def writeLastJobSize(self, lastjob, jobsize, jobprice) :       
718        """Sets the last job's size permanently."""
719        self.doModify("UPDATE jobhistory SET jobsize=%s, jobprice=%s WHERE id=%s" % (self.doQuote(jobsize), self.doQuote(jobprice), self.doQuote(lastjob.ident)))
720       
721    def writeJobNew(self, printer, user, jobid, 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) :
722        """Adds a job in a printer's history."""
723        if self.privacy :   
724            # For legal reasons, we want to hide the title, filename and options
725            title = filename = options = "hidden"
726        filename = self.userCharsetToDatabase(filename)
727        title = self.userCharsetToDatabase(title)
728        options = self.userCharsetToDatabase(options)
729        jobbilling = self.userCharsetToDatabase(jobbilling)
730        if (not self.disablehistory) or (not printer.LastJob.Exists) :
731            if jobsize is not None :
732                self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, jobsize, jobprice, filename, title, copies, options, hostname, jobsizebytes, md5sum, pages, billingcode, precomputedjobsize, precomputedjobprice) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(jobsize), self.doQuote(jobprice), self.doQuote(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options), self.doQuote(clienthost), self.doQuote(jobsizebytes), self.doQuote(jobmd5sum), self.doQuote(jobpages), self.doQuote(jobbilling), self.doQuote(precomputedsize), self.doQuote(precomputedprice)))
733            else :   
734                self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, filename, title, copies, options, hostname, jobsizebytes, md5sum, pages, billingcode, precomputedjobsize, precomputedjobprice) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options), self.doQuote(clienthost), self.doQuote(jobsizebytes), self.doQuote(jobmd5sum), self.doQuote(jobpages), self.doQuote(jobbilling), self.doQuote(precomputedsize), self.doQuote(precomputedprice)))
735        else :       
736            # here we explicitly want to reset jobsize to NULL if needed
737            self.doModify("UPDATE jobhistory SET userid=%s, jobid=%s, pagecounter=%s, action=%s, jobsize=%s, jobprice=%s, filename=%s, title=%s, copies=%s, options=%s, hostname=%s, jobsizebytes=%s, md5sum=%s, pages=%s, billingcode=%s, precomputedjobsize=%s, precomputedjobprice=%s, jobdate=now() WHERE id=%s" % (self.doQuote(user.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(jobsize), self.doQuote(jobprice), self.doQuote(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options), self.doQuote(clienthost), self.doQuote(jobsizebytes), self.doQuote(jobmd5sum), self.doQuote(jobpages), self.doQuote(jobbilling), self.doQuote(precomputedsize), self.doQuote(precomputedprice), self.doQuote(printer.LastJob.ident)))
738           
739    def saveUserPQuota(self, userpquota) :
740        """Saves an user print quota entry."""
741        self.doModify("UPDATE userpquota SET softlimit=%s, hardlimit=%s, warncount=%s, datelimit=%s, pagecounter=%s, lifepagecounter=%s, maxjobsize=%s WHERE id=%s" \
742                              % (self.doQuote(userpquota.SoftLimit), \
743                                 self.doQuote(userpquota.HardLimit), \
744                                 self.doQuote(userpquota.WarnCount or 0), \
745                                 self.doQuote(userpquota.DateLimit), \
746                                 self.doQuote(userpquota.PageCounter or 0), \
747                                 self.doQuote(userpquota.LifePageCounter or 0), \
748                                 self.doQuote(userpquota.MaxJobSize), \
749                                 self.doQuote(userpquota.ident)))
750       
751    def writeUserPQuotaWarnCount(self, userpquota, warncount) :
752        """Sets the warn counter value for a user quota."""
753        self.doModify("UPDATE userpquota SET warncount=%s WHERE id=%s" % (self.doQuote(warncount), self.doQuote(userpquota.ident)))
754       
755    def increaseUserPQuotaWarnCount(self, userpquota) :
756        """Increases the warn counter value for a user quota."""
757        self.doModify("UPDATE userpquota SET warncount=warncount+1 WHERE id=%s" % self.doQuote(userpquota.ident))
758       
759    def saveGroupPQuota(self, grouppquota) :
760        """Saves a group print quota entry."""
761        self.doModify("UPDATE grouppquota SET softlimit=%s, hardlimit=%s, datelimit=%s WHERE id=%s" \
762                              % (self.doQuote(grouppquota.SoftLimit), \
763                                 self.doQuote(grouppquota.HardLimit), \
764                                 self.doQuote(grouppquota.DateLimit), \
765                                 self.doQuote(grouppquota.ident)))
766
767    def writePrinterToGroup(self, pgroup, printer) :
768        """Puts a printer into a printer group."""
769        children = []
770        result = self.doSearch("SELECT printerid FROM printergroupsmembers WHERE groupid=%s" % self.doQuote(pgroup.ident))
771        if result :
772            for record in result :
773                children.append(record.get("printerid")) # TODO : put this into the database integrity rules
774        if printer.ident not in children :       
775            self.doModify("INSERT INTO printergroupsmembers (groupid, printerid) VALUES (%s, %s)" % (self.doQuote(pgroup.ident), self.doQuote(printer.ident)))
776       
777    def removePrinterFromGroup(self, pgroup, printer) :
778        """Removes a printer from a printer group."""
779        self.doModify("DELETE FROM printergroupsmembers WHERE groupid=%s AND printerid=%s" % (self.doQuote(pgroup.ident), self.doQuote(printer.ident)))
780       
781    def retrieveHistory(self, user=None, printer=None, hostname=None, billingcode=None, jobid=None, limit=100, start=None, end=None) :
782        """Retrieves all print jobs for user on printer (or all) between start and end date, limited to first 100 results."""
783        query = "SELECT jobhistory.*,username,printername FROM jobhistory,users,printers WHERE users.id=userid AND printers.id=printerid"
784        where = []
785        if user is not None : # user.ident is None anyway if user doesn't exist
786            where.append("userid=%s" % self.doQuote(user.ident))
787        if printer is not None : # printer.ident is None anyway if printer doesn't exist
788            where.append("printerid=%s" % self.doQuote(printer.ident))
789        if hostname is not None :   
790            where.append("hostname=%s" % self.doQuote(hostname))
791        if billingcode is not None :   
792            where.append("billingcode=%s" % self.doQuote(self.userCharsetToDatabase(billingcode)))
793        if jobid is not None :   
794            where.append("jobid=%s" % self.doQuote(jobid)) # TODO : jobid is text, so self.userCharsetToDatabase(jobid) but do all of them as well.
795        if start is not None :   
796            where.append("jobdate>=%s" % self.doQuote(start))
797        if end is not None :   
798            where.append("jobdate<=%s" % self.doQuote(end))
799        if where :   
800            query += " AND %s" % " AND ".join(where)
801        query += " ORDER BY jobhistory.id DESC"
802        if limit :
803            query += " LIMIT %s" % self.doQuote(int(limit))
804        jobs = []   
805        result = self.doSearch(query)   
806        if result :
807            for fields in result :
808                job = self.storageJobFromRecord(fields)
809                jobs.append(job)
810        return jobs
811       
812    def deleteUser(self, user) :   
813        """Completely deletes an user from the database."""
814        # TODO : What should we do if we delete the last person who used a given printer ?
815        # TODO : we can't reassign the last job to the previous one, because next user would be
816        # TODO : incorrectly charged (overcharged).
817        for q in [ 
818                    "DELETE FROM payments WHERE userid=%s" % self.doQuote(user.ident),
819                    "DELETE FROM groupsmembers WHERE userid=%s" % self.doQuote(user.ident),
820                    "DELETE FROM jobhistory WHERE userid=%s" % self.doQuote(user.ident),
821                    "DELETE FROM userpquota WHERE userid=%s" % self.doQuote(user.ident),
822                    "DELETE FROM users WHERE id=%s" % self.doQuote(user.ident),
823                  ] :
824            self.doModify(q)
825           
826    def multipleQueriesInTransaction(self, queries) :       
827        """Does many modifications in a single transaction."""
828        self.beginTransaction()
829        try :
830            for q in queries :
831                self.doModify(q)
832        except :   
833            self.rollbackTransaction()
834            raise
835        else :   
836            self.commitTransaction()
837           
838    def deleteManyBillingCodes(self, billingcodes) :       
839        """Deletes many billing codes."""
840        codeids = ", ".join(["%s" % self.doQuote(b.ident) for b in billingcodes])
841        if codeids :
842            self.multipleQueriesInTransaction([ 
843                    "DELETE FROM billingcodes WHERE id IN (%s)" % codeids,])
844           
845    def deleteManyUsers(self, users) :       
846        """Deletes many users."""
847        userids = ", ".join(["%s" % self.doQuote(u.ident) for u in users])
848        if userids :
849            self.multipleQueriesInTransaction([ 
850                    "DELETE FROM payments WHERE userid IN (%s)" % userids,
851                    "DELETE FROM groupsmembers WHERE userid IN (%s)" % userids,
852                    "DELETE FROM jobhistory WHERE userid IN (%s)" % userids,
853                    "DELETE FROM userpquota WHERE userid IN (%s)" % userids,
854                    "DELETE FROM users WHERE id IN (%s)" % userids,])
855                   
856    def deleteManyGroups(self, groups) :       
857        """Deletes many groups."""
858        groupids = ", ".join(["%s" % self.doQuote(g.ident) for g in groups])
859        if groupids :
860            self.multipleQueriesInTransaction([ 
861                    "DELETE FROM groupsmembers WHERE groupid IN (%s)" % groupids,
862                    "DELETE FROM grouppquota WHERE groupid IN (%s)" % groupids,
863                    "DELETE FROM groups WHERE id IN (%s)" % groupids,])
864       
865    def deleteManyPrinters(self, printers) :
866        """Deletes many printers."""
867        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers])
868        if printerids :
869            self.multipleQueriesInTransaction([ 
870                    "DELETE FROM printergroupsmembers WHERE groupid IN (%s) OR printerid IN (%s)" % (printerids, printerids),
871                    "DELETE FROM jobhistory WHERE printerid IN (%s)" % printerids,
872                    "DELETE FROM grouppquota WHERE printerid IN (%s)" % printerids,
873                    "DELETE FROM userpquota WHERE printerid IN (%s)" % printerids,
874                    "DELETE FROM printers WHERE id IN (%s)" % printerids,])
875       
876    def deleteManyUserPQuotas(self, printers, users) :       
877        """Deletes many user print quota entries."""
878        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers])
879        userids = ", ".join(["%s" % self.doQuote(u.ident) for u in users])
880        if userids and printerids :
881            self.multipleQueriesInTransaction([ 
882                    "DELETE FROM jobhistory WHERE userid IN (%s) AND printerid IN (%s)" \
883                                 % (userids, printerids),
884                    "DELETE FROM userpquota WHERE userid IN (%s) AND printerid IN (%s)" \
885                                 % (userids, printerids),])
886           
887    def deleteManyGroupPQuotas(self, printers, groups) :
888        """Deletes many group print quota entries."""
889        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers])
890        groupids = ", ".join(["%s" % self.doQuote(g.ident) for g in groups])
891        if groupids and printerids :
892            self.multipleQueriesInTransaction([ 
893                    "DELETE FROM grouppquota WHERE groupid IN (%s) AND printerid IN (%s)" \
894                                 % (groupids, printerids),])
895       
896    def deleteUserPQuota(self, upquota) :   
897        """Completely deletes an user print quota entry from the database."""
898        for q in [ 
899                    "DELETE FROM jobhistory WHERE userid=%s AND printerid=%s" \
900                                 % (self.doQuote(upquota.User.ident), self.doQuote(upquota.Printer.ident)),
901                    "DELETE FROM userpquota WHERE id=%s" % self.doQuote(upquota.ident),
902                  ] :
903            self.doModify(q)
904       
905    def deleteGroupPQuota(self, gpquota) :   
906        """Completely deletes a group print quota entry from the database."""
907        for q in [ 
908                    "DELETE FROM grouppquota WHERE id=%s" % self.doQuote(gpquota.ident),
909                  ] :
910            self.doModify(q)
911       
912    def deleteGroup(self, group) :   
913        """Completely deletes a group from the database."""
914        for q in [
915                   "DELETE FROM groupsmembers WHERE groupid=%s" % self.doQuote(group.ident),
916                   "DELETE FROM grouppquota WHERE groupid=%s" % self.doQuote(group.ident),
917                   "DELETE FROM groups WHERE id=%s" % self.doQuote(group.ident),
918                 ] : 
919            self.doModify(q)
920           
921    def deletePrinter(self, printer) :   
922        """Completely deletes a printer from the database."""
923        for q in [ 
924                    "DELETE FROM printergroupsmembers WHERE groupid=%s OR printerid=%s" % (self.doQuote(printer.ident), self.doQuote(printer.ident)),
925                    "DELETE FROM jobhistory WHERE printerid=%s" % self.doQuote(printer.ident),
926                    "DELETE FROM grouppquota WHERE printerid=%s" % self.doQuote(printer.ident),
927                    "DELETE FROM userpquota WHERE printerid=%s" % self.doQuote(printer.ident),
928                    "DELETE FROM printers WHERE id=%s" % self.doQuote(printer.ident),
929                  ] :
930            self.doModify(q)
931           
932    def deleteBillingCode(self, code) :   
933        """Completely deletes a billing code from the database."""
934        for q in [
935                   "DELETE FROM billingcodes WHERE id=%s" % self.doQuote(code.ident),
936                 ] : 
937            self.doModify(q)
938       
Note: See TracBrowser for help on using the browser.