Mercurial > p > roundup > code
annotate website/issues/detectors/rsswriter.py @ 6628:2bb6d7baa47d
"Comment" out the meta data - will not process under 1.7.5 sphinx
Apparently field names with : fail on 1.7.5 sphinx which is the
virtual env version on sourceforge. It works on my 1.6.7 python2
install.
Looks like I need to add sphinxext-opengraph to get this to work.
However that is python3 only so need to spin up new virtualenv etc.
Looks like no python3 on sourceforge which may be an issue.
On sourceforge in /home/project-web/roundup/src/docbuilder these
packages are used and must be scp'ed as pip has no network access
outside of sourceforge:
Babel-2.6.0-py2.py3-none-any.whl
Jinja2-2.10-py2.py3-none-any.whl
MarkupSafe-1.0.tar.gz
Pygments-2.2.0-py2.py3-none-any.whl
Sphinx-1.7.5
Sphinx-1.7.5-py2.py3-none-any.whl
Sphinx-1.7.5.tar.gz
alabaster-0.7.11-py2.py3-none-any.whl
certifi-2018.4.16-py2.py3-none-any.whl
chardet-3.0.4-py2.py3-none-any.whl
docutils-0.14-py2-none-any.whl
idna-2.7-py2.py3-none-any.whl
imagesize-1.0.0-py2.py3-none-any.whl
packaging-17.1-py2.py3-none-any.whl
pip-10.0.1
pip-10.0.1.tar.gz
pyparsing-2.2.0-py2.py3-none-any.whl
pytz-2018.5-py2.py3-none-any.whl
requests-2.19.1-py2.py3-none-any.whl
setuptools-39.2.0-py2.py3-none-any.whl
six-1.11.0-py2.py3-none-any.whl
snowballstemmer-1.2.1-py2.py3-none-any.whl
sphinxcontrib_websupport-1.1.0-py2.py3-none-any.whl
typing-3.6.4-py2-none-any.whl
urllib3-1.23-py2.py3-none-any.whl
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 27 Mar 2022 13:57:04 -0400 |
| parents | bed1313898d4 |
| children |
| 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. | |
|
6465
bed1313898d4
Force time format to include offset, use dc:creator not author
John Rouillard <rouilj@ieee.org>
parents:
6327
diff
changeset
|
66 RSS20_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S +0000' |
| 6229 | 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") | |
|
6465
bed1313898d4
Force time format to include offset, use dc:creator not author
John Rouillard <rouilj@ieee.org>
parents:
6327
diff
changeset
|
77 root.setAttribute("xmlns:dc","http://purl.org/dc/elements/1.1/") |
| 6229 | 78 |
| 79 channel = root.appendChild(rss.createElement("channel")) | |
| 80 addEl = lambda tag,value: channel.appendChild(rss.createElement(tag)).appendChild(rss.createTextNode(value)) | |
| 81 def addElA(tag,attr): | |
| 82 node=rss.createElement(tag) | |
| 83 for attr, val in attr.items(): | |
| 84 node.setAttribute(attr, val) | |
| 85 channel.appendChild(node) | |
| 86 | |
| 87 addEl("title", title) | |
| 88 addElA('atom:link', attr={"rel": "self", | |
| 89 "type": "application/rss+xml", "href": link + "@@file/rss.xml"}) | |
| 90 addEl("link", link) | |
| 91 addEl("description", description) | |
| 92 | |
| 93 return rss # has no items | |
| 94 | |
| 95 | |
| 96 def writeRss(db, cl, nodeid, olddata): | |
| 97 """ | |
| 98 Reacts to a created or changed issue. Puts new messages and the change note | |
| 99 in items in the RSS feed, as determined by the rsswriter.py FILENAME setting. | |
| 100 If no RSS feed exists where FILENAME specifies, a new feed is created with | |
| 101 rsswriter.newRss. | |
| 102 """ | |
| 103 | |
| 104 # The filename of a tracker's RSS feed. Tracker config variables | |
| 105 # are placed with the standard '%' operator syntax. | |
| 106 | |
| 107 FILENAME = "%s/rss.xml"%db.config['TEMPLATES'] | |
| 108 | |
| 109 # i.e., roundup.cgi/projects/_file/rss.xml | |
| 110 # FILENAME = "/home/markpasc/public_html/%(TRACKER_NAME)s.xml" | |
| 111 | |
| 112 filename = FILENAME % db.config.__dict__ | |
| 113 | |
| 114 # 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
|
115 # 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
|
116 ##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
|
117 ## if __debug__: |
|
c34171b2af43
Fix rss generator. No private atribute in issues in this tracker.
John Rouillard <rouilj@ieee.org>
parents:
6229
diff
changeset
|
118 ## 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
|
119 ## return |
| 6229 | 120 |
| 121 if __debug__: | |
| 122 logger.debug("rss: generating rss for issue %s", nodeid) | |
| 123 | |
| 124 # open the RSS | |
| 125 import xml.dom.minidom | |
| 126 from xml.parsers.expat import ExpatError | |
| 127 | |
| 128 try: | |
| 129 rss = xml.dom.minidom.parse(filename) | |
| 130 except IOError as e: | |
| 131 if 2 != e.errno: raise | |
| 132 # File not found | |
| 133 rss = newRss( | |
| 134 "%s tracker" % (db.config.TRACKER_NAME,), | |
| 135 db.config.TRACKER_WEB, | |
| 136 "Recent changes to the %s Roundup issue tracker" % (db.config.TRACKER_NAME,) | |
| 137 ) | |
| 138 except ExpatError as e: | |
| 139 if os.path.getsize(filename) == 0: | |
| 140 # delete the file, it's broke | |
| 141 os.remove(filename) | |
| 142 # create new rss file | |
| 143 rss = newRss( | |
| 144 "%s tracker" % (db.config.TRACKER_NAME,), | |
| 145 db.config.TRACKER_WEB, | |
| 146 "Recent changes to the %s Roundup issue tracker" % (db.config.TRACKER_NAME,) | |
| 147 ) | |
| 148 else: | |
| 149 raise | |
| 150 | |
| 151 channel = rss.documentElement.getElementsByTagName('channel')[0] | |
| 152 addEl = lambda parent,tag,value: parent.appendChild(rss.createElement(tag)).appendChild(rss.createTextNode(value)) | |
| 153 issuelink = '%sissue%s' % (db.config.TRACKER_WEB, nodeid) | |
| 154 | |
| 155 | |
| 156 if olddata: | |
| 157 chg = cl.generateChangeNote(nodeid, olddata) | |
| 158 else: | |
| 159 chg = cl.generateCreateNote(nodeid) | |
| 160 | |
| 161 def addItem(desc, date, userid): | |
| 162 """ | |
| 163 Adds an RSS item to the RSS document. The title, link, and comments | |
| 164 link are those of the current issue. | |
| 165 | |
| 166 desc: the description text to use | |
| 167 date: an appropriately formatted string for pubDate | |
| 168 userid: a Roundup user ID to use as author | |
| 169 """ | |
| 170 | |
| 171 item = rss.createElement('item') | |
| 172 | |
| 173 addEl(item, 'title', db.issue.get(nodeid, 'title')) | |
| 174 addEl(item, 'link', issuelink) | |
| 175 addEl(item, 'guid', issuelink + '#' + date.replace(' ','+')) | |
| 176 addEl(item, 'comments', issuelink) | |
| 177 addEl(item, 'description', desc.replace('&','&').replace('<','<').replace('\n', '<br>\n')) | |
| 178 addEl(item, 'pubDate', date) | |
|
6465
bed1313898d4
Force time format to include offset, use dc:creator not author
John Rouillard <rouilj@ieee.org>
parents:
6327
diff
changeset
|
179 # use dc:creator as username is not valid email address and |
|
bed1313898d4
Force time format to include offset, use dc:creator not author
John Rouillard <rouilj@ieee.org>
parents:
6327
diff
changeset
|
180 # author element must be valid email address |
|
bed1313898d4
Force time format to include offset, use dc:creator not author
John Rouillard <rouilj@ieee.org>
parents:
6327
diff
changeset
|
181 # addEl(item, 'author', |
|
bed1313898d4
Force time format to include offset, use dc:creator not author
John Rouillard <rouilj@ieee.org>
parents:
6327
diff
changeset
|
182 addEl(item, 'dc:creator', |
|
6327
0014af559224
do not include email address in rss feed. Username only.
John Rouillard <rouilj@ieee.org>
parents:
6308
diff
changeset
|
183 '%s' % ( |
| 6229 | 184 db.user.get(userid, 'username') |
| 185 ) | |
| 186 ) | |
| 187 | |
| 188 channel.appendChild(item) | |
| 189 | |
| 190 # add detectors directory to path if it's not there. | |
| 191 # FIXME - see if this pollutes the sys.path for other | |
| 192 # trackers. | |
| 193 detector_path="%s/detectors"%(db.config.TRACKER_HOME) | |
| 194 if ( sys.path.count(detector_path) == 0 ): | |
| 195 sys.path.insert(0,detector_path) | |
| 196 | |
| 197 from nosyreaction import determineNewMessages | |
| 198 for msgid in determineNewMessages(cl, nodeid, olddata): | |
| 199 logger.debug("Processing new message msg%s for issue%s", msgid, nodeid) | |
| 200 desc = db.msg.get(msgid, 'content') | |
| 201 | |
| 202 if desc and chg: | |
| 203 desc += chg | |
| 204 elif chg: | |
| 205 desc = chg | |
| 206 chg = None | |
| 207 | |
| 208 addItem(desc or '', db.msg.get(msgid, 'date').pretty(RSS20_DATE_FORMAT), db.msg.get(msgid, 'author')) | |
| 209 | |
| 210 if chg: | |
| 211 from time import strftime | |
| 212 addItem(chg.replace('\n----------\n', ''), strftime(RSS20_DATE_FORMAT), db.getuid()) | |
| 213 | |
| 214 | |
| 215 for c in channel.getElementsByTagName('item')[0:-MAX_ITEMS]: # leaves at most MAX_ITEMS at the end | |
| 216 channel.removeChild(c) | |
| 217 | |
| 218 # write the RSS | |
| 219 out = open(filename, 'w') | |
| 220 | |
| 221 try: | |
| 222 out.write(rss.toxml()) | |
| 223 except Exception as e: | |
| 224 # record the falure This should not happen. | |
| 225 logger.error(e) | |
| 226 out.close() # create 0 length file maybe?? But we handle above. | |
| 227 raise # let the user know something went wrong. | |
| 228 | |
| 229 out.close() | |
| 230 | |
| 231 | |
| 232 def init(db): | |
| 233 db.issue.react('create', writeRss) | |
| 234 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
|
235 #SHA: c4f916a13d533ff0c49386fc4f1f9f254adeb744 |
