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

Revision 1021, 18.6 kB (checked in by jalet, 21 years ago)

Deletion of the second user which is not needed anymore.
Added a debug configuration field in /etc/pykota.conf
All queries can now be sent to the logger in debug mode, this will
greatly help improve performance when time for this will come.

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