From 2117a87c051f3d7211f6d361f6ca6bab19d6cf9b Mon Sep 17 00:00:00 2001 From: rochecompaan Date: Sat, 15 Dec 2001 19:24:39 +0000 Subject: [PATCH] . Modified cgi interface to change properties only once all changes are collected, files created and messages generated. . Moved generation of change note to nosyreactors. . We now check for changes to "assignedto" to ensure it's added to the nosy list. git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@465 57a73879-2fb5-44c3-a270-3262357dd7e2 --- roundup/cgi_client.py | 153 ++++++++++-------- roundup/mailgw.py | 45 ++++-- roundup/roundupdb.py | 37 +++-- .../classic/detectors/nosyreaction.py | 17 +- .../extended/detectors/nosyreaction.py | 17 +- 5 files changed, 164 insertions(+), 105 deletions(-) diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py index f4fa8d1..4e6d075 100644 --- a/roundup/cgi_client.py +++ b/roundup/cgi_client.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: cgi_client.py,v 1.81 2001-12-12 23:55:00 richard Exp $ +# $Id: cgi_client.py,v 1.82 2001-12-15 19:24:39 rochecompaan Exp $ __doc__ = """ WWW request handler (also used in the stand-alone server). @@ -314,32 +314,10 @@ class Client: try: props, changed = parsePropsFromForm(self.db, cl, self.form, self.nodeid) - - # set status to chatting if 'unread' or 'resolved' - if not changed.has_key('status'): - try: - # determine the id of 'unread','resolved' and 'chatting' - unread_id = self.db.status.lookup('unread') - resolved_id = self.db.status.lookup('resolved') - chatting_id = self.db.status.lookup('chatting') - except KeyError: - pass - else: - if (not props.has_key('status') or - props['status'] == unread_id or - props['status'] == resolved_id): - props['status'] = chatting_id - changed['status'] = chatting_id - - # get the change note - change_note = cl.generateChangeNote(self.nodeid, changed) - - # make the changes - cl.set(self.nodeid, **props) - - # handle linked nodes and change message generation - self._post_editnode(self.nodeid, change_note) - + # make changes to the node + self._changenode(props) + # handle linked nodes + self._post_editnode(self.nodeid) # and some nice feedback for the user if changed: message = _('%(changes)s edited ok')%{'changes': @@ -455,37 +433,52 @@ class Client: pass else: props['status'] = unread_id + # add assignedto to the nosy list + if props.has_key('assignedto'): + assignedto_id = props['assignedto'] + if props.has_key('nosy') and not assignedto_id in props['nosy']: + props['nosy'].append(assignedto_id) + else: + props['nosy'] = [assignedto_id] + # check for messages + message = self._handle_message() + if message: + props['messages'] = [message] + # create the node and return it's id return cl.create(**props) - def _post_editnode(self, nid, change_note=''): - ''' do the linking and message sending part of the node creation + def _changenode(self, props): + ''' change the node based on the contents of the form ''' - cn = self.classname - cl = self.db.classes[cn] - # link if necessary - keys = self.form.keys() - for key in keys: - if key == ':multilink': - value = self.form[key].value - if type(value) != type([]): value = [value] - for value in value: - designator, property = value.split(':') - link, nodeid = roundupdb.splitDesignator(designator) - link = self.db.classes[link] - value = link.get(nodeid, property) - value.append(nid) - link.set(nodeid, **{property: value}) - elif key == ':link': - value = self.form[key].value - if type(value) != type([]): value = [value] - for value in value: - designator, property = value.split(':') - link, nodeid = roundupdb.splitDesignator(designator) - link = self.db.classes[link] - link.set(nodeid, **{property: nid}) - - # handle file attachments - files = cl.get(nid, 'files') + cl = self.db.classes[self.classname] + # set status to chatting if 'unread' or 'resolved' + try: + # determine the id of 'unread','resolved' and 'chatting' + unread_id = self.db.status.lookup('unread') + resolved_id = self.db.status.lookup('resolved') + chatting_id = self.db.status.lookup('chatting') + except KeyError: + pass + else: + if (props['status'] == unread_id or props['status'] == resolved_id): + props['status'] = chatting_id + # add assignedto to the nosy list + if props.has_key('assignedto'): + assignedto_id = props['assignedto'] + if not assignedto_id in props['nosy']: + props['nosy'].append(assignedto_id) + # create the message + message = self._handle_message() + if message: + props['messages'] = cl.get(self.nodeid, 'messages') + [message] + # make the changes + cl.set(self.nodeid, **props) + + def _handle_message(self): + ''' generate and edit message ''' + + # handle file attachments + files = [] if self.form.has_key('__file'): file = self.form['__file'] if file.filename: @@ -495,14 +488,10 @@ class Client: # create the new file entry files.append(self.db.file.create(type=mime_type, name=file.filename, content=file.file.read())) - # and save the reference - cl.set(nid, files=files) - - # - # generate an edit message - # # we don't want to do a message if none of the following is true... + cn = self.classname + cl = self.db.classes[self.classname] props = cl.getprops() note = None if self.form.has_key('__note'): @@ -513,7 +502,7 @@ class Client: return if not props['messages'].classname == 'msg': return - if not (len(cl.get(nid, 'nosy', [])) or note): + if not (self.form.has_key('nosy') or note): return # handle the note @@ -528,10 +517,6 @@ class Client: ' the web.\n')%{'classname': cn} m = [summary] - # append the change note - if change_note: - m.append(change_note) - # now create the message content = '\n'.join(m) message_id = self.db.msg.create(author=self.getuid(), @@ -539,9 +524,34 @@ class Client: content=content, files=files) # update the messages property - messages = cl.get(nid, 'messages') - messages.append(message_id) - cl.set(nid, messages=messages, files=files) + return message_id + + def _post_editnode(self, nid): + ''' do the linking part of the node creation + ''' + cn = self.classname + cl = self.db.classes[cn] + # link if necessary + keys = self.form.keys() + for key in keys: + if key == ':multilink': + value = self.form[key].value + if type(value) != type([]): value = [value] + for value in value: + designator, property = value.split(':') + link, nodeid = roundupdb.splitDesignator(designator) + link = self.db.classes[link] + value = link.get(nodeid, property) + value.append(nid) + link.set(nodeid, **{property: value}) + elif key == ':link': + value = self.form[key].value + if type(value) != type([]): value = [value] + for value in value: + designator, property = value.split(':') + link, nodeid = roundupdb.splitDesignator(designator) + link = self.db.classes[link] + link.set(nodeid, **{property: nid}) def newnode(self, message=None): ''' Add a new node to the database. @@ -574,7 +584,7 @@ class Client: props = {} try: nid = self._createnode() - # handle linked nodes and change message generation + # handle linked nodes self._post_editnode(nid) # and some nice feedback for the user message = _('%(classname)s created ok')%{'classname': cn} @@ -1090,6 +1100,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0): # # $Log: not supported by cvs2svn $ +# Revision 1.81 2001/12/12 23:55:00 richard +# Fixed some problems with user editing +# # Revision 1.80 2001/12/12 23:27:14 richard # Added a Zope frontend for roundup. # diff --git a/roundup/mailgw.py b/roundup/mailgw.py index 1f0a48a..0d6285e 100644 --- a/roundup/mailgw.py +++ b/roundup/mailgw.py @@ -73,7 +73,7 @@ are calling the create() method to create a new node). If an auditor raises an exception, the original message is bounced back to the sender with the explanatory message given in the exception. -$Id: mailgw.py,v 1.41 2001-12-10 00:57:38 richard Exp $ +$Id: mailgw.py,v 1.42 2001-12-15 19:24:39 rochecompaan Exp $ ''' @@ -506,6 +506,7 @@ not find a text/plain part to use. if n.has_key(nid): continue n[nid] = 1 props['nosy'] = n.keys() + # add assignedto to the nosy list try: assignedto = self.db.user.lookup(props['assignedto']) if assignedto not in props['nosy']: @@ -513,9 +514,6 @@ not find a text/plain part to use. except: pass - change_note = cl.generateChangeNote(nodeid, props) - content += change_note - message_id = self.db.msg.create(author=author, recipients=recipients, date=date.Date('.'), summary=summary, content=content, files=files) @@ -572,16 +570,21 @@ There was a problem with the message you sent: if self.db.hasnode('user', value): nid = value else: - try: - nid = self.db.user.lookup(value) - except: - continue + continue if n.has_key(nid): continue n[nid] = 1 props['nosy'] = n.keys() + recipients + # add the author to the nosy list if not n.has_key(author): props['nosy'].append(author) n[author] = 1 + # add assignedto to the nosy list + try: + assignedto = self.db.user.lookup(props['assignedto']) + if not n.has_key(assignedto): + props['nosy'].append(assignedto) + except: + pass # and attempt to create the new node try: @@ -620,21 +623,35 @@ def parseContent(content, blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'), if not section: continue lines = eol.split(section) - if lines[0] and lines[0][0] in '>|': - continue - if len(lines) > 1 and lines[1] and lines[1][0] in '>|': - continue if not summary: summary = lines[0] l.append(section) continue - if signature.match(lines[0]): - break + # TODO: write better pattern for matching signature - it + # currently truncates messages with dashes in + #if signature.match(lines[0]): + # break l.append(section) return summary, '\n\n'.join(l) # # $Log: not supported by cvs2svn $ +# Revision 1.27 2001/12/15 06:51:04 roche +# Merge with CVS +# +# Revision 1.1.1.11 2001/12/13 07:05:43 roche +# update from cvs +# +# Revision 1.41 2001/12/10 00:57:38 richard +# From CHANGES: +# . Added the "display" command to the admin tool - displays a node's values +# . #489760 ] [issue] only subject +# . fixed the doc/index.html to include the quoting in the mail alias. +# +# Also: +# . fixed roundup-admin so it works with transactions +# . disabled the back_anydbm module if anydbm tries to use dumbdbm +# # Revision 1.40 2001/12/05 14:26:44 rochecompaan # Removed generation of change note from "sendmessage" in roundupdb.py. # The change note is now generated when the message is created. diff --git a/roundup/roundupdb.py b/roundup/roundupdb.py index 609a626..6cb939a 100644 --- a/roundup/roundupdb.py +++ b/roundup/roundupdb.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundupdb.py,v 1.30 2001-12-12 21:47:45 richard Exp $ +# $Id: roundupdb.py,v 1.31 2001-12-15 19:24:39 rochecompaan Exp $ __doc__ = """ Extending hyperdb with types specific to issue-tracking. @@ -268,7 +268,7 @@ class IssueClass(Class): appended to the "messages" field of the specified issue. """ - def sendmessage(self, nodeid, msgid): + def sendmessage(self, nodeid, msgid, change_note): """Send a message to the members of an issue's nosy list. The message is sent only to users on the nosy list who are not @@ -344,6 +344,10 @@ class IssueClass(Class): # add the content m.append(self.db.msg.get(msgid, 'content')) + # add the change note + if change_note: + m.append(change_note) + # put in roundup's signature if self.EMAIL_SIGNATURE_POSITION == 'bottom': m.append(self.email_signature(nodeid, msgid)) @@ -416,7 +420,7 @@ class IssueClass(Class): line = '_' * max(len(web), len(email)) return '%s\n%s\n%s\n%s'%(line, email, web, line) - def generateChangeNote(self, nodeid, newvalues): + def generateChangeNote(self, nodeid, oldvalues): """Generate a change note that lists property changes """ cn = self.classname @@ -425,26 +429,25 @@ class IssueClass(Class): props = cl.getprops(protected=0) # determine what changed - for key in newvalues.keys(): + for key in oldvalues.keys(): if key in ['files','messages']: continue - new_value = newvalues[key] + new_value = cl.get(nodeid, key) # the old value might be non existent try: - old_value = cl.get(nodeid, key) - if type(old_value) is type([]): - old_value.sort() + old_value = oldvalues[key] + if type(new_value) is type([]): new_value.sort() - if old_value != new_value: - changed[key] = new_value + old_value.sort() + if new_value != old_value: + changed[key] = old_value except: changed[key] = new_value # list the changes m = [] - for propname, value in changed.items(): + for propname, oldvalue in changed.items(): prop = cl.properties[propname] - oldvalue = cl.get(nodeid, propname, None) - change = '%s -> %s'%(oldvalue, value) + value = cl.get(nodeid, propname, None) if isinstance(prop, hyperdb.Link): link = self.db.classes[prop.classname] key = link.labelprop(default_to_id=1) @@ -484,6 +487,8 @@ class IssueClass(Class): l.append(entry) if l: change += ' -%s'%(', '.join(l)) + else: + change = '%s -> %s'%(oldvalue, value) m.append('%s: %s'%(propname, change)) if m: m.insert(0, '----------') @@ -492,6 +497,12 @@ class IssueClass(Class): # # $Log: not supported by cvs2svn $ +# Revision 1.30 2001/12/12 21:47:45 richard +# . Message author's name appears in From: instead of roundup instance name +# (which still appears in the Reply-To:) +# . envelope-from is now set to the roundup-admin and not roundup itself so +# delivery reports aren't sent to roundup (thanks Patrick Ohly) +# # Revision 1.29 2001/12/11 04:50:49 richard # fixed the order of the blank line and '-------' line # diff --git a/roundup/templates/classic/detectors/nosyreaction.py b/roundup/templates/classic/detectors/nosyreaction.py index b81e587..1088aa0 100644 --- a/roundup/templates/classic/detectors/nosyreaction.py +++ b/roundup/templates/classic/detectors/nosyreaction.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: nosyreaction.py,v 1.8 2001-12-05 14:26:44 rochecompaan Exp $ +#$Id: nosyreaction.py,v 1.9 2001-12-15 19:24:39 rochecompaan Exp $ from roundup import roundupdb @@ -35,6 +35,7 @@ def nosyreaction(db, cl, nodeid, oldvalues): then provides a log of when the message was sent to whom. ''' messages = [] + change_note = '' if oldvalues is None: # the action was a create, so use all the messages in the create messages = cl.get(nodeid, 'messages') @@ -48,13 +49,15 @@ def nosyreaction(db, cl, nodeid, oldvalues): for msgid in cl.get(nodeid, 'messages'): if not m.has_key(msgid): messages.append(msgid) + if messages: + change_note = cl.generateChangeNote(nodeid, oldvalues) if not messages: return # send a copy to the nosy list for msgid in messages: try: - cl.sendmessage(nodeid, msgid) + cl.sendmessage(nodeid, msgid, change_note) except roundupdb.MessageSendError, message: raise roundupdb.DetectorError, message @@ -63,15 +66,17 @@ def nosyreaction(db, cl, nodeid, oldvalues): n = {} for nosyid in nosy: n[nosyid] = 1 change = 0 - # but don't add admin or the anonymous user to the nosy list + # but don't add admin or the anonymous user to the nosy list and + # don't add the author if he just removed himself for msgid in messages: + authid = db.msg.get(msgid, 'author') for recipid in db.msg.get(msgid, 'recipients'): if recipid == '1': continue if n.has_key(recipid): continue if db.user.get(recipid, 'username') == 'anonymous': continue + if recipid == authid and not n.has_key(authid): continue change = 1 nosy.append(recipid) - authid = db.msg.get(msgid, 'author') if authid == '1': continue if n.has_key(authid): continue if db.user.get(authid, 'username') == 'anonymous': continue @@ -89,6 +94,10 @@ def init(db): # #$Log: not supported by cvs2svn $ +#Revision 1.8 2001/12/05 14:26:44 rochecompaan +#Removed generation of change note from "sendmessage" in roundupdb.py. +#The change note is now generated when the message is created. +# #Revision 1.7 2001/11/30 11:29:04 rochecompaan #Property changes are now listed in emails generated by Roundup # diff --git a/roundup/templates/extended/detectors/nosyreaction.py b/roundup/templates/extended/detectors/nosyreaction.py index 4643ed9..6dfe243 100644 --- a/roundup/templates/extended/detectors/nosyreaction.py +++ b/roundup/templates/extended/detectors/nosyreaction.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: nosyreaction.py,v 1.8 2001-12-05 14:26:44 rochecompaan Exp $ +#$Id: nosyreaction.py,v 1.9 2001-12-15 19:24:39 rochecompaan Exp $ from roundup import roundupdb @@ -35,6 +35,7 @@ def nosyreaction(db, cl, nodeid, oldvalues): then provides a log of when the message was sent to whom. ''' messages = [] + change_note = '' if oldvalues is None: # the action was a create, so use all the messages in the create messages = cl.get(nodeid, 'messages') @@ -48,13 +49,15 @@ def nosyreaction(db, cl, nodeid, oldvalues): for msgid in cl.get(nodeid, 'messages'): if not m.has_key(msgid): messages.append(msgid) + if messages: + change_note = cl.generateChangeNote(nodeid, oldvalues) if not messages: return # send a copy to the nosy list for msgid in messages: try: - cl.sendmessage(nodeid, msgid) + cl.sendmessage(nodeid, msgid, change_note) except roundupdb.MessageSendError, message: raise roundupdb.DetectorError, message @@ -63,15 +66,17 @@ def nosyreaction(db, cl, nodeid, oldvalues): n = {} for nosyid in nosy: n[nosyid] = 1 change = 0 - # but don't add admin or the anonymous user to the nosy list + # but don't add admin or the anonymous user to the nosy list and + # don't add the author if he just removed himself for msgid in messages: + authid = db.msg.get(msgid, 'author') for recipid in db.msg.get(msgid, 'recipients'): if recipid == '1': continue if n.has_key(recipid): continue if db.user.get(recipid, 'username') == 'anonymous': continue + if recipid == authid and not n.has_key(authid): continue change = 1 nosy.append(recipid) - authid = db.msg.get(msgid, 'author') if authid == '1': continue if n.has_key(authid): continue if db.user.get(authid, 'username') == 'anonymous': continue @@ -89,6 +94,10 @@ def init(db): # #$Log: not supported by cvs2svn $ +#Revision 1.8 2001/12/05 14:26:44 rochecompaan +#Removed generation of change note from "sendmessage" in roundupdb.py. +#The change note is now generated when the message is created. +# #Revision 1.7 2001/11/30 11:29:04 rochecompaan #Property changes are now listed in emails generated by Roundup # -- 2.30.2