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

Revision 3056, 53.2 kB (checked in by jerome, 17 years ago)

The code to refund jobs is there and works (at least with PostgreSQL).
Only the pkrefund command line tool (and CGI script ?) is missing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2# -*- coding: ISO-8859-15 -*-
3#
4# PyKota : Print Quotas for CUPS and LPRng
5#
6# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20#
21# $Id$
22#
23#
24
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        thefilter = self.createFilter(extractonly)
190        if thefilter :
191            thefilter = "AND %s" % thefilter
192        result = self.doRawSearch("SELECT username,payments.* FROM users,payments WHERE users.id=payments.userid %s ORDER BY payments.id ASC" % thefilter)
193        return self.prepareRawResult(result)
194       
195    def extractUpquotas(self, extractonly={}) :
196        """Extracts all userpquota records."""
197        thefilter = self.createFilter(extractonly)
198        if thefilter :
199            thefilter = "AND %s" % thefilter
200        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)
201        return self.prepareRawResult(result)
202       
203    def extractGpquotas(self, extractonly={}) :
204        """Extracts all grouppquota records."""
205        thefilter = self.createFilter(extractonly)
206        if thefilter :
207            thefilter = "AND %s" % thefilter
208        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)
209        return self.prepareRawResult(result)
210       
211    def extractUmembers(self, extractonly={}) :
212        """Extracts all user groups members."""
213        thefilter = self.createFilter(extractonly)
214        if thefilter :
215            thefilter = "AND %s" % thefilter
216        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)
217        return self.prepareRawResult(result)
218       
219    def extractPmembers(self, extractonly={}) :
220        """Extracts all printer groups members."""
221        for (k, v) in extractonly.items() :
222            if k == "pgroupname" :
223                del extractonly[k]
224                extractonly["p1.printername"] = v
225            elif k == "printername" :
226                del extractonly[k]
227                extractonly["p2.printername"] = v
228        thefilter = self.createFilter(extractonly)
229        if thefilter :
230            thefilter = "AND %s" % thefilter
231        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)
232        return self.prepareRawResult(result)
233       
234    def extractHistory(self, extractonly={}) :
235        """Extracts all jobhistory records."""
236        startdate = extractonly.get("start")
237        enddate = extractonly.get("end")
238        for limit in ("start", "end") :
239            try :
240                del extractonly[limit]
241            except KeyError :   
242                pass
243        thefilter = self.createFilter(extractonly)
244        if thefilter :
245            thefilter = "AND %s" % thefilter
246        (startdate, enddate) = self.cleanDates(startdate, enddate)
247        if startdate : 
248            thefilter = "%s AND jobdate>=%s" % (thefilter, self.doQuote(startdate))
249        if enddate : 
250            thefilter = "%s AND jobdate<=%s" % (thefilter, self.doQuote(enddate))
251        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)
252        return self.prepareRawResult(result)
253           
254    def filterNames(self, records, attribute, patterns=None) :
255        """Returns a list of 'attribute' from a list of records.
256       
257           Logs any missing attribute.
258        """   
259        result = []
260        for record in records :
261            attrval = record.get(attribute, [None])
262            if attrval is None :
263                self.tool.printInfo("Object %s has no %s attribute !" % (repr(record), attribute), "error")
264            else :
265                attrval = self.databaseToUserCharset(attrval)
266                if patterns :
267                    if (not isinstance(patterns, type([]))) and (not isinstance(patterns, type(()))) :
268                        patterns = [ patterns ]
269                    if self.tool.matchString(attrval, patterns) :
270                        result.append(attrval)
271                else :   
272                    result.append(attrval)
273        return result   
274               
275    def getAllBillingCodes(self, billingcode=None) :   
276        """Extracts all billing codes or only the billing codes matching the optional parameter."""
277        result = self.doSearch("SELECT billingcode FROM billingcodes")
278        if result :
279            return self.filterNames(result, "billingcode", billingcode)
280        else :   
281            return []
282       
283    def getAllPrintersNames(self, printername=None) :   
284        """Extracts all printer names or only the printers' names matching the optional parameter."""
285        result = self.doSearch("SELECT printername FROM printers")
286        if result :
287            return self.filterNames(result, "printername", printername)
288        else :   
289            return []
290   
291    def getAllUsersNames(self, username=None) :   
292        """Extracts all user names."""
293        result = self.doSearch("SELECT username FROM users")
294        if result :
295            return self.filterNames(result, "username", username)
296        else :   
297            return []
298       
299    def getAllGroupsNames(self, groupname=None) :   
300        """Extracts all group names."""
301        result = self.doSearch("SELECT groupname FROM groups")
302        if result :
303            return self.filterNames(result, "groupname", groupname)
304        else :
305            return []
306       
307    def getUserNbJobsFromHistory(self, user) :
308        """Returns the number of jobs the user has in history."""
309        result = self.doSearch("SELECT COUNT(*) FROM jobhistory WHERE userid=%s" % self.doQuote(user.ident))
310        if result :
311            return result[0]["count"]
312        return 0
313       
314    def getUserFromBackend(self, username) :   
315        """Extracts user information given its name."""
316        result = self.doSearch("SELECT * FROM users WHERE username=%s LIMIT 1"\
317                      % self.doQuote(self.userCharsetToDatabase(username)))
318        if result :
319            return self.storageUserFromRecord(username, result[0])
320        else :   
321            return StorageUser(self, username)
322       
323    def getGroupFromBackend(self, groupname) :   
324        """Extracts group information given its name."""
325        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" \
326                      % self.doQuote(self.userCharsetToDatabase(groupname)))
327        if result :
328            return self.storageGroupFromRecord(groupname, result[0])
329        else :   
330            return StorageGroup(self, groupname)
331       
332    def getPrinterFromBackend(self, printername) :       
333        """Extracts printer information given its name."""
334        result = self.doSearch("SELECT * FROM printers WHERE printername=%s LIMIT 1" \
335                      % self.doQuote(self.userCharsetToDatabase(printername)))
336        if result :
337            return self.storagePrinterFromRecord(printername, result[0])
338        else :   
339            return StoragePrinter(self, printername)
340       
341    def getBillingCodeFromBackend(self, label) :       
342        """Extracts a billing code information given its name."""
343        result = self.doSearch("SELECT * FROM billingcodes WHERE billingcode=%s LIMIT 1" \
344                      % self.doQuote(self.userCharsetToDatabase(label)))
345        if result :
346            return self.storageBillingCodeFromRecord(label, result[0])
347        else :   
348            return StorageBillingCode(self, label)
349       
350    def getUserPQuotaFromBackend(self, user, printer) :       
351        """Extracts a user print quota."""
352        if printer.Exists and user.Exists :
353            result = self.doSearch("SELECT * FROM userpquota WHERE userid=%s AND printerid=%s;" \
354                          % (self.doQuote(user.ident), self.doQuote(printer.ident)))
355            if result :
356                return self.storageUserPQuotaFromRecord(user, printer, result[0])
357        return StorageUserPQuota(self, user, printer)
358       
359    def getGroupPQuotaFromBackend(self, group, printer) :       
360        """Extracts a group print quota."""
361        if printer.Exists and group.Exists :
362            result = self.doSearch("SELECT * FROM grouppquota WHERE groupid=%s AND printerid=%s" \
363                          % (self.doQuote(group.ident), self.doQuote(printer.ident)))
364            if result :
365                return self.storageGroupPQuotaFromRecord(group, printer, result[0])
366        return StorageGroupPQuota(self, group, printer)
367       
368    def getPrinterLastJobFromBackend(self, printer) :       
369        """Extracts a printer's last job information."""
370        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))
371        if result :
372            return self.storageLastJobFromRecord(printer, result[0])
373        else :   
374            return StorageLastJob(self, printer)
375           
376    def getGroupMembersFromBackend(self, group) :       
377        """Returns the group's members list."""
378        groupmembers = []
379        result = self.doSearch("SELECT * FROM groupsmembers JOIN users ON groupsmembers.userid=users.id WHERE groupid=%s" % self.doQuote(group.ident))
380        if result :
381            for record in result :
382                user = self.storageUserFromRecord(self.databaseToUserCharset(record.get("username")), \
383                                                  record)
384                groupmembers.append(user)
385                self.cacheEntry("USERS", user.Name, user)
386        return groupmembers       
387       
388    def getUserGroupsFromBackend(self, user) :       
389        """Returns the user's groups list."""
390        groups = []
391        result = self.doSearch("SELECT groupname FROM groupsmembers JOIN groups ON groupsmembers.groupid=groups.id WHERE userid=%s" % self.doQuote(user.ident))
392        if result :
393            for record in result :
394                groups.append(self.getGroup(self.databaseToUserCharset(record.get("groupname"))))
395        return groups       
396       
397    def getParentPrintersFromBackend(self, printer) :   
398        """Get all the printer groups this printer is a member of."""
399        pgroups = []
400        result = self.doSearch("SELECT groupid,printername FROM printergroupsmembers JOIN printers ON groupid=id WHERE printerid=%s" % self.doQuote(printer.ident))
401        if result :
402            for record in result :
403                if record["groupid"] != printer.ident : # in case of integrity violation
404                    parentprinter = self.getPrinter(self.databaseToUserCharset(record.get("printername")))
405                    if parentprinter.Exists :
406                        pgroups.append(parentprinter)
407        return pgroups
408       
409    def getMatchingPrinters(self, printerpattern) :
410        """Returns the list of all printers for which name matches a certain pattern."""
411        printers = []
412        # We 'could' do a SELECT printername FROM printers WHERE printername LIKE ...
413        # but we don't because other storages semantics may be different, so every
414        # storage should use fnmatch to match patterns and be storage agnostic
415        result = self.doSearch("SELECT * FROM printers")
416        if result :
417            patterns = printerpattern.split(",")
418            try :
419                patdict = {}.fromkeys(patterns)
420            except AttributeError :   
421                # Python v2.2 or earlier
422                patdict = {}
423                for p in patterns :
424                    patdict[p] = None
425            for record in result :
426                pname = self.databaseToUserCharset(record["printername"])
427                if patdict.has_key(pname) or self.tool.matchString(pname, patterns) :
428                    printer = self.storagePrinterFromRecord(pname, record)
429                    printers.append(printer)
430                    self.cacheEntry("PRINTERS", printer.Name, printer)
431        return printers       
432       
433    def getMatchingUsers(self, userpattern) :
434        """Returns the list of all users for which name matches a certain pattern."""
435        users = []
436        # We 'could' do a SELECT username FROM users WHERE username LIKE ...
437        # but we don't because other storages semantics may be different, so every
438        # storage should use fnmatch to match patterns and be storage agnostic
439        result = self.doSearch("SELECT * FROM users")
440        if result :
441            patterns = userpattern.split(",")
442            try :
443                patdict = {}.fromkeys(patterns)
444            except AttributeError :   
445                # Python v2.2 or earlier
446                patdict = {}
447                for p in patterns :
448                    patdict[p] = None
449            for record in result :
450                uname = self.databaseToUserCharset(record["username"])
451                if patdict.has_key(uname) or self.tool.matchString(uname, patterns) :
452                    user = self.storageUserFromRecord(uname, record)
453                    users.append(user)
454                    self.cacheEntry("USERS", user.Name, user)
455        return users       
456       
457    def getMatchingGroups(self, grouppattern) :
458        """Returns the list of all groups for which name matches a certain pattern."""
459        groups = []
460        # We 'could' do a SELECT groupname FROM groups WHERE groupname LIKE ...
461        # but we don't because other storages semantics may be different, so every
462        # storage should use fnmatch to match patterns and be storage agnostic
463        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")
464        if result :
465            patterns = grouppattern.split(",")
466            try :
467                patdict = {}.fromkeys(patterns)
468            except AttributeError :   
469                # Python v2.2 or earlier
470                patdict = {}
471                for p in patterns :
472                    patdict[p] = None
473            for record in result :
474                gname = self.databaseToUserCharset(record["groupname"])
475                if patdict.has_key(gname) or self.tool.matchString(gname, patterns) :
476                    group = self.storageGroupFromRecord(gname, record)
477                    groups.append(group)
478                    self.cacheEntry("GROUPS", group.Name, group)
479        return groups       
480       
481    def getMatchingBillingCodes(self, billingcodepattern) :
482        """Returns the list of all billing codes for which the label matches a certain pattern."""
483        codes = []
484        result = self.doSearch("SELECT * FROM billingcodes")
485        if result :
486            patterns = billingcodepattern.split(",")
487            try :
488                patdict = {}.fromkeys(patterns)
489            except AttributeError :   
490                # Python v2.2 or earlier
491                patdict = {}
492                for p in patterns :
493                    patdict[p] = None
494            for record in result :
495                codename = self.databaseToUserCharset(record["billingcode"])
496                if patdict.has_key(codename) or self.tool.matchString(codename, patterns) :
497                    code = self.storageBillingCodeFromRecord(codename, record)
498                    codes.append(code)
499                    self.cacheEntry("BILLINGCODES", code.BillingCode, code)
500        return codes       
501       
502    def getPrinterUsersAndQuotas(self, printer, names=["*"]) :       
503        """Returns the list of users who uses a given printer, along with their quotas."""
504        usersandquotas = []
505        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))
506        if result :
507            for record in result :
508                uname = self.databaseToUserCharset(record.get("username"))
509                if self.tool.matchString(uname, names) :
510                    user = self.storageUserFromRecord(uname, record)
511                    userpquota = self.storageUserPQuotaFromRecord(user, printer, record)
512                    usersandquotas.append((user, userpquota))
513                    self.cacheEntry("USERS", user.Name, user)
514                    self.cacheEntry("USERPQUOTAS", "%s@%s" % (user.Name, printer.Name), userpquota)
515        return usersandquotas
516               
517    def getPrinterGroupsAndQuotas(self, printer, names=["*"]) :       
518        """Returns the list of groups which uses a given printer, along with their quotas."""
519        groupsandquotas = []
520        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))
521        if result :
522            for record in result :
523                gname = self.databaseToUserCharset(record.get("groupname"))
524                if self.tool.matchString(gname, names) :
525                    group = self.getGroup(gname)
526                    grouppquota = self.getGroupPQuota(group, printer)
527                    groupsandquotas.append((group, grouppquota))
528        return groupsandquotas
529       
530    def addPrinter(self, printer) :       
531        """Adds a printer to the quota storage, returns the old value if it already exists."""
532        oldentry = self.getPrinter(printer.Name)
533        if oldentry.Exists :
534            return oldentry
535        self.doModify("INSERT INTO printers (printername, passthrough, maxjobsize, description, priceperpage, priceperjob) VALUES (%s, %s, %s, %s, %s, %s)" \
536                          % (self.doQuote(self.userCharsetToDatabase(printer.Name)), \
537                             self.doQuote((printer.PassThrough and "t") or "f"), \
538                             self.doQuote(printer.MaxJobSize or 0), \
539                             self.doQuote(self.userCharsetToDatabase(printer.Description)), \
540                             self.doQuote(printer.PricePerPage or 0.0), \
541                             self.doQuote(printer.PricePerJob or 0.0)))
542        printer.isDirty = False
543        return None # the entry created doesn't need further modification
544       
545    def addBillingCode(self, bcode) :
546        """Adds a billing code to the quota storage, returns the old value if it already exists."""
547        oldentry = self.getBillingCode(bcode.BillingCode)
548        if oldentry.Exists :
549            return oldentry
550        self.doModify("INSERT INTO billingcodes (billingcode, balance, pagecounter, description) VALUES (%s, %s, %s, %s)" \
551                           % (self.doQuote(self.userCharsetToDatabase(bcode.BillingCode)), 
552                              self.doQuote(bcode.Balance or 0.0), \
553                              self.doQuote(bcode.PageCounter or 0), \
554                              self.doQuote(self.userCharsetToDatabase(bcode.Description))))
555        bcode.isDirty = False
556        return None # the entry created doesn't need further modification
557       
558    def addUser(self, user) :       
559        """Adds a user to the quota storage, returns the old value if it already exists."""
560        oldentry = self.getUser(user.Name)
561        if oldentry.Exists :
562            return oldentry
563        self.doModify("INSERT INTO users (username, limitby, balance, lifetimepaid, email, overcharge, description) VALUES (%s, %s, %s, %s, %s, %s, %s)" % \
564                                     (self.doQuote(self.userCharsetToDatabase(user.Name)), \
565                                      self.doQuote(user.LimitBy or 'quota'), \
566                                      self.doQuote(user.AccountBalance or 0.0), \
567                                      self.doQuote(user.LifeTimePaid or 0.0), \
568                                      self.doQuote(user.Email), \
569                                      self.doQuote(user.OverCharge), \
570                                      self.doQuote(self.userCharsetToDatabase(user.Description))))
571        if user.PaymentsBacklog :
572            for (value, comment) in user.PaymentsBacklog :
573                self.writeNewPayment(user, value, comment)
574            user.PaymentsBacklog = []
575        user.isDirty = False
576        return None # the entry created doesn't need further modification
577       
578    def addGroup(self, group) :       
579        """Adds a group to the quota storage, returns the old value if it already exists."""
580        oldentry = self.getGroup(group.Name)
581        if oldentry.Exists :
582            return oldentry
583        self.doModify("INSERT INTO groups (groupname, limitby, description) VALUES (%s, %s, %s)" % \
584                              (self.doQuote(self.userCharsetToDatabase(group.Name)), \
585                               self.doQuote(group.LimitBy or "quota"), \
586                               self.doQuote(self.userCharsetToDatabase(group.Description))))
587        group.isDirty = False
588        return None # the entry created doesn't need further modification
589
590    def addUserToGroup(self, user, group) :   
591        """Adds an user to a group."""
592        result = self.doSearch("SELECT COUNT(*) AS mexists FROM groupsmembers WHERE groupid=%s AND userid=%s" % (self.doQuote(group.ident), self.doQuote(user.ident)))
593        try :
594            mexists = int(result[0].get("mexists"))
595        except (IndexError, TypeError) :   
596            mexists = 0
597        if not mexists :   
598            self.doModify("INSERT INTO groupsmembers (groupid, userid) VALUES (%s, %s)" % (self.doQuote(group.ident), self.doQuote(user.ident)))
599           
600    def delUserFromGroup(self, user, group) :   
601        """Removes an user from a group."""
602        self.doModify("DELETE FROM groupsmembers WHERE groupid=%s AND userid=%s" % \
603                       (self.doQuote(group.ident), self.doQuote(user.ident)))
604           
605    def addUserPQuota(self, upq) :
606        """Initializes a user print quota on a printer."""
607        oldentry = self.getUserPQuota(upq.User, upq.Printer)
608        if oldentry.Exists :
609            return oldentry
610        self.doModify("INSERT INTO userpquota (userid, printerid, softlimit, hardlimit, warncount, datelimit, pagecounter, lifepagecounter, maxjobsize) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" \
611                          % (self.doQuote(upq.User.ident), \
612                             self.doQuote(upq.Printer.ident), \
613                             self.doQuote(upq.SoftLimit), \
614                             self.doQuote(upq.HardLimit), \
615                             self.doQuote(upq.WarnCount or 0), \
616                             self.doQuote(upq.DateLimit), \
617                             self.doQuote(upq.PageCounter or 0), \
618                             self.doQuote(upq.LifePageCounter or 0), \
619                             self.doQuote(upq.MaxJobSize)))
620        upq.isDirty = False
621        return None # the entry created doesn't need further modification
622       
623    def addGroupPQuota(self, gpq) :
624        """Initializes a group print quota on a printer."""
625        oldentry = self.getGroupPQuota(gpq.Group, gpq.Printer)
626        if oldentry.Exists :
627            return oldentry
628        self.doModify("INSERT INTO grouppquota (groupid, printerid, softlimit, hardlimit, datelimit, maxjobsize) VALUES (%s, %s, %s, %s, %s, %s)" \
629                          % (self.doQuote(gpq.Group.ident), \
630                             self.doQuote(gpq.Printer.ident), \
631                             self.doQuote(gpq.SoftLimit), \
632                             self.doQuote(gpq.HardLimit), \
633                             self.doQuote(gpq.DateLimit), \
634                             self.doQuote(gpq.MaxJobSize)))
635        gpq.isDirty = False
636        return None # the entry created doesn't need further modification
637       
638    def savePrinter(self, printer) :   
639        """Saves the printer to the database in a single operation."""
640        self.doModify("UPDATE printers SET passthrough=%s, maxjobsize=%s, description=%s, priceperpage=%s, priceperjob=%s WHERE id=%s" \
641                              % (self.doQuote((printer.PassThrough and "t") or "f"), \
642                                 self.doQuote(printer.MaxJobSize or 0), \
643                                 self.doQuote(self.userCharsetToDatabase(printer.Description)), \
644                                 self.doQuote(printer.PricePerPage or 0.0), \
645                                 self.doQuote(printer.PricePerJob or 0.0), \
646                                 self.doQuote(printer.ident)))
647                                 
648    def saveUser(self, user) :       
649        """Saves the user to the database in a single operation."""
650        self.doModify("UPDATE users SET limitby=%s, balance=%s, lifetimepaid=%s, email=%s, overcharge=%s, description=%s WHERE id=%s" \
651                               % (self.doQuote(user.LimitBy or 'quota'), \
652                                  self.doQuote(user.AccountBalance or 0.0), \
653                                  self.doQuote(user.LifeTimePaid or 0.0), \
654                                  self.doQuote(user.Email), \
655                                  self.doQuote(user.OverCharge), \
656                                  self.doQuote(self.userCharsetToDatabase(user.Description)), \
657                                  self.doQuote(user.ident)))
658                                 
659    def saveGroup(self, group) :       
660        """Saves the group to the database in a single operation."""
661        self.doModify("UPDATE groups SET limitby=%s, description=%s WHERE id=%s" \
662                               % (self.doQuote(group.LimitBy or 'quota'), \
663                                  self.doQuote(self.userCharsetToDatabase(group.Description)), \
664                                  self.doQuote(group.ident)))
665       
666    def writeUserPQuotaDateLimit(self, userpquota, datelimit) :   
667        """Sets the date limit permanently for a user print quota."""
668        self.doModify("UPDATE userpquota SET datelimit=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(userpquota.ident)))
669           
670    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :   
671        """Sets the date limit permanently for a group print quota."""
672        self.doModify("UPDATE grouppquota SET datelimit=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(grouppquota.ident)))
673       
674    def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) :   
675        """Increase page counters for a user print quota."""
676        self.doModify("UPDATE userpquota SET pagecounter=pagecounter + %s,lifepagecounter=lifepagecounter + %s WHERE id=%s" % (self.doQuote(nbpages), self.doQuote(nbpages), self.doQuote(userpquota.ident)))
677       
678    def saveBillingCode(self, bcode) :   
679        """Saves the billing code to the database."""
680        self.doModify("UPDATE billingcodes SET balance=%s, pagecounter=%s, description=%s WHERE id=%s" \
681                            % (self.doQuote(bcode.Balance or 0.0), \
682                               self.doQuote(bcode.PageCounter or 0), \
683                               self.doQuote(self.userCharsetToDatabase(bcode.Description)), \
684                               self.doQuote(bcode.ident)))
685       
686    def consumeBillingCode(self, bcode, pagecounter, balance) :
687        """Consumes from a billing code."""
688        self.doModify("UPDATE billingcodes SET balance=balance + %s, pagecounter=pagecounter + %s WHERE id=%s" % (self.doQuote(balance), self.doQuote(pagecounter), self.doQuote(bcode.ident)))
689       
690    def refundJob(self, jobident) :   
691        """Marks a job as refunded in the history."""
692        self.doModify("UPDATE jobhistory SET action='REFUND' WHERE id=%s;" % self.doQuote(jobident))
693       
694    def decreaseUserAccountBalance(self, user, amount) :   
695        """Decreases user's account balance from an amount."""
696        self.doModify("UPDATE users SET balance=balance - %s WHERE id=%s" % (self.doQuote(amount), self.doQuote(user.ident)))
697       
698    def writeNewPayment(self, user, amount, comment="") :
699        """Adds a new payment to the payments history."""
700        if user.ident is not None :
701            self.doModify("INSERT INTO payments (userid, amount, description) VALUES (%s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(amount), self.doQuote(self.userCharsetToDatabase(comment))))
702        else :   
703            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))))
704       
705    def writeLastJobSize(self, lastjob, jobsize, jobprice) :       
706        """Sets the last job's size permanently."""
707        self.doModify("UPDATE jobhistory SET jobsize=%s, jobprice=%s WHERE id=%s" % (self.doQuote(jobsize), self.doQuote(jobprice), self.doQuote(lastjob.ident)))
708       
709    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) :
710        """Adds a job in a printer's history."""
711        if self.privacy :   
712            # For legal reasons, we want to hide the title, filename and options
713            title = filename = options = "hidden"
714        filename = self.userCharsetToDatabase(filename)
715        title = self.userCharsetToDatabase(title)
716        options = self.userCharsetToDatabase(options)
717        jobbilling = self.userCharsetToDatabase(jobbilling)
718        if (not self.disablehistory) or (not printer.LastJob.Exists) :
719            if jobsize is not None :
720                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)))
721            else :   
722                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)))
723        else :       
724            # here we explicitly want to reset jobsize to NULL if needed
725            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)))
726           
727    def saveUserPQuota(self, userpquota) :
728        """Saves an user print quota entry."""
729        self.doModify("UPDATE userpquota SET softlimit=%s, hardlimit=%s, warncount=%s, datelimit=%s, pagecounter=%s, lifepagecounter=%s, maxjobsize=%s WHERE id=%s" \
730                              % (self.doQuote(userpquota.SoftLimit), \
731                                 self.doQuote(userpquota.HardLimit), \
732                                 self.doQuote(userpquota.WarnCount or 0), \
733                                 self.doQuote(userpquota.DateLimit), \
734                                 self.doQuote(userpquota.PageCounter or 0), \
735                                 self.doQuote(userpquota.LifePageCounter or 0), \
736                                 self.doQuote(userpquota.MaxJobSize), \
737                                 self.doQuote(userpquota.ident)))
738       
739    def writeUserPQuotaWarnCount(self, userpquota, warncount) :
740        """Sets the warn counter value for a user quota."""
741        self.doModify("UPDATE userpquota SET warncount=%s WHERE id=%s" % (self.doQuote(warncount), self.doQuote(userpquota.ident)))
742       
743    def increaseUserPQuotaWarnCount(self, userpquota) :
744        """Increases the warn counter value for a user quota."""
745        self.doModify("UPDATE userpquota SET warncount=warncount+1 WHERE id=%s" % self.doQuote(userpquota.ident))
746       
747    def saveGroupPQuota(self, grouppquota) :
748        """Saves a group print quota entry."""
749        self.doModify("UPDATE grouppquota SET softlimit=%s, hardlimit=%s, datelimit=%s WHERE id=%s" \
750                              % (self.doQuote(grouppquota.SoftLimit), \
751                                 self.doQuote(grouppquota.HardLimit), \
752                                 self.doQuote(grouppquota.DateLimit), \
753                                 self.doQuote(grouppquota.ident)))
754
755    def writePrinterToGroup(self, pgroup, printer) :
756        """Puts a printer into a printer group."""
757        children = []
758        result = self.doSearch("SELECT printerid FROM printergroupsmembers WHERE groupid=%s" % self.doQuote(pgroup.ident))
759        if result :
760            for record in result :
761                children.append(record.get("printerid")) # TODO : put this into the database integrity rules
762        if printer.ident not in children :       
763            self.doModify("INSERT INTO printergroupsmembers (groupid, printerid) VALUES (%s, %s)" % (self.doQuote(pgroup.ident), self.doQuote(printer.ident)))
764       
765    def removePrinterFromGroup(self, pgroup, printer) :
766        """Removes a printer from a printer group."""
767        self.doModify("DELETE FROM printergroupsmembers WHERE groupid=%s AND printerid=%s" % (self.doQuote(pgroup.ident), self.doQuote(printer.ident)))
768       
769    def retrieveHistory(self, user=None, printer=None, hostname=None, billingcode=None, jobid=None, limit=100, start=None, end=None) :
770        """Retrieves all print jobs for user on printer (or all) between start and end date, limited to first 100 results."""
771        query = "SELECT jobhistory.*,username,printername FROM jobhistory,users,printers WHERE users.id=userid AND printers.id=printerid"
772        where = []
773        if user is not None : # user.ident is None anyway if user doesn't exist
774            where.append("userid=%s" % self.doQuote(user.ident))
775        if printer is not None : # printer.ident is None anyway if printer doesn't exist
776            where.append("printerid=%s" % self.doQuote(printer.ident))
777        if hostname is not None :   
778            where.append("hostname=%s" % self.doQuote(hostname))
779        if billingcode is not None :   
780            where.append("billingcode=%s" % self.doQuote(self.userCharsetToDatabase(billingcode)))
781        if jobid is not None :   
782            where.append("jobid=%s" % self.doQuote(jobid)) # TODO : jobid is text, so self.userCharsetToDatabase(jobid) but do all of them as well.
783        if start is not None :   
784            where.append("jobdate>=%s" % self.doQuote(start))
785        if end is not None :   
786            where.append("jobdate<=%s" % self.doQuote(end))
787        if where :   
788            query += " AND %s" % " AND ".join(where)
789        query += " ORDER BY jobhistory.id DESC"
790        if limit :
791            query += " LIMIT %s" % self.doQuote(int(limit))
792        jobs = []   
793        result = self.doSearch(query)   
794        if result :
795            for fields in result :
796                job = self.storageJobFromRecord(fields)
797                jobs.append(job)
798        return jobs
799       
800    def deleteUser(self, user) :   
801        """Completely deletes an user from the database."""
802        # TODO : What should we do if we delete the last person who used a given printer ?
803        # TODO : we can't reassign the last job to the previous one, because next user would be
804        # TODO : incorrectly charged (overcharged).
805        for q in [ 
806                    "DELETE FROM payments WHERE userid=%s" % self.doQuote(user.ident),
807                    "DELETE FROM groupsmembers WHERE userid=%s" % self.doQuote(user.ident),
808                    "DELETE FROM jobhistory WHERE userid=%s" % self.doQuote(user.ident),
809                    "DELETE FROM userpquota WHERE userid=%s" % self.doQuote(user.ident),
810                    "DELETE FROM users WHERE id=%s" % self.doQuote(user.ident),
811                  ] :
812            self.doModify(q)
813           
814    def multipleQueriesInTransaction(self, queries) :       
815        """Does many modifications in a single transaction."""
816        self.beginTransaction()
817        try :
818            for q in queries :
819                self.doModify(q)
820        except :   
821            self.rollbackTransaction()
822            raise
823        else :   
824            self.commitTransaction()
825           
826    def deleteManyBillingCodes(self, billingcodes) :       
827        """Deletes many billing codes."""
828        codeids = ", ".join(["%s" % self.doQuote(b.ident) for b in billingcodes])
829        self.multipleQueriesInTransaction([ 
830                    "DELETE FROM billingcodes WHERE id IN (%s)" % codeids,])
831           
832    def deleteManyUsers(self, users) :       
833        """Deletes many users."""
834        userids = ", ".join(["%s" % self.doQuote(u.ident) for u in users])
835        self.multipleQueriesInTransaction([ 
836                    "DELETE FROM payments WHERE userid IN (%s)" % userids,
837                    "DELETE FROM groupsmembers WHERE userid IN (%s)" % userids,
838                    "DELETE FROM jobhistory WHERE userid IN (%s)" % userids,
839                    "DELETE FROM userpquota WHERE userid IN (%s)" % userids,
840                    "DELETE FROM users WHERE id IN (%s)" % userids,])
841                   
842    def deleteManyGroups(self, groups) :       
843        """Deletes many groups."""
844        groupids = ", ".join(["%s" % self.doQuote(g.ident) for g in groups])
845        self.multipleQueriesInTransaction([ 
846                    "DELETE FROM groupsmembers WHERE groupid IN (%s)" % groupids,
847                    "DELETE FROM grouppquota WHERE groupid IN (%s)" % groupids,
848                    "DELETE FROM groups WHERE id IN (%s)" % groupids,])
849       
850    def deleteManyPrinters(self, printers) :
851        """Deletes many printers."""
852        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers])
853        self.multipleQueriesInTransaction([ 
854                    "DELETE FROM printergroupsmembers WHERE groupid IN (%s) OR printerid IN (%s)" % (printerids, printerids),
855                    "DELETE FROM jobhistory WHERE printerid IN (%s)" % printerids,
856                    "DELETE FROM grouppquota WHERE printerid IN (%s)" % printerids,
857                    "DELETE FROM userpquota WHERE printerid IN (%s)" % printerids,
858                    "DELETE FROM printers WHERE id IN (%s)" % printerids,])
859       
860    def deleteManyUserPQuotas(self, printers, users) :       
861        """Deletes many user print quota entries."""
862        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers])
863        userids = ", ".join(["%s" % self.doQuote(u.ident) for u in users])
864        self.multipleQueriesInTransaction([ 
865                    "DELETE FROM jobhistory WHERE userid IN (%s) AND printerid IN (%s)" \
866                                 % (userids, printerids),
867                    "DELETE FROM userpquota WHERE userid IN (%s) AND printerid IN (%s)" \
868                                 % (userids, printerids),])
869           
870    def deleteManyGroupPQuotas(self, printers, groups) :
871        """Deletes many group print quota entries."""
872        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers])
873        groupids = ", ".join(["%s" % self.doQuote(g.ident) for g in groups])
874        self.multipleQueriesInTransaction([ 
875                    "DELETE FROM grouppquota WHERE groupid IN (%s) AND printerid IN (%s)" \
876                                 % (groupids, printerids),])
877       
878    def deleteUserPQuota(self, upquota) :   
879        """Completely deletes an user print quota entry from the database."""
880        for q in [ 
881                    "DELETE FROM jobhistory WHERE userid=%s AND printerid=%s" \
882                                 % (self.doQuote(upquota.User.ident), self.doQuote(upquota.Printer.ident)),
883                    "DELETE FROM userpquota WHERE id=%s" % self.doQuote(upquota.ident),
884                  ] :
885            self.doModify(q)
886       
887    def deleteGroupPQuota(self, gpquota) :   
888        """Completely deletes a group print quota entry from the database."""
889        for q in [ 
890                    "DELETE FROM grouppquota WHERE id=%s" % self.doQuote(gpquota.ident),
891                  ] :
892            self.doModify(q)
893       
894    def deleteGroup(self, group) :   
895        """Completely deletes a group from the database."""
896        for q in [
897                   "DELETE FROM groupsmembers WHERE groupid=%s" % self.doQuote(group.ident),
898                   "DELETE FROM grouppquota WHERE groupid=%s" % self.doQuote(group.ident),
899                   "DELETE FROM groups WHERE id=%s" % self.doQuote(group.ident),
900                 ] : 
901            self.doModify(q)
902           
903    def deletePrinter(self, printer) :   
904        """Completely deletes a printer from the database."""
905        for q in [ 
906                    "DELETE FROM printergroupsmembers WHERE groupid=%s OR printerid=%s" % (self.doQuote(printer.ident), self.doQuote(printer.ident)),
907                    "DELETE FROM jobhistory WHERE printerid=%s" % self.doQuote(printer.ident),
908                    "DELETE FROM grouppquota WHERE printerid=%s" % self.doQuote(printer.ident),
909                    "DELETE FROM userpquota WHERE printerid=%s" % self.doQuote(printer.ident),
910                    "DELETE FROM printers WHERE id=%s" % self.doQuote(printer.ident),
911                  ] :
912            self.doModify(q)
913           
914    def deleteBillingCode(self, code) :   
915        """Completely deletes a billing code from the database."""
916        for q in [
917                   "DELETE FROM billingcodes WHERE id=%s" % self.doQuote(code.ident),
918                 ] : 
919            self.doModify(q)
920       
Note: See TracBrowser for help on using the browser.