root / pykota / trunk / bin / pkusers @ 2699

Revision 2699, 16.1 kB (checked in by jerome, 18 years ago)

Preliminary work on pkusers. Don't use it right now !

  • 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                for entry in entries :
198                    print "%s - <%s>" % (entry.Name, entry.Email)
199            else :
200                self.display("%s...\n" % _("Modification"))
201               
202                limitby = options["limitby"]
203                if limitby :
204                    limitby = limitby.strip().lower()
205                if limitby :
206                    if limitby not in ('quota', 'balance', 'noquota', \
207                                                'noprint', 'nochange') :
208                        raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
209                    if limitby in ('noquota', 'nochange') :   
210                        options["noquota"] = 1
211                    if (limitby in ('nochange', 'noprint')) and options["groups"] :   
212                        raise PyKotaCommandLineError, _("Invalid limitby value %s") % options["limitby"]
213                   
214                overcharge = options["overcharge"]
215                if overcharge :
216                    try :
217                        overcharge = float(overcharge.strip())
218                    except (ValueError, AttributeError) :   
219                        raise PyKotaCommandLineError, _("Invalid overcharge value %s") % options["overcharge"]
220                       
221                balance = options["balance"]
222                if balance :
223                    balance = balance.strip()
224                    try :
225                        balancevalue = float(balance)
226                    except ValueError :   
227                        raise PyKotaCommandLineError, _("Invalid balance value %s") % options["balance"]
228                   
229                if options["ingroups"] :
230                    usersgroups = self.storage.getMatchingGroups(options["ingroups"])
231                    if not usersgroups :
232                        raise PyKotaCommandLineError, _("There's no users group matching %s") % " ".join(options["ingroups"].split(','))
233                else :         
234                    usersgroups = []
235                       
236                if options["description"] :
237                    description = options["description"].strip()
238                   
239                if options["prototype"] :   
240                    protoentry = getattr(self.storage, "get%s" % suffix)(options["prototype"])
241                    if not protoentry.Exists :
242                        raise PyKotaCommandLineError, _("Prototype object %s not found in Quota Storage.") % protoentry.Name
243                    else :   
244                        limitby = protoentry.LimitBy
245                        balancevalue = protoentry.AccountBalance
246                        if balancevalue is not None :
247                            balance = str(abs(balancevalue))
248                        else :   
249                            balance = None
250                        overcharge = getattr(protoentry, "OverCharge", None)
251                   
252                nbtotal = len(entries)
253                for i in range(nbtotal) :       
254                    entry = entries[i]
255                    if description is not None :        # NB : "" is allowed !
256                        entry.setDescription(description)
257                    entry.save()   
258                    if not options["groups"] :
259                        for ugroup in usersgroups :
260                            if options["remove"] :
261                                ugroup.delUserFromGroup(entry)
262                            else :
263                                ugroup.addUserToGroup(entry)
264                    percent = 100.0 * float(i) / float(nbtotal)
265                    self.display("\r%.02f%%" % percent)
266                               
267        if not options["list"] :               
268            self.display("\r100.00%%\r        \r%s\n" % _("Done."))
269                     
270if __name__ == "__main__" : 
271    retcode = 0
272    try :
273        defaults = { \
274                     "comment" : "", \
275                   }
276        short_options = "hvaD:dgl:rsp:o:i:b:C:L"
277        long_options = ["help", "version", "add", "description=", \
278                        "delete", "groups", "list", "remove", \
279                        "skipexisting", "overcharge=", "prototype=", \
280                        "ingroups=", "limitby=", "balance=", "comment=", \
281                       ]
282                       
283       
284        # Initializes the command line tool
285        manager = PKUsers(doc=__doc__)
286        manager.deferredInit()
287       
288        # parse and checks the command line
289        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
290       
291        # sets long options
292        options["help"] = options["h"] or options["help"]
293        options["version"] = options["v"] or options["version"]
294        options["add"] = options["a"] or options["add"]
295        options["description"] = options["D"] or options["description"]
296        options["delete"] = options["d"] or options["delete"] 
297        options["groups"] = options["g"] or options["groups"]
298        options["list"] = options["L"] or options["list"]
299        options["remove"] = options["r"] or options["remove"]
300        options["skipexisting"] = options["s"] or options["skipexisting"]
301        options["prototype"] = options["p"] or options["prototype"]
302        options["limitby"] = options["l"] or options["limitby"]
303        options["balance"] = options["b"] or options["balance"] 
304        options["ingroups"] = options["i"] or options["ingroups"]
305        options["overcharge"] = options["o"] or options["overcharge"]
306        options["comment"] = options["C"] or options["comment"] or defaults["comment"]
307       
308        if options["help"] :
309            manager.display_usage_and_quit()
310        elif options["version"] :
311            manager.display_version_and_quit()
312        elif (options["delete"] and (options["add"] or options["groups"] or options["remove"] or options["description"])) \
313           or (options["skipexisting"] and not options["add"]) \
314           or (options["list"] and (options["add"] or options["delete"] or options["groups"] or options["remove"] or options["description"])) \
315           or (options["groups"] and (options["balance"] or options["ingroups"] or options["overcharge"])) :
316            raise PyKotaCommandLineError, _("incompatible options, see help.")
317        elif options["remove"] and not options["ingroups"] :   
318            raise PyKotaCommandLineError, _("You have to pass user groups names on the command line")
319        elif (not args) and options["add"] :
320            raise PyKotaCommandLineError, _("You have to pass user or group names on the command line")
321        else :
322            retcode = manager.main(args, options)
323    except KeyboardInterrupt :       
324        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
325        retcode = -3
326    except PyKotaCommandLineError, msg :   
327        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
328        retcode = -2
329    except SystemExit :       
330        pass
331    except :
332        try :
333            manager.crashed("pkusers failed")
334        except :   
335            crashed("pkusers failed")
336        retcode = -1
337
338    try :
339        manager.storage.close()
340    except (TypeError, NameError, AttributeError) :   
341        pass
342       
343    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.