def twitter_context(arg): import json import urllib from util import rfc3339 import datetime import twitter from twitter import format_tweet if "arg" not in arg["qs"] and arg["oauth"] == False: err(noarg) _default(arg, "oauth", False) _default(arg, "token_name", None) _default(arg, "infinite_retries", True) _default(arg, "source_filter", False) p = twitter.Twitter(db=arg["cursor"], oauth=arg["oauth"], token_name=arg["token_name"], infinite_retries=arg["infinite_retries"]) if "mentions" in arg and arg["mentions"] == True: tweets = p.mentions() uname = p.me().screen_name else: uname = arg["qs"]["arg"] tweets = p.user_timeline(uname) tweet_cache = {} for tweet in tweets: tweet_cache[tweet.id] = tweet rval = {"id": "http://twitter.com/%s#atom_maker_context_feed" % uname, "link": "http://twitter.com/%s" % uname, "title": "Twitter / %s / context" % uname, "author": tweets[0].user.name, "entries": []} if 'lang' in arg["qs"]: rval["lang"] = arg["qs"]['lang'] parent_skip_list = set() for tweet in tweets: if tweet.id in parent_skip_list: continue if arg["source_filter"] and tweet.source in arg["source_filter"]: continue content = [] tweet_url = "http://twitter.com/%s/status/%s" % (tweet.user.screen_name, tweet.id_str) entry = {"id": tweet_url, "title": "%s: " % tweet.user.screen_name + tweet.text, "content_type": "html", "updated": rfc3339(tweet.created_at), "link": tweet_url} content.append(format_tweet(tweet.user.screen_name, tweet.user.name, tweet.text, tweet_url, tweet.created_at)) parent_id = tweet.in_reply_to_status_id while parent_id: if parent_id in tweet_cache: parent_tweet = tweet_cache[parent_id] else: try: parent_tweet = p.get_tweet(parent_id) except: break tweet_cache[parent_id] = parent_tweet # don't make a new RSS entry for tweets in a conversation chain if parent_tweet.user.id == tweet.user.id: parent_skip_list.add(parent_tweet.id) content.append(format_tweet(parent_tweet.user.screen_name, parent_tweet.user.name, parent_tweet.text, "http://twitter.com/%s/status/%s" % (parent_tweet.user.screen_name, parent_id), parent_tweet.created_at)) # continue to next parent or terminate parent_id = parent_tweet.in_reply_to_status_id entry["content"] = "".join(reversed(content)) rval["entries"].append(entry) rval["updated"] = rval["entries"][0]["updated"] # first tweet is newest return rval
def create_atom(feed): """Validates the generator output and creates the ATOM feed""" root = etree.Element("feed", attrib={"xmlns": "http://www.w3.org/2005/Atom"}) esc = cgi.escape ts = rfc3339(now) if not isinstance(feed, dict): err("Your generator forgot to return a dict.") if not "title" in feed: err("The feed lacks a title.") if not "id" in feed: err("The feed lacks a UUID.") if not "updated" in feed: feed["updated"] = ts if not "entries" in feed: err("The feed lacks entries.") if 'lang' in feed: root.set(etree.QName("{http://www.w3.org/XML/1998/namespace}lang"), feed["lang"]) child_tag(root, "title", text=feed["title"]) child_tag(root, "id", text=feed["id"]) child_tag(root, "updated", text=feed["updated"]) if "author" in feed: author = child_tag(root, "author") child_tag(author, "name", text=feed["author"]) if "author_uri" in feed: child_tag(author, "uri", feed["author_uri"]) if "subtitle" in feed: child_tag(root, "subtitle", text=feed["subtitle"]) if "link" in feed: child_tag(root, "link", attrib={'href': feed["link"]}) child_tag(root, "generator", attrib={"uri": "https://github.com/dgilman/atom_maker", "version": str(VERSION)}, text="atom_maker") child_tag(root, "link", attrib={"rel": "self", "href": self_url()}) #validate individual entries. check_for_authors = False if not "author" in feed: check_for_authors = True for entry in feed["entries"]: if check_for_authors and not "author" in entry: err("One of the feed entries lacks an author. If there is no global author set each feed needs its own author.") if not "id" in entry: err("An entry lacks a UUID.") if not "title" in entry: err("An entry lacks a title.") if not "content" in entry: err("An entry lacks content.") if not "content_type" in entry: err("All entries need a content_type.") if entry["content_type"] not in ["html", "text", "xhtml"]: err("content_type must be one of html, text, or html.") if not "updated" in entry: entry["updated"] = ts e = child_tag(root, "entry") if "lang" in entry: e.set(etree.QName("{http://www.w3.org/XML/1998/namespace}lang"), feed["lang"]) child_tag(e, "id", text=entry["id"]) child_tag(e, "title", text=entry["title"]) child_tag(e, "content", attrib={"type": entry["content_type"]}, text=entry["content"]) child_tag(e, "updated", text=entry["updated"]) if "author" in entry: author = child_tag(e, "author") child_tag(author, "name", text=entry["author"]) if "author_uri" in entry: child_tag(author, "uri", text=entry["author_uri"]) if "published" in entry: child_tag(e, "published", text=entry["published"]) if "link" in entry: child_tag(e, "link", attrib={"href": entry["link"]}) rval = cStringIO.StringIO() tree = etree.ElementTree(element=root) if sys.version_info < (2, 7): tree.write(rval, encoding="UTF-8") else: tree.write(rval, encoding="UTF-8", xml_declaration=True) return rval.getvalue()
def _bz_xmlrpc(arg): """arg: bug id as string url: path to bugzilla installation history: put history changes in feed (optional, default true) ccs: include cc changes in history (optional, default false)""" import xmlrpclib import sqlite3 import datetime import re now = datetime.datetime.utcnow() from util import rfc3339 from util import warn_old if "arg" not in arg["qs"]: err(noarg) try: int(arg['qs']['arg']) except: err("Bug IDs must be numerical.") if not "history" in arg["qs"]: # the default history = True else: if arg["qs"]["history"][0] in "Ff0": history = False else: history = True if not "ccs" in arg["qs"]: ccs = False else: if arg["qs"]["ccs"][0] in "Ff0": ccs = False else: ccs = True _default(arg, 'warn_old', True) url = arg["url"] bugid = arg["qs"]["arg"] p = xmlrpclib.ServerProxy(url + "/xmlrpc.cgi", use_datetime=True) try: bugdata = p.Bug.get({"ids":[bugid], "permissive": True}) except: err(badfetch) if len(bugdata['faults']) > 0: err(bugdata['faults'][0]['faultString']) bugdata = bugdata["bugs"][0] guid = '%s/show_bug.cgi?id=%s' % (url, str(bugdata['id'])) # get the ID in case the query string used the bug alias rval = {"id": guid, "link": guid, "updated": rfc3339(bugdata['last_change_time']), "title": "Bug %s - " % bugid + bugdata['summary'], "entries": []} if "lang" in arg["qs"]: rval["lang"] = arg["qs"]["lang"] try: bugcomments = p.Bug.comments({"ids":[bugid]})["bugs"][bugid]['comments'] except: err(badfetch) commenting_users = [x['author'] for x in bugcomments] if history: try: bug_history = p.Bug.history({"ids":[bugid]})['bugs'][0]['history'] except: err(badfetch) commenting_users.extend([h['who'] for h in bug_history]) c = arg["cursor"] c.executescript("""pragma temp_store = MEMORY; create temp table email_queries (email text unique);""") c.execute("insert or ignore into bugzillas (id, url) values (NULL, ?)", (url,)) bz_id = c.execute("select id from bugzillas where url = ?", (url,)).fetchall()[0][0] c.execute("delete from bugzilla_users where ts <= ?", (now.year*100 + now.month - 1,)) c.executemany("insert or ignore into email_queries (email) values (?)", ((e,) for e in commenting_users)) cache_misses = c.execute("select email from email_queries where not exists (select 1 from bugzilla_users where bugzilla_users.bz = ? and bugzilla_users.email = email_queries.email)", (bz_id,)).fetchall() if len(cache_misses) > 0: try: real_names = p.User.get({"names": [e[0] for e in cache_misses]})["users"] except: err(badfetch) for user in real_names: if len(user['real_name']) != 0: rn = user['real_name'] else: rn = user['name'] c.execute("insert into bugzilla_users (email, name, ts, bz) values (?, ?, ?, ?)", (user['name'], rn, now.year*100 + now.month, bz_id)) rn = lambda x: c.execute("select name from bugzilla_users where bz = ? and email = ?", (bz_id, x)).fetchall()[0][0] if history: for bug_history_change_no, bug_history_change in enumerate(bug_history): # don't even create an rss entry if cc is the only thing that's changed and we're ignoring ccs if len(bug_history_change['changes']) == 1 and bug_history_change['changes'][0]['field_name'] == 'cc' and ccs == False: continue history_id = guid + "#h" + str(bug_history_change_no) content = ['<pre style="white-space:pre-wrap">'] for field_change in bug_history_change['changes']: if field_change['field_name'] == 'cc' and ccs == False: continue content.append("Field <b>%s</b>:\n" % field_change['field_name']) if field_change['field_name'] == 'attachments.isobsolete': content.append('<a href="%s/attachment.cgi?id=%d">Attachment #%d</a> is obsolete\n' % (url, field_change['attachment_id'], field_change['attachment_id'])) if field_change['field_name'] in ['dependson', 'blocked']: sub = lambda f: re.sub("(\d+)", lambda m: '<a href="%s/show_bug.cgi?id=%s">%s</a>' % (url, m.group(1), "Bug " + m.group(1)), f) if 'added' in field_change: field_change['added'] = sub(field_change['added']) if 'removed' in field_change: field_change['removed'] = sub(field_change['removed']) content.append("Removed:\n") content.append(" %s\n" % field_change['removed']) content.append("Added:\n") content.append(" %s\n\n" % field_change['added']) content.append("</pre>") real_name = rn(bug_history_change['who']) when = rfc3339(bug_history_change['when']) entry = {"id": history_id, "title": "%s changed at %s" % (real_name, when), "author": real_name, "updated": when, "published": bug_history_change['when'], # keep for sorting "link": history_id, "content": "".join(content), "content_type": "html"} rval["entries"].append(entry) linkbugs = lambda x: re.sub("([Bb])ug (\d+)", lambda m: '<a href="%s/show_bug.cgi?id=%s">%s</a>' % (url, m.group(2), m.group(1) + "ug " + m.group(2)), x) for comment_no, comment in enumerate(bugcomments): comment_id = guid + "#c" + str(comment_no) real_name = rn(comment['author']) comment_time_str = rfc3339(comment['time']) entry = {"id": comment_id, "title": u"Comment %s - %s - %s" % (str(comment_no), real_name, comment_time_str), "content": '<pre style="white-space:pre-wrap">' + linkbugs(comment['text']) + "</pre>", "content_type": "html", "author": real_name, "updated": comment_time_str, "published": comment['time'], # keep for sorting "link": comment_id} rval["entries"].append(entry) rval["entries"].sort(key=lambda e: e["published"]) for entry in rval["entries"]: entry["published"] = rfc3339(entry["published"]) if arg["warn_old"] and bugdata['last_change_time'] < (now - datetime.timedelta(days=365)): rval["entries"].append(warn_old(guid, bugid)) return rval