root / pykota / trunk / bin / edpykota @ 924

Revision 924, 22.4 kB (checked in by jalet, 21 years ago)

More strict error detection.
Minor code rewrite to avoid some repetitive tests.

  • 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
3# PyKota Print Quota Editor
4#
5# PyKota - Print Quotas for CUPS
6#
7# (c) 2003 Jerome Alet <alet@librelogiciel.com>
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21#
22# $Id$
23#
24# $Log$
25# Revision 1.40  2003/04/16 08:22:09  jalet
26# More strict error detection.
27# Minor code rewrite to avoid some repetitive tests.
28#
29# Revision 1.39  2003/04/16 08:01:53  jalet
30# edpykota --charge command line option works now.
31#
32# Revision 1.38  2003/04/15 22:02:43  jalet
33# More complete docstring
34#
35# Revision 1.37  2003/04/15 21:58:33  jalet
36# edpykota now accepts a --delete option.
37# Preparation to allow edpykota to accept much more command line options
38# (WARNING : docstring is OK, but code isn't !)
39#
40# Revision 1.36  2003/04/15 13:55:28  jalet
41# Options --limitby and --balance added to edpykota
42#
43# Revision 1.35  2003/04/15 13:06:39  jalet
44# Allow to add a printer without any user
45#
46# Revision 1.34  2003/04/11 16:51:11  jalet
47# Bug fix for edpykota --add with users who already had a quota on the printer.
48#
49# Revision 1.33  2003/04/10 21:47:20  jalet
50# Job history added. Upgrade script neutralized for now !
51#
52# Revision 1.32  2003/04/08 21:31:39  jalet
53# (anything or 0) = anything !!! Go back to school Jerome !
54#
55# Revision 1.31  2003/04/08 21:13:44  jalet
56# Prepare --groups option to work.
57#
58# Revision 1.30  2003/04/08 21:10:18  jalet
59# Checks --groups option presence instead of --users because --users is the default.
60#
61# Revision 1.29  2003/04/05 09:28:56  jalet
62# Unnecessary message was logged
63#
64# Revision 1.28  2003/03/29 13:45:26  jalet
65# GPL paragraphs were incorrectly (from memory) copied into the sources.
66# Two README files were added.
67# Upgrade script for PostgreSQL pre 1.01 schema was added.
68#
69# Revision 1.27  2003/03/10 00:23:04  jalet
70# Bad english
71#
72# Revision 1.26  2003/03/10 00:11:27  jalet
73# Cleaner example.
74#
75# Revision 1.25  2003/03/09 23:56:21  jalet
76# Option noquota added to do accounting only.
77#
78# Revision 1.24  2003/02/27 23:48:41  jalet
79# Correctly maps PyKota's log levels to syslog log levels
80#
81# Revision 1.23  2003/02/27 22:55:20  jalet
82# WARN log priority doesn't exist.
83#
84# Revision 1.22  2003/02/27 09:37:02  jalet
85# Wildcards seem to work now
86#
87# Revision 1.21  2003/02/27 09:04:46  jalet
88# user and group names can be passed as wildcards if the --add option
89# is not set. The default is to act on all users or groups.
90#
91# Revision 1.20  2003/02/10 12:07:30  jalet
92# Now repykota should output the recorded total page number for each printer too.
93#
94# Revision 1.19  2003/02/09 13:40:29  jalet
95# typo
96#
97# Revision 1.18  2003/02/09 12:56:53  jalet
98# Internationalization begins...
99#
100# Revision 1.17  2003/02/08 22:47:23  jalet
101# Option --reset can now be used without having to use soft and hard limits
102# on the command line.
103#
104# Revision 1.16  2003/02/08 22:39:46  jalet
105# --reset command line option added
106#
107# Revision 1.15  2003/02/08 22:20:01  jalet
108# Clarification on why we don't check with /etc/passwd to see if the user
109# name is valid or not.
110#
111# Revision 1.14  2003/02/08 22:18:15  jalet
112# Now checks user and group names for validity before adding them
113#
114# Revision 1.13  2003/02/08 22:09:02  jalet
115# Only printer was added the first time.
116#
117# Revision 1.12  2003/02/08 21:44:49  jalet
118# Python 2.1 string module doesn't define ascii_letters
119#
120# Revision 1.11  2003/02/08 09:42:44  jalet
121# Better handle wrong or bad command line arguments
122#
123# Revision 1.10  2003/02/08 09:39:20  jalet
124# typos
125#
126# Revision 1.9  2003/02/08 09:38:06  jalet
127# Badly placed test
128#
129# Revision 1.8  2003/02/07 22:53:57  jalet
130# Checks if printer name is valid before adding it
131#
132# Revision 1.7  2003/02/07 22:17:58  jalet
133# Incomplete test
134#
135# Revision 1.6  2003/02/07 22:13:13  jalet
136# Perhaps edpykota is now able to add printers !!! Oh, stupid me !
137#
138# Revision 1.5  2003/02/06 14:49:04  jalet
139# edpykota should be ok now
140#
141# Revision 1.4  2003/02/06 14:28:59  jalet
142# edpykota should be ok, minus some typos
143#
144# Revision 1.3  2003/02/06 10:47:21  jalet
145# Documentation string and command line options didn't match.
146#
147# Revision 1.2  2003/02/06 10:39:23  jalet
148# Preliminary edpykota work.
149#
150# Revision 1.1  2003/02/05 21:41:09  jalet
151# Skeletons added for all command line tools
152#
153#
154#
155
156import sys
157
158from pykota import version
159from pykota.tool import PyKotaTool, PyKotaToolError
160
161__doc__ = """edpykota v%s (C) 2003 C@LL - Conseil Internet & Logiciels Libres
162A Print Quota editor for PyKota.
163
164command line usage :
165
166  edpykota [options] user1 user2 ... userN
167  edpykota [options] group1 group2 ... groupN
168
169options :
170
171  -v | --version       Prints edpykota's version number then exits.
172  -h | --help          Prints this message then exits.
173 
174  -a | --add           Adds users and/or printers if they don't
175                       exist on the Quota Storage Server.
176                       
177  -d | --delete        Deletes users/groups from the quota storage.
178                       Printers are never deleted.
179                       
180  -c | --charge p[,j]  Sets the price per page and per job to charge
181                       for a particular printer. Job price is optional.
182                       If both are to be set, separate them with a comma.
183                       Floating point values are allowed.
184 
185  -i | --ingroups g1[,g2...]  Puts the users into each of the groups
186                              listed, separated by commas. The groups
187                              must already exist in the Quota Storage.
188 
189  -u | --users         Edit users print quotas, this is the default.
190 
191  -P | --printer p     Edit quotas on printer p only. Actually p can
192                       use wildcards characters to select only
193                       some printers. The default value is *, meaning
194                       all printers.
195 
196  -g | --groups        Edit groups print quotas instead of users.
197                         
198  -p | --prototype u|g Uses user u or group g as a prototype to set
199                       print quotas
200                       
201  -n | --noquota       Doesn't set a quota but only does accounting.
202 
203  -r | --reset         Resets the printed page counter for the user
204                       or group to zero. The life time page counter
205                       is kept unchanged.
206                       
207  -l | --limitby l     Choose if the user/group is limited in printing                     
208                       by its account balance or by its page quota.
209                       The default value is 'quota'. Allowed values
210                       are 'quota' and 'balance'.
211                       
212  -b | --balance b     Sets the user's account balance to b.                     
213                       Account balance may be increase or decreased
214                       if b is prefixed with + or -.
215                       WARNING : when decreasing account balance,
216                       the total paid so far by the user is decreased
217                       too.
218                       Groups don't have a real balance, but the
219                       sum of their users' account balance.
220                       
221  -S | --softlimit sl  Sets the quota soft limit to sl pages.                       
222 
223  -H | --hardlimit hl  Sets the quota hard limit to hl pages.
224 
225  user1 through userN and group1 through groupN can use wildcards
226  if the --add option is not set.
227 
228examples :                             
229
230  $ edpykota -p jerome john paul george ringo
231 
232  This will set print quotas for the users john, paul, george and ringo
233  to the same values than user jerome. User jerome must exist.
234 
235  $ edpykota --printer lp -S 50 -H 60 jerome
236 
237  This will set jerome's print quota on the lp printer to a soft limit
238  of 50 pages, and a hard limit of 60 pages. If either user jerome or
239  printer lp doesn't exist on the Quota Storage Server then nothing is done.
240
241  $ edpykota --add --printer lp --ingroups coders,it -S 50 -H 60 jerome
242 
243  Same as above, but if either user jerome or printer lp doesn't exist
244  on the Quota Storage Server they are automatically added. Also
245  user jerome is put into the groups "coders" and "it" which must
246  already exist in the Quota Storage.
247  WARNING : the CUPS PPD file for this printer must still be modified
248            manually, as well as pykota's configuration file for a
249            new printer to be managed successfully.
250           
251  $ edpykota -g -S 500 -H 550 financial support           
252 
253  This will set print quota soft limit to 500 pages and hard limit
254  to 550 pages for groups financial and support on all printers.
255 
256  $ edpykota --reset jerome "jo*"
257 
258  This will reset jerome's page counter to zero on all printers, as
259  well as every user whose name begins with 'jo'.
260  Their life time page counter on each printer will be kept unchanged.
261 
262  $ edpykota --printer hpcolor --noquota jerome
263 
264  This will tell PyKota to not limit jerome when printing on the
265  hpcolor printer. All his jobs will be allowed on this printer, but
266  accounting of the pages he prints will still be kept.
267  Print Quotas for jerome on other printers are unchanged.
268 
269  $ edpykota --limitby balance jerome
270 
271  This will tell PyKota to limit jerome by his account's balance
272  when printing.
273 
274  $ edpykota --balance +10.0 jerome
275 
276  This will increase jerome's account balance by 10.0 (in your
277  own currency). You can decrease the account balance with a
278  dash prefix, and set it to a fixed amount with no prefix.
279 
280  $ edpykota --delete jerome rachel
281 
282  This will completely delete jerome and rachel from the Quota Storage
283  database. All their quotas and jobs will be deleted too.
284 
285  $ edpykota --printer lp --charge 0.1
286 
287  This will set the page price for printer lp to 0.1. Job price
288  will not be changed.
289
290This program is free software; you can redistribute it and/or modify
291it under the terms of the GNU General Public License as published by
292the Free Software Foundation; either version 2 of the License, or
293(at your option) any later version.
294
295This program is distributed in the hope that it will be useful,
296but WITHOUT ANY WARRANTY; without even the implied warranty of
297MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
298GNU General Public License for more details.
299
300You should have received a copy of the GNU General Public License
301along with this program; if not, write to the Free Software
302Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
303
304Please e-mail bugs to: %s""" % (version.__version__, version.__author__)
305       
306class EdPyKota(PyKotaTool) :       
307    """A class for edpykota."""
308    def main(self, names, options) :
309        """Edit user or group quotas."""
310        printeradded = 0
311        printers = self.storage.getMatchingPrinters(options["printer"])
312        if not printers :
313            pname = options["printer"]
314            if options["add"] and pname :
315                if self.isValidName(pname) :
316                    printerid = self.storage.addPrinter(pname)
317                    printers = [ (printerid, pname) ]
318                    printeradded = 1
319                else :   
320                    raise PyKotaToolError, _("Invalid printer name %s") % pname
321            else :
322                raise PyKotaToolError, _("There's no printer matching %s") % pname
323               
324        softlimit = hardlimit = None   
325        if options["softlimit"] :
326            try :
327                softlimit = int(options["softlimit"].strip())
328            except ValueError :   
329                raise PyKotaToolError, _("Invalid softlimit value %s.") % options["softlimit"]
330        if options["hardlimit"] :
331            try :
332                hardlimit = int(options["hardlimit"].strip())
333            except ValueError :   
334                raise PyKotaToolError, _("Invalid hardlimit value %s.") % options["hardlimit"]
335        if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :       
336            # error, exchange them
337            self.logger.log_message(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit))
338            (softlimit, hardlimit) = (hardlimit, softlimit)
339           
340        if not names :   
341            if options["add"] and not printeradded :
342                raise PyKotaToolError, _("You have to pass user names on the command line")
343            else :   
344                names = [ "*" ] # all users
345               
346        balance = options["balance"]
347        if balance :
348            balance = balance.strip()
349            try :
350                balancevalue = float(balance)
351            except ValueError :   
352                raise PyKotaToolError, _("Invalid balance value %s" % options["balance"])
353           
354        if options["charge"] :
355            try :
356                charges = [float(part) for part in options["charge"].split(',', 1)]
357            except ValueError :   
358                raise PyKotaToolError, _("Invalid charge amount value %s" % options["charge"])
359            else :   
360                if len(charges) < 2 :
361                    charges.append(None)
362                   
363        limitby = options["limitby"]
364        if limitby :
365            limitby = limitby.strip().lower()
366        if limitby and (limitby not in ('quota', 'balance')) :   
367            raise PyKotaToolError, _("Invalid limitby value %s" % options["limitby"])
368           
369        for (printerid, printer) in printers :
370            if options["charge"] :
371                (perpage, perjob) = charges
372                if perjob is None :
373                    # we don't want to change this one, get the old value
374                    (dummy, perjob) = self.storage.getPrinterPrices(printerid)
375                self.storage.setPrinterPrices(printerid, perpage, perjob)   
376            if options["prototype"] :
377                if options["groups"] :
378                    prototype = self.storage.getGroupPQuota(self.storage.getGroupId(options["prototype"]), printerid)
379                else :     
380                    # default is user quota edition
381                    prototype = self.storage.getUserPQuota(self.storage.getUserId(options["prototype"]), printerid)
382                if prototype is None :
383                    self.logger.log_message(_("Prototype %s not found in Quota Storage for printer %s.") % (options["prototype"], printer))
384                    continue    # skip this printer
385                else :   
386                    (softlimit, hardlimit) = (prototype["softlimit"], prototype["hardlimit"])
387            if hardlimit is None :   
388                hardlimit = softlimit
389                if hardlimit is not None :
390                    self.logger.log_message(_("Undefined hard limit set to soft limit (%s) on printer %s.") % (str(hardlimit), printer))
391            if softlimit is None :   
392                softlimit = hardlimit
393                if softlimit is not None :
394                    self.logger.log_message(_("Undefined soft limit set to hard limit (%s) on printer %s.") % (str(softlimit), printer))
395            if (not options["reset"] and not options["noquota"] and not options["prototype"] and not options["limitby"] and not options["balance"] and not options["delete"] and not options["charge"]) and ((hardlimit is None) or (softlimit is None)) :
396                raise PyKotaToolError, _("Both hard and soft limits must be set ! Aborting.")
397            if options["add"] :   
398                if options["groups"] :   
399                    allidnames = [(self.storage.getGroupId(n), n) for n in names]
400                else :
401                    allidnames = [(self.storage.getUserId(n), n) for n in names]
402            else :   
403                if options["groups"] :   
404                    allidnames = self.storage.getPrinterGroups(printerid)
405                else :   
406                    allidnames = self.storage.getPrinterUsers(printerid)
407            for (ident, name) in [(i, n) for (i, n) in allidnames if self.matchString(n, names)]:
408                if options["groups"] :
409                    quota = self.storage.getGroupPQuota(ident, printerid)
410                else :
411                    quota = self.storage.getUserPQuota(ident, printerid)
412                if quota is None :
413                    # not found
414                    if options["add"] :
415                        # In case we want to add something, it is crucial
416                        # that we DON'T check with the system accounts files
417                        # like /etc/passwd because users may be defined
418                        # only remotely
419                        if options["groups"] :
420                            if self.isValidName(name) :
421                                (ident, printerid) = self.storage.addGroupPQuota(name, printerid)
422                                quota = self.storage.getGroupPQuota(ident, printerid)
423                            else :   
424                                self.logger.log_message(_("Invalid group name %s") % name)
425                        else :
426                            if self.isValidName(name) :
427                                (ident, printerid) = self.storage.addUserPQuota(name, printerid)
428                                quota = self.storage.getUserPQuota(ident, printerid)
429                            else :   
430                                self.logger.log_message(_("Invalid user name %s") % name)
431                if quota is None :     
432                    self.logger.log_message(_("Quota not found for object %s on printer %s.") % (name, printer))
433                else :   
434                    if options["delete"] :
435                        if options["groups"] :
436                            self.storage.deleteGroup(ident)
437                        else :
438                            self.storage.deleteUser(ident)
439                    else :
440                        if options["groups"] :
441                            if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) :
442                                self.storage.setGroupPQuota(ident, printerid, softlimit, hardlimit)
443                            if options["reset"] :
444                                self.storage.resetGroupPQuota(ident, printerid)
445                            if limitby :
446                                self.storage.limitGroupBy(ident, limitby)
447                            self.warnGroupPQuota(name, printer)   
448                        else :
449                            if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) :
450                                self.storage.setUserPQuota(ident, printerid, softlimit, hardlimit)
451                            if options["reset"] :
452                                self.storage.resetUserPQuota(ident, printerid)
453                            if limitby :
454                                self.storage.limitUserBy(ident, limitby)
455                            if balance :
456                                if balance.startswith("+") or balance.startswith("-") :
457                                    self.storage.increaseUserBalance(ident, balancevalue)
458                                else :
459                                    self.storage.setUserBalance(ident, balancevalue)
460                            self.warnUserPQuota(name, printer)   
461                     
462if __name__ == "__main__" : 
463    try :
464        defaults = { \
465                     "printer" : "*", \
466                   }
467        short_options = "vhdc:l:b:i:naugrp:P:S:H:"
468        long_options = ["help", "version", "charge=", "delete", "limitby=", "balance=", "ingroups=", "noquota", "add", "users", "groups", "reset", "prototype=", "printer=", "softlimit=", "hardlimit="]
469       
470        # Initializes the command line tool
471        editor = EdPyKota(doc=__doc__)
472       
473        # parse and checks the command line
474        (options, args) = editor.parseCommandline(sys.argv[1:], short_options, long_options)
475       
476        # sets long options
477        options["help"] = options["h"] or options["help"]
478        options["version"] = options["v"] or options["version"]
479        options["add"] = options["a"] or options["add"]
480        options["users"] = options["u"] or options["users"]
481        options["groups"] = options["g"] or options["groups"]
482        options["prototype"] = options["p"] or options["prototype"]
483        options["printer"] = options["P"] or options["printer"] or defaults["printer"]
484        options["softlimit"] = options["S"] or options["softlimit"]
485        options["hardlimit"] = options["H"] or options["hardlimit"] 
486        options["reset"] = options["r"] or options["reset"] 
487        options["noquota"] = options["n"] or options["noquota"]
488        options["limitby"] = options["l"] or options["limitby"]
489        options["balance"] = options["b"] or options["balance"] 
490        options["delete"] = options["d"] or options["delete"] 
491        options["ingroups"] = options["i"] or options["ingroups"]
492        options["charge"] = options["c"] or options["charge"]
493       
494        if options["help"] :
495            editor.display_usage_and_quit()
496        elif options["version"] :
497            editor.display_version_and_quit()
498        elif options["users"] and options["groups"] :   
499            raise PyKotaToolError, _("incompatible options, see help.")
500        elif (options["add"] or options["prototype"]) and options["delete"] :   
501            raise PyKotaToolError, _("incompatible options, see help.")
502        elif (options["softlimit"] or options["hardlimit"]) and options["prototype"] :   
503            raise PyKotaToolError, _("incompatible options, see help.")
504        elif options["noquota"] and (options["prototype"] or options["hardlimit"] or options["softlimit"]) :
505            raise PyKotaToolError, _("incompatible options, see help.")
506        elif options["groups"] and (options["balance"] or options["ingroups"]) :
507            raise PyKotaToolError, _("incompatible options, see help.")
508        elif options["groups"] :   
509            raise PyKotaToolError, _("option --groups is currently not implemented.")
510        else :
511            sys.exit(editor.main(args, options))
512    except PyKotaToolError, msg :           
513        sys.stderr.write("%s\n" % msg)
514        sys.stderr.flush()
515        sys.exit(-1)
Note: See TracBrowser for help on using the browser.