root / pykota / trunk / bin / edpykota @ 922

Revision 922, 21.5 kB (checked in by jalet, 21 years ago)

More complete docstring

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