root / pykota / trunk / bin / edpykota @ 923

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

edpykota --charge command line option works now.

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