root / pykota / trunk / bin / pkprinters @ 2770

Revision 2770, 15.5 kB (checked in by jerome, 18 years ago)

Now does all modifications in a single database transaction.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota Printers Manager
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22#
23# $Id$
24#
25#
26
27import os
28import sys
29import pwd
30
31from pykota.tool import PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_
32from pykota.storage import StoragePrinter
33
34__doc__ = N_("""pkprinters v%(__version__)s (c) %(__years__)s %(__author__)s
35
36A Printers Manager for PyKota.
37
38command line usage :
39
40  pkprinters [options] printer1 printer2 printer3 ... printerN
41
42options :
43
44  -v | --version       Prints pkprinters's version number then exits.
45  -h | --help          Prints this message then exits.
46 
47  -a | --add           Adds printers if they don't exist on the Quota
48                       Storage Server. If they exist, they are modified
49                       unless -s|--skipexisting is also used.
50                       
51  -d | --delete        Deletes printers from the quota storage.
52 
53  -D | --description d Adds a textual description to printers.
54                       
55  -c | --charge p[,j]  Sets the price per page and per job to charge.
56                       Job price is optional.
57                       If both are to be set, separate them with a comma.
58                       Floating point and negative values are allowed.
59 
60  -g | --groups pg1[,pg2...] Adds or Remove the printer(s) to the printer
61                       groups pg1, pg2, etc... which must already exist.
62                       A printer group is just like a normal printer,
63                       only that it is usually unknown from the printing
64                       system. Create printer groups exactly the same
65                       way that you create printers, then add other
66                       printers to them with this option.
67                       Accounting is done on a printer and on all
68                       the printer groups it belongs to, quota checking
69                       is done on a printer and on all the printer groups
70                       it belongs to.
71                       If the --remove option below is not used, the
72                       default action is to add printers to the specified
73                       printer groups.
74                       
75  -l | --list          List informations about the printer(s) and the
76                       printers groups it is a member of.
77                       
78  -r | --remove        In combination with the --groups option above,                       
79                       remove printers from the specified printers groups.
80                       
81  -s | --skipexisting  In combination with the --add option above, tells
82                       pkprinters to not modify existing printers.
83                       
84  -m | --maxjobsize s  Sets the maximum job size allowed on the printer
85                       to s pages.
86                       
87  -p | --passthrough   Activate passthrough mode for the printer. In this
88                       mode, users are allowed to print without any impact
89                       on their quota or account balance.
90                       
91  -n | --nopassthrough Deactivate passthrough mode for the printer.
92                       Without -p or -n, printers are created in
93                       normal mode, i.e. no passthrough.
94 
95  printer1 through printerN can contain wildcards if the --add option
96  is not set.
97 
98examples :                             
99
100  $ pkprinters --add -D "HP Printer" --charge 0.05,0.1 hp2100 hp2200 hp8000
101 
102  Will create three printers named hp2100, hp2200 and hp8000.
103  Their price per page will be set at 0.05 unit, and their price
104  per job will be set at 0.1 unit. Units are in your own currency,
105  or whatever you want them to mean.
106  All of their descriptions will be set to the string "HP Printer".
107  If any of these printers already exists, it will also be modified
108  unless the -s|--skipexisting command line option is also used.
109           
110  $ pkprinters --delete "*"
111 
112  This will completely delete all printers and associated quota information,
113  as well as their job history. USE WITH CARE !
114 
115  $ pkprinters --groups Laser,HP "hp*"
116 
117  This will put all printers which name matches "hp*" into printers groups
118  Laser and HP, which MUST already exist.
119 
120  $ pkprinters --groups LexMark --remove hp2200
121 
122  This will remove the hp2200 printer from the LexMark printer group.
123""")
124       
125class PKPrinters(PyKotaTool) :       
126    """A class for a printers manager."""
127    def modifyPrinter(self, printer, charges, perpage, perjob, description, passthrough, nopassthrough, maxjobsize) :
128        if charges :
129            printer.setPrices(perpage, perjob)   
130        if description is not None :        # NB : "" is allowed !
131            printer.setDescription(description)
132        if nopassthrough :   
133            printer.setPassThrough(False)
134        if passthrough :   
135            printer.setPassThrough(True)
136        if maxjobsize is not None :
137            printer.setMaxJobSize(maxjobsize)
138           
139    def managePrintersGroups(self, pgroups, printer, remove) :       
140        """Manage printer group membership."""
141        for pgroup in pgroups :
142            if remove :
143                pgroup.delPrinterFromGroup(printer)
144            else :
145                pgroup.addPrinterToGroup(printer)   
146               
147    def main(self, names, options) :
148        """Manage printers."""
149        if (not self.config.isAdmin) and (not options["list"]) :
150            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
151           
152        if not options["add"] :
153            if not options["list"] :
154                self.display(_("Extracting datas..."))
155            if not names :      # NB : can't happen for --delete because it's catched earlier
156                names = ["*"]
157            printers = self.storage.getMatchingPrinters(",".join(names))
158            if not printers :
159                raise PyKotaCommandLineError, _("There's no printer matching %s") % " ".join(names)
160               
161        if options["list"] :
162            for printer in printers :
163                parents = ", ".join([p.Name for p in self.storage.getParentPrinters(printer)])
164                print "%s [%s] (%s + #*%s)" % \
165                      (printer.Name, printer.Description, printer.PricePerJob, \
166                       printer.PricePerPage)
167                print "    %s" % (_("Passthrough mode : %s") % ((printer.PassThrough and _("ON")) or _("OFF")))
168                print "    %s" % (_("Maximum job size : %s") % ((printer.MaxJobSize and (_("%s pages") % printer.MaxJobSize)) or _("Unlimited")))
169                if parents : 
170                    print "    %s %s" % (_("in"), parents)
171                print   
172        elif options["delete"] :   
173            self.display("\n%s..." % _("Deletion"))
174            self.storage.deleteManyPrinters(printers)
175            self.display("\n")
176        else :
177            if options["groups"] :       
178                printersgroups = self.storage.getMatchingPrinters(options["groups"])
179                if not printersgroups :
180                    raise PyKotaCommandLineError, _("There's no printer matching %s") % " ".join(options["groups"].split(','))
181            else :         
182                printersgroups = []
183                   
184            if options["charge"] :
185                try :
186                    charges = [float(part) for part in options["charge"].split(',', 1)]
187                except ValueError :   
188                    raise PyKotaCommandLineError, _("Invalid charge amount value %s") % options["charge"]
189                else :   
190                    if len(charges) > 2 :
191                        charges = charges[:2]
192                    if len(charges) != 2 :
193                        charges = [charges[0], None]
194                    (perpage, perjob) = charges
195            else :       
196                charges = perpage = perjob = None
197                   
198            if options["maxjobsize"] :       
199                try :
200                    maxjobsize = int(options["maxjobsize"])
201                    if maxjobsize < 0 :
202                        raise ValueError
203                except ValueError :   
204                    raise PyKotaCommandLineError, _("Invalid maximum job size value %s") % options["maxjobsize"]
205            else :       
206                maxjobsize = None
207                   
208            description = options["description"]
209            if description :
210                description = description.strip()
211               
212            nopassthrough = options["nopassthrough"]   
213            passthrough = options["passthrough"]
214            remove = options["remove"]
215            skipexisting = options["skipexisting"]
216            self.storage.beginTransaction()
217            try :
218                if options["add"] :   
219                    self.display("%s...\n" % _("Creation"))
220                    nbtotal = len(names)
221                    for i in range(nbtotal) :
222                        pname = names[i]
223                        if self.isValidName(pname) :
224                            printer = StoragePrinter(self.storage, pname)
225                            self.modifyPrinter(printer, charges, perpage, perjob,\
226                                           description, passthrough, \
227                                           nopassthrough, maxjobsize)
228                            oldprinter = self.storage.addPrinter(printer)               
229                            if oldprinter is not None :
230                                if skipexisting :
231                                    self.logdebug(_("Printer %s already exists, skipping.") % pname)
232                                else :   
233                                    self.logdebug(_("Printer %s already exists, will be modified.") % pname)
234                                    self.modifyPrinter(oldprinter, charges, \
235                                               perpage, perjob, description, \
236                                               passthrough, nopassthrough, \
237                                               maxjobsize)
238                                    oldprinter.save()           
239                                    self.managePrintersGroups(printersgroups, oldprinter, remove)
240                            elif printersgroups :       
241                                self.managePrintersGroups(printersgroups, \
242                                                          self.storage.getPrinter(pname), \
243                                                          remove)
244                        else :   
245                            raise PyKotaCommandLineError, _("Invalid printer name %s") % pname
246                        percent = 100.0 * float(i) / float(nbtotal)
247                        self.display("\r%.02f%%" % percent)
248                else :       
249                    self.display("\n%s...\n" % _("Modification"))
250                    nbtotal = len(printers)
251                    for i in range(nbtotal) :       
252                        printer = printers[i]
253                        self.modifyPrinter(printer, charges, perpage, perjob, \
254                                           description, passthrough, \
255                                           nopassthrough, maxjobsize)
256                        printer.save()   
257                        self.managePrintersGroups(printersgroups, printer, remove)
258                        percent = 100.0 * float(i) / float(nbtotal)
259                        self.display("\r%.02f%%" % percent)
260            except :                   
261                self.storage.rollbackTransaction()
262                raise
263            else :   
264                self.storage.commitTransaction()
265        if not options["list"] :               
266            self.done()
267                     
268if __name__ == "__main__" : 
269    retcode = 0
270    try :
271        short_options = "hvac:D:dg:lrsnpm:"
272        long_options = ["help", "version", "add", "charge=", "description=", \
273                        "delete", "groups=", "list", "remove", \
274                        "skipexisting", "passthrough", "nopassthrough", \
275                        "maxjobsize="]
276       
277        # Initializes the command line tool
278        manager = PKPrinters(doc=__doc__)
279        manager.deferredInit()
280       
281        # parse and checks the command line
282        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
283       
284        # sets long options
285        options["help"] = options["h"] or options["help"]
286        options["version"] = options["v"] or options["version"]
287        options["add"] = options["a"] or options["add"]
288        options["charge"] = options["c"] or options["charge"]
289        options["description"] = options["D"] or options["description"]
290        options["delete"] = options["d"] or options["delete"] 
291        options["groups"] = options["g"] or options["groups"]
292        options["list"] = options["l"] or options["list"]
293        options["remove"] = options["r"] or options["remove"]
294        options["skipexisting"] = options["s"] or options["skipexisting"]
295        options["maxjobsize"] = options["m"] or options["maxjobsize"]
296        options["passthrough"] = options["p"] or options["passthrough"]
297        options["nopassthrough"] = options["n"] or options["nopassthrough"]
298       
299        if options["help"] :
300            manager.display_usage_and_quit()
301        elif options["version"] :
302            manager.display_version_and_quit()
303        elif (options["delete"] and (options["add"] or options["groups"] or options["charge"] or options["remove"] or options["description"])) \
304           or (options["skipexisting"] and not options["add"]) \
305           or (options["list"] and (options["add"] or options["delete"] or options["groups"] or options["charge"] or options["remove"] or options["description"])) \
306           or (options["passthrough"] and options["nopassthrough"]) \
307           or (options["remove"] and options["add"]) :
308            raise PyKotaCommandLineError, _("incompatible options, see help.")
309        elif options["remove"] and not options["groups"] :
310            raise PyKotaCommandLineError, _("You have to pass printer groups names on the command line")
311        elif (not args) and (options["add"] or options["delete"]) :
312            raise PyKotaCommandLineError, _("You have to pass printer names on the command line")
313        else :
314            retcode = manager.main(args, options)
315    except KeyboardInterrupt :       
316        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
317        retcode = -3
318    except PyKotaCommandLineError, msg :   
319        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
320        retcode = -2
321    except SystemExit :       
322        pass
323    except :
324        try :
325            manager.crashed("pkprinters failed")
326        except :   
327            crashed("pkprinters failed")
328        retcode = -1
329
330    try :
331        manager.storage.close()
332    except (TypeError, NameError, AttributeError) :   
333        pass
334       
335    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.