root / pykota / trunk / pykota / storages / ldapstorage.py @ 1017

Revision 1017, 16.1 kB (checked in by jalet, 21 years ago)

New LDAP schema.
Small bug fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2#
3# PyKota : Print Quotas for CUPS and LPRng
4#
5# (c) 2003 Jerome Alet <alet@librelogiciel.com>
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19#
20# $Id$
21#
22# $Log$
23# Revision 1.2  2003/06/06 14:21:08  jalet
24# New LDAP schema.
25# Small bug fixes.
26#
27# Revision 1.1  2003/06/05 11:19:13  jalet
28# More good work on LDAP storage.
29#
30#
31#
32
33#
34# My IANA assigned number, for
35# "Conseil Internet & Logiciels Libres, J�me Alet"
36# is 16868. Use this as a base to create the LDAP schema.
37#
38
39import fnmatch
40
41from pykota.storage import PyKotaStorageError
42
43try :
44    import ldap
45except ImportError :   
46    import sys
47    # TODO : to translate or not to translate ?
48    raise PyKotaStorageError, "This python version (%s) doesn't seem to have the python-ldap module installed correctly." % sys.version.split()[0]
49   
50class Storage :
51    def __init__(self, host, dbname, user, passwd) :
52        """Opens the LDAP connection."""
53        # raise PyKotaStorageError, "Sorry, the LDAP backend for PyKota is not yet implemented !"
54        self.closed = 1
55        try :
56            self.database = ldap.initialize(host) 
57            self.database.simple_bind_s(user, passwd)
58            self.basedn = dbname
59        except ldap.SERVER_DOWN :   
60            raise PyKotaStorageError, "LDAP backend for PyKota seems to be down !" # TODO : translate
61        else :   
62            self.closed = 0
63           
64    def __del__(self) :       
65        """Closes the database connection."""
66        if not self.closed :
67            del self.database
68            self.closed = 1
69       
70    def doSearch(self, key, fields, base="", scope=ldap.SCOPE_SUBTREE) :
71        """Does an LDAP search query."""
72        try :
73            # prepends something more restrictive at the beginning of the base dn
74            result = self.database.search_s(base or self.basedn, scope, key, fields)
75        except ldap.NO_SUCH_OBJECT :   
76            return
77        else :     
78            return result
79       
80    def getMatchingPrinters(self, printerpattern) :
81        """Returns the list of all printers as tuples (id, name) for printer names which match a certain pattern."""
82        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"])
83        if result :
84            return [(printerid, printer["pykotaPrinterName"][0]) for (printerid, printer) in result if fnmatch.fnmatchcase(printer["pykotaPrinterName"][0], printerpattern)]
85           
86    def getPrinterId(self, printername) :       
87        """Returns a printerid given a printername."""
88        result = self.doSearch("(&(objectClass=pykotaPrinter)(pykotaPrinterName=%s))" % printername, ["pykotaPrinterName"])
89        if result :
90            return result[0][0]
91           
92    def getPrinterPrices(self, printerid) :       
93        """Returns a printer prices per page and per job given a printerid."""
94        result = self.doSearch("pykotaPrinterName=*", ["pykotaPricePerPage", "pykotaPricePerJob"], base=printerid)
95        if result :
96            return (float(result[0][1]["pykotaPricePerPage"][0]), float(result[0][1]["pykotaPricePerJob"][0]))
97           
98    def setPrinterPrices(self, printerid, perpage, perjob) :
99        """Sets prices per job and per page for a given printer."""
100        pass
101   
102    def getUserId(self, username) :
103        """Returns a userid given a username."""
104        result = self.doSearch("(&(objectClass=pykotaAccount)(pykotaUserName=%s))" % username, ["uid"])
105        if result :
106            return result[0][0]
107           
108    def getGroupId(self, groupname) :
109        """Returns a groupid given a grupname."""
110        result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["cn"])
111        if result is not None :
112            (groupid, dummy) = result[0]
113            return groupid
114           
115    def getJobHistoryId(self, jobid, userid, printerid) :       
116        """Returns the history line's id given a (jobid, userid, printerid)."""
117        pass
118           
119    def getPrinterUsers(self, printerid) :       
120        """Returns the list of userids and usernames which uses a given printer."""
121        # first get the printer's name from the id
122        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"], base=printerid, scope=ldap.SCOPE_BASE)
123        if result :
124            printername = result[0][1]["pykotaPrinterName"][0]
125            result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaUserName"]) 
126            if result :
127                return [(pquotauserid, fields["pykotaUserName"][0]) for (pquotauserid, fields) in result]
128       
129    def getPrinterGroups(self, printerid) :       
130        """Returns the list of groups which uses a given printer."""
131        # first get the printer's name from the id
132        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"], base=printerid, scope=ldap.SCOPE_BASE)
133        if result :
134            printername = result[0][1]["pykotaPrinterName"][0]
135            result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaGroupName"]) 
136            if result :
137                return [(pquotagroupid, fields["pykotaGroupName"][0]) for (pquotagroupid, fields) in result]
138       
139    def getGroupMembersNames(self, groupname) :       
140        """Returns the list of user's names which are member of this group."""
141        result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["memberUid"])
142        if result :
143            return result[0][1]["memberUid"]
144       
145    def getUserGroupsNames(self, userid) :       
146        """Returns the list of groups' names the user is a member of."""
147        pass
148       
149    def addPrinter(self, printername) :       
150        """Adds a printer to the quota storage, returns its id."""
151        pass
152       
153    def addUser(self, username) :       
154        """Adds a user to the quota storage, returns its id."""
155        pass
156       
157    def addGroup(self, groupname) :       
158        """Adds a group to the quota storage, returns its id."""
159        pass
160       
161    def addUserPQuota(self, username, printerid) :
162        """Initializes a user print quota on a printer, adds the user to the quota storage if needed."""
163        pass
164       
165    def addGroupPQuota(self, groupname, printerid) :
166        """Initializes a group print quota on a printer, adds the group to the quota storage if needed."""
167        pass
168       
169    def increaseUserBalance(self, userid, amount) :   
170        """Increases (or decreases) an user's account balance by a given amount."""
171        pass
172       
173    def getUserBalance(self, userquotaid) :   
174        """Returns the current account balance for a given user quota identifier."""
175        # first get the user's name from the user quota id
176        result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE)
177        if result :
178            username = result[0][1]["pykotaUserName"][0]
179            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % username, ["pykotaBalance", "pykotaLifeTimePaid"])
180            if result :
181                fields = result[0][1]
182                return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
183       
184    def getUserBalanceFromUserId(self, userid) :   
185        """Returns the current account balance for a given user id."""
186        # first get the user's name from the user id
187        result = self.doSearch("objectClass=pykotaAccount", ["pykotaUserName"], base=userid, scope=ldap.SCOPE_BASE)
188        if result :
189            username = result[0][1]["pykotaUserName"][0]
190            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % username, ["pykotaBalance", "pykotaLifeTimePaid"])
191            if result :
192                fields = result[0][1]
193                return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
194       
195    def getGroupBalance(self, groupquotaid) :   
196        """Returns the current account balance for a given group, as the sum of each of its users' account balance."""
197        # first get the group's name from the group quota id
198        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE)
199        if result :
200            groupname = result[0][1]["pykotaGroupName"][0]
201            members = self.getGroupMembersNames(groupname)
202            balance = lifetimepaid = 0.0
203            for member in members :
204                userid = self.getUserId(member)
205                if userid :
206                    userbal = self.getUserBalanceFromUserId(userid)
207                    if userbal :
208                        (bal, paid) = userbal
209                        balance += bal
210                        lifetimepaid += paid
211            return (balance, lifetimepaid)           
212       
213    def getUserLimitBy(self, userid) :   
214        """Returns the way in which user printing is limited."""
215        result = self.doSearch("objectClass=pykotaAccount", ["pykotaLimitBy"], base=userid, scope=ldap.SCOPE_BASE)
216        if result :
217            return result[0][1]["pykotaLimitBy"][0]
218       
219    def getGroupLimitBy(self, groupquotaid) :   
220        """Returns the way in which group printing is limited."""
221        # first get the group's name from the group quota id
222        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE)
223        if result :
224            groupname = result[0][1]["pykotaGroupName"][0]
225            result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["pykotaLimitBy"])
226            if result :
227                return result[0][1]["pykotaLimitBy"][0]
228       
229    def setUserBalance(self, userid, balance) :   
230        """Sets the account balance for a given user to a fixed value."""
231        pass
232       
233    def limitUserBy(self, userid, limitby) :   
234        """Limits a given user based either on print quota or on account balance."""
235        pass
236       
237    def limitGroupBy(self, groupid, limitby) :   
238        """Limits a given group based either on print quota or on sum of its users' account balances."""
239        pass
240       
241    def setUserPQuota(self, userid, printerid, softlimit, hardlimit) :
242        """Sets soft and hard limits for a user quota on a specific printer given (userid, printerid)."""
243        pass
244       
245    def setGroupPQuota(self, groupid, printerid, softlimit, hardlimit) :
246        """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid)."""
247        pass
248       
249    def resetUserPQuota(self, userid, printerid) :   
250        """Resets the page counter to zero for a user on a printer. Life time page counter is kept unchanged."""
251        pass
252       
253    def resetGroupPQuota(self, groupid, printerid) :   
254        """Resets the page counter to zero for a group on a printer. Life time page counter is kept unchanged."""
255        pass
256       
257    def updateUserPQuota(self, userid, printerid, pagecount) :
258        """Updates the used user Quota information given (userid, printerid) and a job size in pages."""
259        pass
260       
261    def getUserPQuota(self, userquotaid, printerid) :
262        """Returns the Print Quota information for a given (userquotaid, printerid)."""
263        # first get the user's name from the id
264        result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=userquotaid, scope=ldap.SCOPE_BASE)
265        if result :
266            fields = result[0][1]
267            datelimit = fields["pykotaDateLimit"][0].strip()
268            if (not datelimit) or (datelimit.upper() == "NONE") : 
269                datelimit = None
270            return { "lifepagecounter" : int(fields["pykotaLifePageCounter"][0]), 
271                     "pagecounter" : int(fields["pykotaPageCounter"][0]),
272                     "softlimit" : int(fields["pykotaSoftLimit"][0]),
273                     "hardlimit" : int(fields["pykotaHardLimit"][0]),
274                     "datelimit" : datelimit
275                   }
276       
277    def getGroupPQuota(self, grouppquotaid, printerid) :
278        """Returns the Print Quota information for a given (grouppquotaid, printerid)."""
279        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=grouppquotaid, scope=ldap.SCOPE_BASE)
280        if result :
281            fields = result[0][1]
282            groupname = fields["pykotaGroupName"][0]
283            datelimit = fields["pykotaDateLimit"][0].strip()
284            if (not datelimit) or (datelimit.upper() == "NONE") : 
285                datelimit = None
286            quota = {
287                      "softlimit" : int(fields["pykotaSoftLimit"][0]),
288                      "hardlimit" : int(fields["pykotaHardLimit"][0]),
289                      "datelimit" : datelimit
290                    }
291            members = self.getGroupMembersNames(groupname)
292            pagecounter = lifepagecounter = 0
293            printerusers = self.getPrinterUsers(printerid)
294            if printerusers :
295                for (userid, username) in printerusers :
296                    if username in members :
297                        userpquota = self.getUserPQuota(userid, printerid)
298                        if userpquota :
299                            pagecounter += userpquota["pagecounter"]
300                            lifepagecounter += userpquota["lifepagecounter"]
301            quota.update({"pagecounter": pagecounter, "lifepagecounter": lifepagecounter})               
302            return quota
303       
304    def setUserDateLimit(self, userid, printerid, datelimit) :
305        """Sets the limit date for a soft limit to become an hard one given (userid, printerid)."""
306        pass
307       
308    def setGroupDateLimit(self, groupid, printerid, datelimit) :
309        """Sets the limit date for a soft limit to become an hard one given (groupid, printerid)."""
310        pass
311       
312    def addJobToHistory(self, jobid, userid, printerid, pagecounter, action) :
313        """Adds a job to the history: (jobid, userid, printerid, last page counter taken from requester)."""
314        pass
315   
316    def updateJobSizeInHistory(self, historyid, jobsize) :
317        """Updates a job size in the history given the history line's id."""
318        pass
319   
320    def getPrinterPageCounter(self, printerid) :
321        """Returns the last page counter value for a printer given its id, also returns last username, last jobid and history line id."""
322        return # TODO
323        result = self.doSearch("objectClass=pykotaPrinterJob", ["pykotaJobHistoryId", "pykotaJobId", "uid", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "pykotaJobDate"], base=printerid)
324        if result :
325            pass # TODO
326       
327    def addUserToGroup(self, userid, groupid) :   
328        """Adds an user to a group."""
329        pass
330       
331    def deleteUser(self, userid) :   
332        """Completely deletes an user from the Quota Storage."""
333        pass
334       
335    def deleteGroup(self, groupid) :   
336        """Completely deletes an user from the Quota Storage."""
337        pass
338       
339    def computePrinterJobPrice(self, printerid, jobsize) :   
340        """Returns the price for a job on a given printer."""
341        # TODO : create a base class with things like this
342        prices = self.getPrinterPrices(printerid)
343        if prices is None :
344            perpage = perjob = 0.0
345        else :   
346            (perpage, perjob) = prices
347        return perjob + (perpage * jobsize)
Note: See TracBrowser for help on using the browser.