root / pykota / trunk / bin / pkusers @ 2705

Revision 2705, 18.0 kB (checked in by jerome, 19 years ago)

Removed all references to the -p|--prototype command line switch, which
was (silently) removed.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[2699]1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota Users Manager
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22#
23# $Id$
24#
25#
26
27import os
28import sys
29import pwd
[2704]30import grp
[2699]31
32from pykota.tool import PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_
33
34__doc__ = N_("""pkusers v%(__version__)s (c) %(__years__)s %(__author__)s
35
36An Users and Groups Manager for PyKota.
37
38command line usage :
39
40  pkusers [options] user1 user2 user3 ... userN
41 
42or : 
43
44  pkusers --groups [options] group1 group2 group3 ... groupN
45
46options :
47
48  -v | --version       Prints pkusers's version number then exits.
49  -h | --help          Prints this message then exits.
50 
51  -a | --add           Adds users if they don't exist on the database.
52                       If they exist, they are modified unless
53                       -s|--skipexisting is also used.
54                       
55  -d | --delete        Deletes users from the quota storage.
56 
57  -D | --description d Adds a textual description to users or groups.
58                       
59  -g | --groups        Edit users groups instead of users.
60                         
61  -o | --overcharge f  Sets the overcharging factor applied to the user
62                       when computing the cost of a print job. Positive or
63                       negative floating point values are allowed,
64                       this allows you to do some really creative
65                       things like giving money to an user whenever
66                       he prints. The number of pages in a print job
67                       is not modified by this coefficient, only the
68                       cost of the job for a particular user.
69                       Only users have such a coefficient.
70 
71  -i | --ingroups g1[,g2...]  Puts the users into each of the groups
72                              listed, separated by commas. The groups
73                              must already exist in the Quota Storage.
74                       
75  -l | --limitby l     Choose if the user/group is limited in printing                     
76                       by its account balance or by its page quota.
77                       The default value is 'quota'. Allowed values
78                       are 'quota' 'balance' 'noquota' 'noprint' 
79                       and 'nochange' :
80                       
81                         - quota : limit by number of pages per printer.
82                         - balance : limit by number of credits in account.
83                         - noquota : no limit, accounting still done.
84                         - nochange : no limit, accounting not done.
85                         - noprint : printing is denied.
86                       NB : nochange and noprint are not supported for groups.
87                       
88  -b | --balance b     Sets the user's account balance to b.                     
89                       Account balance may be increase or decreased
90                       if b is prefixed with + or -.
91                       WARNING : when decreasing account balance,
92                       the total paid so far by the user is decreased
93                       too.
94                       Groups don't have a real balance, but the
95                       sum of their users' account balance.
96                       
97  -C | --comment txt   Defines some informational text to be associated
98                       with a change to an user's account balance.
99                       Only meaningful if -b | --balance is also used.
100                       
101                       
102  -r | --remove        In combination with the --groups option above,                       
103                       remove users from the specified users groups.
104                       
105  -s | --skipexisting  In combination with the --add option above, tells
106                       pkusers to not modify existing users.
107                       
108  user1 through userN and group1 through groupN can use wildcards
109  if the --add option is not set.
110 
111examples :                             
112
[2705]113  $ pkusers --add john paul george ringo/ringo@example.com
[2703]114 
115  This will add users john, paul, george and ringo to the quota
[2705]116  database. User ringo's email address will also be set to
117  'ringo@example.com'
[2703]118 
119  $ pkusers --ingroups coders,it jerome
120 
121  User jerome is put into the groups "coders" and "it" which must
122  already exist in the quota database.
123           
124  $ pkusers --limitby balance jerome
125 
126  This will tell PyKota to limit jerome by his account's balance
127  when printing.
128 
[2705]129  $ pkusers --balance +10.0 --comment "He paid with his blood !" jerome
[2703]130 
131  This will increase jerome's account balance by 10.0 (in your
132  own currency). You can decrease the account balance with a
133  dash prefix, and set it to a fixed amount with no prefix.
[2705]134  A comment will be stored for this balance change.
[2703]135 
136  $ pkusers --delete jerome rachel
137 
138  This will completely delete jerome and rachel from the quota
139  database. All their quotas and jobs will be deleted too.
140 
141  $ pkusers --overcharge 2.5 poorstudent
142 
143  This will overcharge the poorstudent user by a factor of 2.5.
144 
145  $ pkusers --overcharge -1 jerome
146 
147  User jerome will actually earn money whenever he prints.
148 
149  $ pkusers --overcharge 0 boss
150 
151  User boss can print at will, it won't cost him anything because the
152  cost of each print job will be multiplied by zero before charging
153  his account.
[2699]154""")
155       
156class PKUsers(PyKotaTool) :       
157    """A class for a users and users groups manager."""
158    def main(self, names, options) :
159        """Manage users or groups."""
160        if not self.config.isAdmin :
161            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
162           
163        suffix = (options["groups"] and "Group") or "User"       
164       
165        if options["delete"] :   
166            self.display("%s...\n" % _("Deletion"))
167            todelete = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
168            nbtotal = len(todelete)
169            for i in range(nbtotal) :
170                todelete[i].delete()
171                percent = 100.0 * float(i) / float(nbtotal)
172                self.display("\r%.02f%%" % percent)
173        else :
174            if options["add"] :   
175                self.display("%s...\n" % _("Creation"))
176                rejectunknown = self.config.getRejectUnknown()   
177                entries = []
178                nbtotal = len(names)
179                for i in range(nbtotal) :
180                    ename = names[i]
181                    email = ""
182                    if not options["groups"] :
183                        splitname = ename.split('/', 1)     # username/email
184                        if len(splitname) == 1 :
185                            splitname.append("")
186                        (ename, email) = splitname
187                        if email and (email.count('@') != 1) :
188                            self.printInfo(_("Invalid email address %s") % email)
189                            email = ""
190                    entry = getattr(self.storage, "get%s" % suffix)(ename)
191                    if entry.Exists :
192                        if options["skipexisting"] :
193                            self.printInfo(_("%s %s already exists, skipping.") % (suffix, entry.Name))
194                        else :   
195                            self.printInfo(_("%s %s already exists, will be modified.") % (suffix, entry.Name))
196                            entries.append(entry)
197                    else :
198                        if self.isValidName(entry.Name) :
199                            reject = 0
200                            if rejectunknown :
201                                if options["groups"] :
202                                    try :
203                                        grp.getgrnam(entry.Name)
204                                    except KeyError :   
205                                        self.printInfo(_("Unknown group %s") % entry.Name, "error")
206                                        reject = 1
207                                else :   
208                                    try :
209                                        pwd.getpwnam(entry.Name)
210                                    except KeyError :   
211                                        self.printInfo(_("Unknown user %s") % entry.Name, "error")
212                                        reject = 1
213                            if not reject :       
214                                if email :
215                                    entry.Email = email
216                                entry = getattr(self.storage, "add%s" % suffix)(entry)
217                                entries.append(entry)
218                        else :   
219                            if options["groups"] :
220                                self.printInfo(_("Invalid group name %s") % entry.Name)
221                            else :   
222                                self.printInfo(_("Invalid user name %s") % entry.Name)
223                               
224                    percent = 100.0 * float(i) / float(nbtotal)
225                    self.display("\r%.02f%%" % percent)
226                self.display("\r100.00%%\r        \r%s\n" % _("Done."))
227            else :       
228                if not names :
229                    names = ["*"]
230                entries = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
231                if not entries :
232                    raise PyKotaCommandLineError, _("There's no %s matching %s") % (suffix.lower(), " ".join(names))
233                       
234            if options["list"] :
[2701]235                if suffix == "User" :
236                    maildomain = self.config.getMailDomain()
237                    smtpserver = self.config.getSMTPServer()
238                    for entry in entries :
239                        email = entry.Email
240                        if not email :
241                            if maildomain :     
242                                email = "%s@%s" % (entry.Name, maildomain)
243                            elif smtpserver :   
244                                email = "%s@%s" % (entry.Name, smtpserver)
245                            else :   
246                                email = "%s@%s" % (entry.Name, "localhost")
247                        msg = "%s - <%s>" % (entry.Name, email)
248                        if entry.Description :
249                            msg += " - %s" % entry.Description
250                        print msg   
251                        print "    %s" % (_("Limited by : %s") % entry.LimitBy)
252                        print "    %s" % (_("Account balance : %.2f") % (entry.AccountBalance or 0.0))
253                        print "    %s" % (_("Total paid so far : %.2f") % (entry.LifeTimePaid or 0.0))
254                        print "    %s" % (_("Overcharging factor : %.2f") % entry.OverCharge)
255                else :   
256                    for entry in entries :
257                        msg = "%s" % entry.Name
258                        if entry.Description :
259                            msg += " - %s" % entry.Description
260                        print msg   
261                        print "    %s" % (_("Limited by : %s") % entry.LimitBy)
262                        print "    %s" % (_("Group balance : %.2f") % (entry.AccountBalance or 0.0))
263                        print "    %s" % (_("Total paid so far : %.2f") % (entry.LifeTimePaid or 0.0))
[2699]264            else :
265                self.display("%s...\n" % _("Modification"))
266               
267                limitby = options["limitby"]
268                if limitby :
269                    limitby = limitby.strip().lower()
270                if limitby :
271                    if limitby not in ('quota', 'balance', 'noquota', \
272                                                'noprint', 'nochange') :
273                        raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
274                    if (limitby in ('nochange', 'noprint')) and options["groups"] :   
275                        raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
276                   
277                overcharge = options["overcharge"]
278                if overcharge :
279                    try :
280                        overcharge = float(overcharge.strip())
281                    except (ValueError, AttributeError) :   
282                        raise PyKotaCommandLineError, _("Invalid overcharge value %s") % options["overcharge"]
283                       
284                balance = options["balance"]
285                if balance :
286                    balance = balance.strip()
287                    try :
288                        balancevalue = float(balance)
289                    except ValueError :   
290                        raise PyKotaCommandLineError, _("Invalid balance value %s") % options["balance"]
291                   
292                if options["ingroups"] :
293                    usersgroups = self.storage.getMatchingGroups(options["ingroups"])
294                    if not usersgroups :
295                        raise PyKotaCommandLineError, _("There's no users group matching %s") % " ".join(options["ingroups"].split(','))
296                else :         
297                    usersgroups = []
298                       
299                if options["description"] :
300                    description = options["description"].strip()
301                   
302                nbtotal = len(entries)
303                for i in range(nbtotal) :       
304                    entry = entries[i]
305                    if description is not None :        # NB : "" is allowed !
306                        entry.setDescription(description)
307                    entry.save()   
308                    if not options["groups"] :
309                        for ugroup in usersgroups :
310                            if options["remove"] :
311                                ugroup.delUserFromGroup(entry)
312                            else :
313                                ugroup.addUserToGroup(entry)
314                    percent = 100.0 * float(i) / float(nbtotal)
315                    self.display("\r%.02f%%" % percent)
316                               
317        if not options["list"] :               
318            self.display("\r100.00%%\r        \r%s\n" % _("Done."))
319                     
320if __name__ == "__main__" : 
321    retcode = 0
322    try :
323        defaults = { \
324                     "comment" : "", \
325                   }
[2705]326        short_options = "hvaD:dgl:rso:i:b:C:L"
[2699]327        long_options = ["help", "version", "add", "description=", \
328                        "delete", "groups", "list", "remove", \
[2705]329                        "skipexisting", "overcharge=", \
[2699]330                        "ingroups=", "limitby=", "balance=", "comment=", \
331                       ]
332                       
333       
334        # Initializes the command line tool
335        manager = PKUsers(doc=__doc__)
336        manager.deferredInit()
337       
338        # parse and checks the command line
339        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
340       
341        # sets long options
342        options["help"] = options["h"] or options["help"]
343        options["version"] = options["v"] or options["version"]
344        options["add"] = options["a"] or options["add"]
345        options["description"] = options["D"] or options["description"]
346        options["delete"] = options["d"] or options["delete"] 
347        options["groups"] = options["g"] or options["groups"]
348        options["list"] = options["L"] or options["list"]
349        options["remove"] = options["r"] or options["remove"]
350        options["skipexisting"] = options["s"] or options["skipexisting"]
351        options["limitby"] = options["l"] or options["limitby"]
352        options["balance"] = options["b"] or options["balance"] 
353        options["ingroups"] = options["i"] or options["ingroups"]
354        options["overcharge"] = options["o"] or options["overcharge"]
355        options["comment"] = options["C"] or options["comment"] or defaults["comment"]
356       
357        if options["help"] :
358            manager.display_usage_and_quit()
359        elif options["version"] :
360            manager.display_version_and_quit()
[2704]361        elif (options["delete"] and (options["add"] or options["remove"] or options["description"])) \
[2699]362           or (options["skipexisting"] and not options["add"]) \
[2701]363           or (options["list"] and (options["add"] or options["delete"] or options["remove"] or options["description"])) \
[2699]364           or (options["groups"] and (options["balance"] or options["ingroups"] or options["overcharge"])) :
365            raise PyKotaCommandLineError, _("incompatible options, see help.")
366        elif options["remove"] and not options["ingroups"] :   
367            raise PyKotaCommandLineError, _("You have to pass user groups names on the command line")
368        elif (not args) and options["add"] :
369            raise PyKotaCommandLineError, _("You have to pass user or group names on the command line")
370        else :
371            retcode = manager.main(args, options)
372    except KeyboardInterrupt :       
373        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
374        retcode = -3
375    except PyKotaCommandLineError, msg :   
376        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
377        retcode = -2
378    except SystemExit :       
379        pass
380    except :
381        try :
382            manager.crashed("pkusers failed")
383        except :   
384            crashed("pkusers failed")
385        retcode = -1
386
387    try :
388        manager.storage.close()
389    except (TypeError, NameError, AttributeError) :   
390        pass
391       
392    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.