Mercurial > p > roundup > code
annotate website/issues/detectors/rsswriter.py @ 6327:0014af559224
do not include email address in rss feed. Username only.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Wed, 10 Feb 2021 22:23:41 -0500 |
| parents | c34171b2af43 |
| children | bed1313898d4 |
| rev | line source |
|---|---|
| 6229 | 1 #!/usr/bin/python |
| 2 | |
| 3 # | |
| 4 # RSS writer Roundup reactor | |
| 5 # Mark Paschal <markpasc@markpasc.org> | |
| 6 # | |
| 7 | |
| 8 import os | |
| 9 | |
| 10 import logging | |
| 11 logger = logging.getLogger('detector') | |
| 12 | |
| 13 import sys | |
| 14 | |
| 15 # How many <item>s to have in the feed, at most. | |
| 16 MAX_ITEMS = 30 | |
| 17 | |
| 18 # | |
| 19 # Module metadata | |
| 20 # | |
| 21 | |
| 22 __author__ = "Mark Paschal <markpasc@markpasc.org>" | |
| 23 __copyright__ = "Copyright 2003 Mark Paschal" | |
| 24 __version__ = "1.2" | |
| 25 | |
| 26 __changes__ = """ | |
| 27 1.1 29 Aug 2003 Produces valid pubDates. Produces pubDates and authors for | |
| 28 change notes. Consolidates a message and change note into one | |
| 29 item. Uses TRACKER_NAME in filename to produce one feed per | |
| 30 tracker. Keeps to MAX_ITEMS limit more efficiently. | |
| 31 1.2 5 Sep 2003 Fixes bug with programmatically submitted issues having | |
| 32 messages without summaries (?!). | |
| 33 x.x 26 Feb 2017 John Rouillard try to deal with truncation of rss | |
| 34 file cause by error in parsing 8'bit characcters in | |
| 35 input message. Further attempts to fix issue by | |
| 36 modifying message bail on 0 length rss file. Delete | |
| 37 it and retry. | |
| 38 """ | |
| 39 | |
| 40 __license__ = 'MIT' | |
| 41 | |
| 42 # | |
| 43 # Copyright 2003 Mark Paschal | |
| 44 # | |
| 45 # Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 46 # of this software and associated documentation files (the "Software"), to deal | |
| 47 # in the Software without restriction, including without limitation the rights | |
| 48 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 49 # copies of the Software, and to permit persons to whom the Software is | |
| 50 # furnished to do so, subject to the following conditions: | |
| 51 # | |
| 52 # The above copyright notice and this permission notice shall be included in all | |
| 53 # copies or substantial portions of the Software. | |
| 54 # | |
| 55 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 56 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 57 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 58 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 59 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 60 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 61 # SOFTWARE. | |
| 62 # | |
| 63 | |
| 64 | |
| 65 # The strftime format to use for <pubDate>s. | |
| 66 RSS20_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S %z' | |
| 67 | |
| 68 | |
| 69 def newRss(title, link, description): | |
| 70 """Returns an XML Document containing an RSS 2.0 feed with no items.""" | |
| 71 import xml.dom.minidom | |
| 72 rss = xml.dom.minidom.Document() | |
| 73 | |
| 74 root = rss.appendChild(rss.createElement("rss")) | |
| 75 root.setAttribute("version", "2.0") | |
| 76 root.setAttribute("xmlns:atom","http://www.w3.org/2005/Atom") | |
| 77 | |
| 78 channel = root.appendChild(rss.createElement("channel")) | |
| 79 addEl = lambda tag,value: channel.appendChild(rss.createElement(tag)).appendChild(rss.createTextNode(value)) | |
| 80 def addElA(tag,attr): | |
| 81 node=rss.createElement(tag) | |
| 82 for attr, val in attr.items(): | |
| 83 node.setAttribute(attr, val) | |
| 84 channel.appendChild(node) | |
| 85 | |
| 86 addEl("title", title) | |
| 87 addElA('atom:link', attr={"rel": "self", | |
| 88 "type": "application/rss+xml", "href": link + "@@file/rss.xml"}) | |
| 89 addEl("link", link) | |
| 90 addEl("description", description) | |
| 91 | |
| 92 return rss # has no items | |
| 93 | |
| 94 | |
| 95 def writeRss(db, cl, nodeid, olddata): | |
| 96 """ | |
| 97 Reacts to a created or changed issue. Puts new messages and the change note | |
| 98 in items in the RSS feed, as determined by the rsswriter.py FILENAME setting. | |
| 99 If no RSS feed exists where FILENAME specifies, a new feed is created with | |
| 100 rsswriter.newRss. | |
| 101 """ | |
| 102 | |
| 103 # The filename of a tracker's RSS feed. Tracker config variables | |
| 104 # are placed with the standard '%' operator syntax. | |
| 105 | |
| 106 FILENAME = "%s/rss.xml"%db.config['TEMPLATES'] | |
| 107 | |
| 108 # i.e., roundup.cgi/projects/_file/rss.xml | |
| 109 # FILENAME = "/home/markpasc/public_html/%(TRACKER_NAME)s.xml" | |
| 110 | |
| 111 filename = FILENAME % db.config.__dict__ | |
| 112 | |
| 113 # return if issue is private | |
|
6308
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
114 # enable when private property is added |
|
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
115 ##if ( db.issue.get(nodeid, 'private') ): |
|
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
116 ## if __debug__: |
|
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
117 ## logger.debug("rss: Private issue. not generating rss") |
|
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
118 ## return |
| 6229 | 119 |
| 120 if __debug__: | |
| 121 logger.debug("rss: generating rss for issue %s", nodeid) | |
| 122 | |
| 123 # open the RSS | |
| 124 import xml.dom.minidom | |
| 125 from xml.parsers.expat import ExpatError | |
| 126 | |
| 127 try: | |
| 128 rss = xml.dom.minidom.parse(filename) | |
| 129 except IOError as e: | |
| 130 if 2 != e.errno: raise | |
| 131 # File not found | |
| 132 rss = newRss( | |
| 133 "%s tracker" % (db.config.TRACKER_NAME,), | |
| 134 db.config.TRACKER_WEB, | |
| 135 "Recent changes to the %s Roundup issue tracker" % (db.config.TRACKER_NAME,) | |
| 136 ) | |
| 137 except ExpatError as e: | |
| 138 if os.path.getsize(filename) == 0: | |
| 139 # delete the file, it's broke | |
| 140 os.remove(filename) | |
| 141 # create new rss file | |
| 142 rss = newRss( | |
| 143 "%s tracker" % (db.config.TRACKER_NAME,), | |
| 144 db.config.TRACKER_WEB, | |
| 145 "Recent changes to the %s Roundup issue tracker" % (db.config.TRACKER_NAME,) | |
| 146 ) | |
| 147 else: | |
| 148 raise | |
| 149 | |
| 150 channel = rss.documentElement.getElementsByTagName('channel')[0] | |
| 151 addEl = lambda parent,tag,value: parent.appendChild(rss.createElement(tag)).appendChild(rss.createTextNode(value)) | |
| 152 issuelink = '%sissue%s' % (db.config.TRACKER_WEB, nodeid) | |
| 153 | |
| 154 | |
| 155 if olddata: | |
| 156 chg = cl.generateChangeNote(nodeid, olddata) | |
| 157 else: | |
| 158 chg = cl.generateCreateNote(nodeid) | |
| 159 | |
| 160 def addItem(desc, date, userid): | |
| 161 """ | |
| 162 Adds an RSS item to the RSS document. The title, link, and comments | |
| 163 link are those of the current issue. | |
| 164 | |
| 165 desc: the description text to use | |
| 166 date: an appropriately formatted string for pubDate | |
| 167 userid: a Roundup user ID to use as author | |
| 168 """ | |
| 169 | |
| 170 item = rss.createElement('item') | |
| 171 | |
| 172 addEl(item, 'title', db.issue.get(nodeid, 'title')) | |
| 173 addEl(item, 'link', issuelink) | |
| 174 addEl(item, 'guid', issuelink + '#' + date.replace(' ','+')) | |
| 175 addEl(item, 'comments', issuelink) | |
| 176 addEl(item, 'description', desc.replace('&','&').replace('<','<').replace('\n', '<br>\n')) | |
| 177 addEl(item, 'pubDate', date) | |
| 178 addEl(item, 'author', | |
|
6327
0014af559224
do not include email address in rss feed. Username only.
John Rouillard <rouilj@ieee.org>
parents:
6308
diff
changeset
|
179 '%s' % ( |
| 6229 | 180 db.user.get(userid, 'username') |
| 181 ) | |
| 182 ) | |
| 183 | |
| 184 channel.appendChild(item) | |
| 185 | |
| 186 # add detectors directory to path if it's not there. | |
| 187 # FIXME - see if this pollutes the sys.path for other | |
| 188 # trackers. | |
| 189 detector_path="%s/detectors"%(db.config.TRACKER_HOME) | |
| 190 if ( sys.path.count(detector_path) == 0 ): | |
| 191 sys.path.insert(0,detector_path) | |
| 192 | |
| 193 from nosyreaction import determineNewMessages | |
| 194 for msgid in determineNewMessages(cl, nodeid, olddata): | |
| 195 logger.debug("Processing new message msg%s for issue%s", msgid, nodeid) | |
| 196 desc = db.msg.get(msgid, 'content') | |
| 197 | |
| 198 if desc and chg: | |
| 199 desc += chg | |
| 200 elif chg: | |
| 201 desc = chg | |
| 202 chg = None | |
| 203 | |
| 204 addItem(desc or '', db.msg.get(msgid, 'date').pretty(RSS20_DATE_FORMAT), db.msg.get(msgid, 'author')) | |
| 205 | |
| 206 if chg: | |
| 207 from time import strftime | |
| 208 addItem(chg.replace('\n----------\n', ''), strftime(RSS20_DATE_FORMAT), db.getuid()) | |
| 209 | |
| 210 | |
| 211 for c in channel.getElementsByTagName('item')[0:-MAX_ITEMS]: # leaves at most MAX_ITEMS at the end | |
| 212 channel.removeChild(c) | |
| 213 | |
| 214 # write the RSS | |
| 215 out = open(filename, 'w') | |
| 216 | |
| 217 try: | |
| 218 out.write(rss.toxml()) | |
| 219 except Exception as e: | |
| 220 # record the falure This should not happen. | |
| 221 logger.error(e) | |
| 222 out.close() # create 0 length file maybe?? But we handle above. | |
| 223 raise # let the user know something went wrong. | |
| 224 | |
| 225 out.close() | |
| 226 | |
| 227 | |
| 228 def init(db): | |
| 229 db.issue.react('create', writeRss) | |
| 230 db.issue.react('set', writeRss) | |
|
6308
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
231 #SHA: c4f916a13d533ff0c49386fc4f1f9f254adeb744 |
