root / pykota / trunk / bin / edpykota @ 921

Revision 921, 21.3 kB (checked in by jalet, 21 years ago)

edpykota now accepts a --delete option.
Preparation to allow edpykota to accept much more command line options
(WARNING : docstring is OK, but code isn't !)

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