root / pykota / trunk / bin / pkusers @ 2701

Revision 2701, 17.7 kB (checked in by jerome, 18 years ago)

Option --list now works for pkusers.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
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
30
31from pykota.tool import PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_
32
33__doc__ = N_("""pkusers v%(__version__)s (c) %(__years__)s %(__author__)s
34
35An Users and Groups Manager for PyKota.
36
37command line usage :
38
39  pkusers [options] user1 user2 user3 ... userN
40 
41or : 
42
43  pkusers --groups [options] group1 group2 group3 ... groupN
44
45options :
46
47  -v | --version       Prints pkusers's version number then exits.
48  -h | --help          Prints this message then exits.
49 
50  -a | --add           Adds users if they don't exist on the database.
51                       If they exist, they are modified unless
52                       -s|--skipexisting is also used.
53                       
54  -d | --delete        Deletes users from the quota storage.
55 
56  -D | --description d Adds a textual description to users or groups.
57                       
58  -g | --groups        Edit users groups instead of users.
59                         
60  -p | --prototype u|g Uses user u or group g as a prototype to create
61                       or modify datas.
62                       
63  -o | --overcharge f  Sets the overcharging factor applied to the user
64                       when computing the cost of a print job. Positive or
65                       negative floating point values are allowed,
66                       this allows you to do some really creative
67                       things like giving money to an user whenever
68                       he prints. The number of pages in a print job
69                       is not modified by this coefficient, only the
70                       cost of the job for a particular user.
71                       Only users have such a coefficient.
72 
73  -i | --ingroups g1[,g2...]  Puts the users into each of the groups
74                              listed, separated by commas. The groups
75                              must already exist in the Quota Storage.
76                       
77  -l | --limitby l     Choose if the user/group is limited in printing                     
78                       by its account balance or by its page quota.
79                       The default value is 'quota'. Allowed values
80                       are 'quota' 'balance' 'noquota' 'noprint' 
81                       and 'nochange' :
82                       
83                         - quota : limit by number of pages per printer.
84                         - balance : limit by number of credits in account.
85                         - noquota : no limit, accounting still done.
86                         - nochange : no limit, accounting not done.
87                         - noprint : printing is denied.
88                       NB : nochange and noprint are not supported for groups.
89                       
90  -b | --balance b     Sets the user's account balance to b.                     
91                       Account balance may be increase or decreased
92                       if b is prefixed with + or -.
93                       WARNING : when decreasing account balance,
94                       the total paid so far by the user is decreased
95                       too.
96                       Groups don't have a real balance, but the
97                       sum of their users' account balance.
98                       
99  -C | --comment txt   Defines some informational text to be associated
100                       with a change to an user's account balance.
101                       Only meaningful if -b | --balance is also used.
102                       
103                       
104  -r | --remove        In combination with the --groups option above,                       
105                       remove users from the specified users groups.
106                       
107  -s | --skipexisting  In combination with the --add option above, tells
108                       pkusers to not modify existing users.
109                       
110  user1 through userN and group1 through groupN can use wildcards
111  if the --add option is not set.
112 
113examples :                             
114
115  TODO...
116""")
117       
118class PKUsers(PyKotaTool) :       
119    """A class for a users and users groups manager."""
120    def main(self, names, options) :
121        """Manage users or groups."""
122        if not self.config.isAdmin :
123            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
124           
125        suffix = (options["groups"] and "Group") or "User"       
126       
127        if options["delete"] :   
128            self.display("%s...\n" % _("Deletion"))
129            todelete = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
130            nbtotal = len(todelete)
131            for i in range(nbtotal) :
132                todelete[i].delete()
133                percent = 100.0 * float(i) / float(nbtotal)
134                self.display("\r%.02f%%" % percent)
135        else :
136            if options["add"] :   
137                self.display("%s...\n" % _("Creation"))
138                rejectunknown = self.config.getRejectUnknown()   
139                entries = []
140                nbtotal = len(names)
141                for i in range(nbtotal) :
142                    ename = names[i]
143                    email = ""
144                    if not options["groups"] :
145                        splitname = ename.split('/', 1)     # username/email
146                        if len(splitname) == 1 :
147                            splitname.append("")
148                        (ename, email) = splitname
149                        if email and (email.count('@') != 1) :
150                            self.printInfo(_("Invalid email address %s") % email)
151                            email = ""
152                    entry = getattr(self.storage, "get%s" % suffix)(ename)
153                    if entry.Exists :
154                        if options["skipexisting"] :
155                            self.printInfo(_("%s %s already exists, skipping.") % (suffix, entry.Name))
156                        else :   
157                            self.printInfo(_("%s %s already exists, will be modified.") % (suffix, entry.Name))
158                            entries.append(entry)
159                    else :
160                        if self.isValidName(entry.Name) :
161                            reject = 0
162                            if rejectunknown :
163                                if options["groups"] :
164                                    try :
165                                        grp.getgrnam(entry.Name)
166                                    except KeyError :   
167                                        self.printInfo(_("Unknown group %s") % entry.Name, "error")
168                                        reject = 1
169                                else :   
170                                    try :
171                                        pwd.getpwnam(entry.Name)
172                                    except KeyError :   
173                                        self.printInfo(_("Unknown user %s") % entry.Name, "error")
174                                        reject = 1
175                            if not reject :       
176                                if email :
177                                    entry.Email = email
178                                entry = getattr(self.storage, "add%s" % suffix)(entry)
179                                entries.append(entry)
180                        else :   
181                            if options["groups"] :
182                                self.printInfo(_("Invalid group name %s") % entry.Name)
183                            else :   
184                                self.printInfo(_("Invalid user name %s") % entry.Name)
185                               
186                    percent = 100.0 * float(i) / float(nbtotal)
187                    self.display("\r%.02f%%" % percent)
188                self.display("\r100.00%%\r        \r%s\n" % _("Done."))
189            else :       
190                if not names :
191                    names = ["*"]
192                entries = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
193                if not entries :
194                    raise PyKotaCommandLineError, _("There's no %s matching %s") % (suffix.lower(), " ".join(names))
195                       
196            if options["list"] :
197                if suffix == "User" :
198                    maildomain = self.config.getMailDomain()
199                    smtpserver = self.config.getSMTPServer()
200                    for entry in entries :
201                        email = entry.Email
202                        if not email :
203                            if maildomain :     
204                                email = "%s@%s" % (entry.Name, maildomain)
205                            elif smtpserver :   
206                                email = "%s@%s" % (entry.Name, smtpserver)
207                            else :   
208                                email = "%s@%s" % (entry.Name, "localhost")
209                        msg = "%s - <%s>" % (entry.Name, email)
210                        if entry.Description :
211                            msg += " - %s" % entry.Description
212                        print msg   
213                        print "    %s" % (_("Limited by : %s") % entry.LimitBy)
214                        print "    %s" % (_("Account balance : %.2f") % (entry.AccountBalance or 0.0))
215                        print "    %s" % (_("Total paid so far : %.2f") % (entry.LifeTimePaid or 0.0))
216                        print "    %s" % (_("Overcharging factor : %.2f") % entry.OverCharge)
217                else :   
218                    for entry in entries :
219                        msg = "%s" % entry.Name
220                        if entry.Description :
221                            msg += " - %s" % entry.Description
222                        print msg   
223                        print "    %s" % (_("Limited by : %s") % entry.LimitBy)
224                        print "    %s" % (_("Group balance : %.2f") % (entry.AccountBalance or 0.0))
225                        print "    %s" % (_("Total paid so far : %.2f") % (entry.LifeTimePaid or 0.0))
226            else :
227                self.display("%s...\n" % _("Modification"))
228               
229                limitby = options["limitby"]
230                if limitby :
231                    limitby = limitby.strip().lower()
232                if limitby :
233                    if limitby not in ('quota', 'balance', 'noquota', \
234                                                'noprint', 'nochange') :
235                        raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
236                    if limitby in ('noquota', 'nochange') :   
237                        options["noquota"] = 1
238                    if (limitby in ('nochange', 'noprint')) and options["groups"] :   
239                        raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
240                   
241                overcharge = options["overcharge"]
242                if overcharge :
243                    try :
244                        overcharge = float(overcharge.strip())
245                    except (ValueError, AttributeError) :   
246                        raise PyKotaCommandLineError, _("Invalid overcharge value %s") % options["overcharge"]
247                       
248                balance = options["balance"]
249                if balance :
250                    balance = balance.strip()
251                    try :
252                        balancevalue = float(balance)
253                    except ValueError :   
254                        raise PyKotaCommandLineError, _("Invalid balance value %s") % options["balance"]
255                   
256                if options["ingroups"] :
257                    usersgroups = self.storage.getMatchingGroups(options["ingroups"])
258                    if not usersgroups :
259                        raise PyKotaCommandLineError, _("There's no users group matching %s") % " ".join(options["ingroups"].split(','))
260                else :         
261                    usersgroups = []
262                       
263                if options["description"] :
264                    description = options["description"].strip()
265                   
266                if options["prototype"] :   
267                    protoentry = getattr(self.storage, "get%s" % suffix)(options["prototype"])
268                    if not protoentry.Exists :
269                        raise PyKotaCommandLineError, _("Prototype object %s not found in Quota Storage.") % protoentry.Name
270                    else :   
271                        limitby = protoentry.LimitBy
272                        balancevalue = protoentry.AccountBalance
273                        if balancevalue is not None :
274                            balance = str(abs(balancevalue))
275                        else :   
276                            balance = None
277                        overcharge = getattr(protoentry, "OverCharge", None)
278                   
279                nbtotal = len(entries)
280                for i in range(nbtotal) :       
281                    entry = entries[i]
282                    if description is not None :        # NB : "" is allowed !
283                        entry.setDescription(description)
284                    entry.save()   
285                    if not options["groups"] :
286                        for ugroup in usersgroups :
287                            if options["remove"] :
288                                ugroup.delUserFromGroup(entry)
289                            else :
290                                ugroup.addUserToGroup(entry)
291                    percent = 100.0 * float(i) / float(nbtotal)
292                    self.display("\r%.02f%%" % percent)
293                               
294        if not options["list"] :               
295            self.display("\r100.00%%\r        \r%s\n" % _("Done."))
296                     
297if __name__ == "__main__" : 
298    retcode = 0
299    try :
300        defaults = { \
301                     "comment" : "", \
302                   }
303        short_options = "hvaD:dgl:rsp:o:i:b:C:L"
304        long_options = ["help", "version", "add", "description=", \
305                        "delete", "groups", "list", "remove", \
306                        "skipexisting", "overcharge=", "prototype=", \
307                        "ingroups=", "limitby=", "balance=", "comment=", \
308                       ]
309                       
310       
311        # Initializes the command line tool
312        manager = PKUsers(doc=__doc__)
313        manager.deferredInit()
314       
315        # parse and checks the command line
316        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
317       
318        # sets long options
319        options["help"] = options["h"] or options["help"]
320        options["version"] = options["v"] or options["version"]
321        options["add"] = options["a"] or options["add"]
322        options["description"] = options["D"] or options["description"]
323        options["delete"] = options["d"] or options["delete"] 
324        options["groups"] = options["g"] or options["groups"]
325        options["list"] = options["L"] or options["list"]
326        options["remove"] = options["r"] or options["remove"]
327        options["skipexisting"] = options["s"] or options["skipexisting"]
328        options["prototype"] = options["p"] or options["prototype"]
329        options["limitby"] = options["l"] or options["limitby"]
330        options["balance"] = options["b"] or options["balance"] 
331        options["ingroups"] = options["i"] or options["ingroups"]
332        options["overcharge"] = options["o"] or options["overcharge"]
333        options["comment"] = options["C"] or options["comment"] or defaults["comment"]
334       
335        if options["help"] :
336            manager.display_usage_and_quit()
337        elif options["version"] :
338            manager.display_version_and_quit()
339        elif (options["delete"] and (options["add"] or options["groups"] or options["remove"] or options["description"])) \
340           or (options["skipexisting"] and not options["add"]) \
341           or (options["list"] and (options["add"] or options["delete"] or options["remove"] or options["description"])) \
342           or (options["groups"] and (options["balance"] or options["ingroups"] or options["overcharge"])) :
343            raise PyKotaCommandLineError, _("incompatible options, see help.")
344        elif options["remove"] and not options["ingroups"] :   
345            raise PyKotaCommandLineError, _("You have to pass user groups names on the command line")
346        elif (not args) and options["add"] :
347            raise PyKotaCommandLineError, _("You have to pass user or group names on the command line")
348        else :
349            retcode = manager.main(args, options)
350    except KeyboardInterrupt :       
351        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
352        retcode = -3
353    except PyKotaCommandLineError, msg :   
354        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
355        retcode = -2
356    except SystemExit :       
357        pass
358    except :
359        try :
360            manager.crashed("pkusers failed")
361        except :   
362            crashed("pkusers failed")
363        retcode = -1
364
365    try :
366        manager.storage.close()
367    except (TypeError, NameError, AttributeError) :   
368        pass
369       
370    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.