root / pykota / trunk / bin / edpykota @ 1041

Revision 1041, 23.2 kB (checked in by jalet, 21 years ago)

Hey, it may work (edpykota --reset excepted) !

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