root / pykota / trunk / bin / edpykota @ 937

Revision 937, 22.9 kB (checked in by jalet, 21 years ago)

Docstring corrected for better manual page

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