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

Revision 1016, 14.3 kB (checked in by jalet, 21 years ago)

More good work on LDAP storage.

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