comparison roundup/roundupdb.py @ 753:938edfdeac6e

Sorry about this huge checkin! It's fixing a lot of related stuff in one go though. . [SF#541941] changing multilink properties by mail . [SF#526730] search for messages capability . [SF#505180] split MailGW.handle_Message - also changed cgi client since it was duplicating the functionality . build htmlbase if tests are run using CVS checkout (removed note from installation.txt) . don't create an empty message on email issue creation if the email is empty
author Richard Jones <richard@users.sourceforge.net>
date Wed, 29 May 2002 01:16:17 +0000
parents 51c425129b35
children ae0ec3c15e0d
comparison
equal deleted inserted replaced
752:a721f4e7ebbc 753:938edfdeac6e
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 # 17 #
18 # $Id: roundupdb.py,v 1.53 2002-05-25 07:16:24 rochecompaan Exp $ 18 # $Id: roundupdb.py,v 1.54 2002-05-29 01:16:17 richard Exp $
19 19
20 __doc__ = """ 20 __doc__ = """
21 Extending hyperdb with types specific to issue-tracking. 21 Extending hyperdb with types specific to issue-tracking.
22 """ 22 """
23 23
113 """These operations trigger detectors and can be vetoed. Attempts 113 """These operations trigger detectors and can be vetoed. Attempts
114 to modify the "creation" or "activity" properties cause a KeyError. 114 to modify the "creation" or "activity" properties cause a KeyError.
115 """ 115 """
116 if propvalues.has_key('creation') or propvalues.has_key('activity'): 116 if propvalues.has_key('creation') or propvalues.has_key('activity'):
117 raise KeyError, '"creation" and "activity" are reserved' 117 raise KeyError, '"creation" and "activity" are reserved'
118 for audit in self.auditors['create']: 118 self.fireAuditors('create', None, propvalues)
119 audit(self.db, self, None, propvalues)
120 nodeid = hyperdb.Class.create(self, **propvalues) 119 nodeid = hyperdb.Class.create(self, **propvalues)
121 for react in self.reactors['create']: 120 self.fireReactors('create', nodeid, None)
122 react(self.db, self, nodeid, None)
123 return nodeid 121 return nodeid
124 122
125 def set(self, nodeid, **propvalues): 123 def set(self, nodeid, **propvalues):
126 """These operations trigger detectors and can be vetoed. Attempts 124 """These operations trigger detectors and can be vetoed. Attempts
127 to modify the "creation" or "activity" properties cause a KeyError. 125 to modify the "creation" or "activity" properties cause a KeyError.
128 """ 126 """
129 if propvalues.has_key('creation') or propvalues.has_key('activity'): 127 if propvalues.has_key('creation') or propvalues.has_key('activity'):
130 raise KeyError, '"creation" and "activity" are reserved' 128 raise KeyError, '"creation" and "activity" are reserved'
131 for audit in self.auditors['set']: 129 self.fireAuditors('set', nodeid, propvalues)
132 audit(self.db, self, nodeid, propvalues)
133 # Take a copy of the node dict so that the subsequent set 130 # Take a copy of the node dict so that the subsequent set
134 # operation doesn't modify the oldvalues structure. 131 # operation doesn't modify the oldvalues structure.
135 try: 132 try:
136 # try not using the cache initially 133 # try not using the cache initially
137 oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid, 134 oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid,
139 except IndexError: 136 except IndexError:
140 # this will be needed if somone does a create() and set() 137 # this will be needed if somone does a create() and set()
141 # with no intervening commit() 138 # with no intervening commit()
142 oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid)) 139 oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid))
143 hyperdb.Class.set(self, nodeid, **propvalues) 140 hyperdb.Class.set(self, nodeid, **propvalues)
144 for react in self.reactors['set']: 141 self.fireReactors('set', nodeid, oldvalues)
145 react(self.db, self, nodeid, oldvalues)
146 142
147 def retire(self, nodeid): 143 def retire(self, nodeid):
148 """These operations trigger detectors and can be vetoed. Attempts 144 """These operations trigger detectors and can be vetoed. Attempts
149 to modify the "creation" or "activity" properties cause a KeyError. 145 to modify the "creation" or "activity" properties cause a KeyError.
150 """ 146 """
151 for audit in self.auditors['retire']: 147 self.fireAuditors('retire', nodeid, None)
152 audit(self.db, self, nodeid, None)
153 hyperdb.Class.retire(self, nodeid) 148 hyperdb.Class.retire(self, nodeid)
154 for react in self.reactors['retire']: 149 self.fireReactors('retire', nodeid, None)
155 react(self.db, self, nodeid, None)
156 150
157 def get(self, nodeid, propname, default=_marker, cache=1): 151 def get(self, nodeid, propname, default=_marker, cache=1):
158 """Attempts to get the "creation" or "activity" properties should 152 """Attempts to get the "creation" or "activity" properties should
159 do the right thing. 153 do the right thing.
160 """ 154 """
206 """ 200 """
207 l = self.auditors[event] 201 l = self.auditors[event]
208 if detector not in l: 202 if detector not in l:
209 self.auditors[event].append(detector) 203 self.auditors[event].append(detector)
210 204
205 def fireAuditors(self, action, nodeid, newvalues):
206 """Fire all registered auditors.
207 """
208 for audit in self.auditors[action]:
209 audit(self.db, self, nodeid, newvalues)
210
211 def react(self, event, detector): 211 def react(self, event, detector):
212 """Register a detector 212 """Register a detector
213 """ 213 """
214 l = self.reactors[event] 214 l = self.reactors[event]
215 if detector not in l: 215 if detector not in l:
216 self.reactors[event].append(detector) 216 self.reactors[event].append(detector)
217 217
218 def fireReactors(self, action, nodeid, oldvalues):
219 """Fire all registered reactors.
220 """
221 for react in self.reactors[action]:
222 react(self.db, self, nodeid, oldvalues)
218 223
219 class FileClass(Class): 224 class FileClass(Class):
220 def create(self, **propvalues): 225 def create(self, **propvalues):
221 ''' snaffle the file propvalue and store in a file 226 ''' snaffle the file propvalue and store in a file
222 ''' 227 '''
295 300
296 The given text is saved as the body of the message and the node is 301 The given text is saved as the body of the message and the node is
297 appended to the "messages" field of the specified issue. 302 appended to the "messages" field of the specified issue.
298 """ 303 """
299 304
300 def nosymessage(self, nodeid, msgid, change_note): 305 def nosymessage(self, nodeid, msgid, oldvalues):
301 """Send a message to the members of an issue's nosy list. 306 """Send a message to the members of an issue's nosy list.
302 307
303 The message is sent only to users on the nosy list who are not 308 The message is sent only to users on the nosy list who are not
304 already on the "recipients" list for the message. 309 already on the "recipients" list for the message.
305 310
316 r[recipid] = 1 321 r[recipid] = 1
317 322
318 # figure the author's id, and indicate they've received the message 323 # figure the author's id, and indicate they've received the message
319 authid = messages.get(msgid, 'author') 324 authid = messages.get(msgid, 'author')
320 325
321 # get the current nosy list, we'll need it
322 nosy = self.get(nodeid, 'nosy')
323
324 # possibly send the message to the author, as long as they aren't 326 # possibly send the message to the author, as long as they aren't
325 # anonymous 327 # anonymous
326 if (self.db.config.MESSAGES_TO_AUTHOR == 'yes' and 328 if (self.db.config.MESSAGES_TO_AUTHOR == 'yes' and
327 users.get(authid, 'username') != 'anonymous'): 329 users.get(authid, 'username') != 'anonymous'):
328 sendto.append(authid) 330 sendto.append(authid)
329 r[authid] = 1 331 r[authid] = 1
330 332
331 # now figure the nosy people who weren't recipients 333 # now figure the nosy people who weren't recipients
334 nosy = self.get(nodeid, 'nosy')
332 for nosyid in nosy: 335 for nosyid in nosy:
333 # Don't send nosy mail to the anonymous user (that user 336 # Don't send nosy mail to the anonymous user (that user
334 # shouldn't appear in the nosy list, but just in case they 337 # shouldn't appear in the nosy list, but just in case they
335 # do...) 338 # do...)
336 if users.get(nosyid, 'username') == 'anonymous': 339 if users.get(nosyid, 'username') == 'anonymous':
339 if not r.has_key(nosyid): 342 if not r.has_key(nosyid):
340 # send it to them 343 # send it to them
341 sendto.append(nosyid) 344 sendto.append(nosyid)
342 recipients.append(nosyid) 345 recipients.append(nosyid)
343 346
347 # generate a change note
348 if oldvalues:
349 note = self.generateChangeNote(nodeid, oldvalues)
350 else:
351 note = self.generateCreateNote(nodeid)
352
344 # we have new recipients 353 # we have new recipients
345 if sendto: 354 if sendto:
346 # map userids to addresses 355 # map userids to addresses
347 sendto = [users.get(i, 'address') for i in sendto] 356 sendto = [users.get(i, 'address') for i in sendto]
348 357
349 # update the message's recipients list 358 # update the message's recipients list
350 messages.set(msgid, recipients=recipients) 359 messages.set(msgid, recipients=recipients)
351 360
352 # send the message 361 # send the message
353 self.send_message(nodeid, msgid, change_note, sendto) 362 self.send_message(nodeid, msgid, note, sendto)
354 363
355 # XXX backwards compatibility - don't remove 364 # XXX backwards compatibility - don't remove
356 sendmessage = nosymessage 365 sendmessage = nosymessage
357 366
358 def send_message(self, nodeid, msgid, note, sendto): 367 def send_message(self, nodeid, msgid, note, sendto):
623 m.insert(0, '') 632 m.insert(0, '')
624 return '\n'.join(m) 633 return '\n'.join(m)
625 634
626 # 635 #
627 # $Log: not supported by cvs2svn $ 636 # $Log: not supported by cvs2svn $
637 # Revision 1.53 2002/05/25 07:16:24 rochecompaan
638 # Merged search_indexing-branch with HEAD
639 #
628 # Revision 1.52 2002/05/15 03:27:16 richard 640 # Revision 1.52 2002/05/15 03:27:16 richard
629 # . fixed SCRIPT_NAME in ZRoundup for instances not at top level of Zope 641 # . fixed SCRIPT_NAME in ZRoundup for instances not at top level of Zope
630 # (thanks dman) 642 # (thanks dman)
631 # . fixed some sorting issues that were breaking some unit tests under py2.2 643 # . fixed some sorting issues that were breaking some unit tests under py2.2
632 # . mailgw test output dir was confusing the init test (but only on 2.2 *shrug*) 644 # . mailgw test output dir was confusing the init test (but only on 2.2 *shrug*)

Roundup Issue Tracker: http://roundup-tracker.org/