def deliver(self, event): if event.identity in nomemos_cache: return memos = get_memos(event) if len(memos) > self.public_limit and event.public: if event.identity not in notified_overlimit_cache: public = [True for memo in memos if not memo.private] message = u'By the way, you have a pile of memos waiting for ' \ u'you, too many to read out in public. PM me' if public: event.addresponse(u'%s: ' + message, event.sender['nick']) else: event.addresponse(message, target=event.sender['connection']) notified_overlimit_cache.add(event.identity) return for memo in memos: # Don't deliver if the user just sent a memo to themself if 'memo' in event and event.memo == memo.id: continue if memo.private: message = u'By the way, %(sender)s on %(source)s told me ' \ u'"%(message)s" %(ago)s ago' % { 'sender': memo.sender.identity, 'source': memo.sender.source, 'message': memo.memo, 'ago': ago(event.time - memo.time), } event.addresponse(message, target=event.sender['connection']) else: event.addresponse(u'By the way, %(sender)s on %(source)s ' u'told me "%(message)s" %(ago)s ago', { 'sender': memo.sender.identity, 'source': memo.sender.source, 'message': memo.memo, 'ago': ago(event.time - memo.time), }) memo.delivered = True event.session.save_or_update(memo) event.session.commit() log.info(u"Delivered memo %s to %s (%s)", memo.id, event.identity, event.sender['connection']) if 'memo' not in event: nomemos_cache.add(event.identity)
def get(self, event, number): ticket = self.get_ticket(int(number)) if ticket: event.addresponse( u'Ticket %(id)s (%(status)s %(priority)s %(type)s in %(component)s for %(milestone)s) ' u'reported %(ago)s ago assigned to %(owner)s: "%(summary)s" %(url)sticket/%(id)s', { 'id': ticket.id, 'status': ticket.status, 'priority': ticket.priority, 'type': ticket.type, 'component': ticket.component, 'milestone': ticket.milestone, 'ago': ago(datetime.now() - datetime.fromtimestamp(ticket.time), 2), 'owner': ticket.owner, 'summary': ticket.summary, 'url': self.url, }) else: event.addresponse(u"No such ticket")
def log_revision(self, revision): if self.full: delta = self.branch.repository.get_revision_delta( revision.rev.revision_id) changes = [] if delta.added: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: changes.append('Modified: %s' % ', '.join([file[0] for file in delta.modified])) if delta.removed: changes.append('Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join([ '%s => %s' % (file[0], file[1]) for file in delta.renamed ])) timestamp = datetime.utcfromtimestamp(revision.rev.timestamp) commit = 'Commit %s by %s to %s on %s at %s: %s (%s)\n' % ( revision.revno, self.short_author( revision.rev), self.repository, format_date(timestamp, 'date'), format_date(timestamp, 'time'), revision.rev.message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision.revno, self.short_author( revision.rev), self.repository, ago( datetime.now() - datetime.fromtimestamp(revision.rev.timestamp), 2), revision.rev.get_summary().replace('\n', ' ')) self.to_file.write(commit)
def log_revision(self, revision): if self.full: delta = self.branch.repository.get_revision_delta(revision.rev.revision_id) changes = [] if delta.added: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: changes.append('Modified: %s' % ', '.join([file[0] for file in delta.modified])) if delta.removed: changes.append('Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join(['%s => %s' % (file[0], file[1]) for file in delta.renamed])) timestamp = datetime.utcfromtimestamp(revision.rev.timestamp) commit = 'Commit %s by %s to %s on %s at %s: %s (%s)\n' % ( revision.revno, self.short_author(revision.rev), self.repository, format_date(timestamp, 'date'), format_date(timestamp, 'time'), revision.rev.message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision.revno, self.short_author(revision.rev), self.repository, ago(datetime.now() - datetime.fromtimestamp(revision.rev.timestamp), 2), revision.rev.get_summary().replace('\n', ' ')) self.to_file.write(commit)
def listsongs(self, event, username): songs = feedparser.parse('http://ws.audioscrobbler.com/1.0/user/%s/recenttracks.rss?%s' % (username, time())) if songs['bozo']: event.addresponse(u'No such user') else: event.addresponse(u', '.join(u'%s (%s ago)' % ( e.title, ago(event.time - parse_timestamp(e.updated)) ) for e in songs['entries']))
def listsongs(self, event, username): songs = feedparser.parse( 'http://ws.audioscrobbler.com/1.0/user/%s/recenttracks.rss?%s' % (username, time())) if songs['bozo']: event.addresponse(u'No such user') else: event.addresponse(u', '.join( u'%s (%s ago)' % (e.title, ago(event.time - parse_timestamp(e.updated))) for e in songs['entries']))
def remote_latest(self, service, user): if service['api'] == 'twitter': # Twitter ommits retweets in the JSON and XML results: statuses = generic_webservice( '%sstatuses/user_timeline.rss' % service['endpoint'], { 'screen_name': user, 'count': 1 }) tree = ElementTree.fromstring(statuses) latest = tree.find('.//item') if latest is None: if tree.find('.//error'): log.info('Twitter user_latest returned: %s', tree.findtext('.//error')) raise self.NoTweetsException(user) return { 'text': latest.findtext('description').split(': ', 1)[1], 'ago': ago(datetime.utcnow() - parse_timestamp(latest.findtext('pubDate'))), 'url': latest.findtext('guid'), } elif service['api'] == 'laconica': statuses = json_webservice( '%sstatuses/user_timeline/%s.json' % (service['endpoint'], user.encode('utf-8')), {'count': 1}) if not statuses: raise self.NoTweetsException(user) latest = statuses[0] url = '%s/notice/%i' % (service['endpoint'].split( '/api/', 1)[0], latest['id']) return { 'text': decode_htmlentities(latest['text']), 'ago': ago(datetime.utcnow() - parse_timestamp(latest['created_at'])), 'url': url, }
def remote_latest(self, service, user): if service['api'] == 'twitter': # Twitter ommits retweets in the JSON and XML results: statuses = generic_webservice( '%sstatuses/user_timeline/%s.atom' % (service['endpoint'], user.encode('utf-8')), {'count': 1}) tree = ElementTree.fromstring(statuses) latest = tree.find('{http://www.w3.org/2005/Atom}entry') if latest is None: raise self.NoTweetsException(user) return { 'text': latest.findtext('{http://www.w3.org/2005/Atom}content').split( ': ', 1)[1], 'ago': ago(datetime.utcnow() - parse_timestamp( latest.findtext('{http://www.w3.org/2005/Atom}published')) ), 'url': [ x for x in latest.getiterator( '{http://www.w3.org/2005/Atom}link') if x.get('type') == 'text/html' ][0].get('href'), } elif service['api'] == 'laconica': statuses = json_webservice( '%sstatuses/user_timeline/%s.json' % (service['endpoint'], user.encode('utf-8')), {'count': 1}) if not statuses: raise self.NoTweetsException(user) latest = statuses[0] url = '%s/notice/%i' % (service['endpoint'].split( '/api/', 1)[0], latest['id']) return { 'text': decode_htmlentities(latest['text']), 'ago': ago(datetime.utcnow() - parse_timestamp(latest['created_at'])), 'url': url, }
def remote_latest(self, service, user): if service['api'] == 'twitter': # Twitter ommits retweets in the JSON and XML results: statuses = generic_webservice('%sstatuses/user_timeline.rss' % service['endpoint'], { 'screen_name': user, 'count': 1 }) tree = ElementTree.fromstring(statuses) latest = tree.find('.//item') if latest is None: if tree.find('.//error'): log.info('Twitter user_latest returned: %s', tree.findtext('.//error')) raise self.NoTweetsException(user) return { 'text': latest.findtext('description') .split(': ', 1)[1], 'ago': ago(datetime.utcnow() - parse_timestamp( latest.findtext('pubDate'))), 'url': latest.findtext('guid'), } elif service['api'] == 'laconica': statuses = json_webservice('%sstatuses/user_timeline/%s.json' % (service['endpoint'], user.encode('utf-8')), {'count': 1}) if not statuses: raise self.NoTweetsException(user) latest = statuses[0] url = '%s/notice/%i' % (service['endpoint'].split('/api/', 1)[0], latest['id']) return { 'text': decode_htmlentities(latest['text']), 'ago': ago(datetime.utcnow() - parse_timestamp(latest['created_at'])), 'url': url, }
def remote_latest(self, service, user): if service['api'] == 'twitter': # Twitter ommits retweets in the JSON and XML results: statuses = generic_webservice('%sstatuses/user_timeline/%s.atom' % (service['endpoint'], user.encode('utf-8')), {'count': 1}) tree = ElementTree.fromstring(statuses) latest = tree.find('{http://www.w3.org/2005/Atom}entry') if latest is None: raise self.NoTweetsException(user) return { 'text': latest.findtext('{http://www.w3.org/2005/Atom}content') .split(': ', 1)[1], 'ago': ago(datetime.utcnow() - parse_timestamp( latest.findtext('{http://www.w3.org/2005/Atom}published'))), 'url': [x for x in latest.getiterator('{http://www.w3.org/2005/Atom}link') if x.get('type') == 'text/html' ][0].get('href'), } elif service['api'] == 'laconica': statuses = json_webservice('%sstatuses/user_timeline/%s.json' % (service['endpoint'], user.encode('utf-8')), {'count': 1}) if not statuses: raise self.NoTweetsException(user) latest = statuses[0] url = '%s/notice/%i' % (service['endpoint'].split('/api/', 1)[0], latest['id']) return { 'text': decode_htmlentities(latest['text']), 'ago': ago(datetime.utcnow() - parse_timestamp(latest['created_at'])), 'url': url, }
def deliver(self, event): if event.identity in nomemos_cache: return memos = get_memos(event) if len(memos) > self.public_limit and event.public: if event.identity not in notified_overlimit_cache: public = [True for memo in memos if not memo.private] message = u'By the way, you have a pile of memos waiting for ' \ u'you, too many to read out in public. PM me' if public: event.addresponse(message) else: event.addresponse(message, target=event.sender['connection'], address=False) notified_overlimit_cache.add(event.identity) return for memo in memos: # Don't deliver if the user just sent a memo to themself if 'memo' in event and event.memo == memo.id: continue message = u'By the way, %(sender)s on %(source)s told me ' \ u'"%(message)s" %(ago)s ago' % { 'sender': memo.sender.identity, 'source': memo.sender.source, 'message': memo.memo, 'ago': ago(event.time - memo.time), } if memo.private: event.addresponse(message, target=event.sender['connection'], address=False) else: event.addresponse(message) memo.delivered = True event.session.add(memo) event.session.commit() log.info(u"Delivered memo %s to %s (%s)", memo.id, event.identity, event.sender['connection']) if 'memo' not in event: nomemos_cache.add(event.identity)
def get(self, event, number): ticket = self.get_ticket(int(number)) if ticket: event.addresponse(u'Ticket %(id)s (%(status)s %(priority)s %(type)s in %(component)s for %(milestone)s) ' u'reported %(ago)s ago assigned to %(owner)s: "%(summary)s" %(url)sticket/%(id)s', { 'id': ticket.id, 'status': ticket.status, 'priority': ticket.priority, 'type': ticket.type, 'component': ticket.component, 'milestone': ticket.milestone, 'ago': ago(datetime.now() - datetime.fromtimestamp(ticket.time), 2), 'owner': ticket.owner, 'summary': ticket.summary, 'url': self.url, }) else: event.addresponse(u"No such ticket")
def announce(self, event, who, what, from_who, from_when): """This handler gets called after the timeout and will notify the user.""" # we keep this logic here to simplify the code on the other side if who == from_who: from_who = "You" if event.public: who += ": " else: who = "" if what: what = "remind you " + what else: what = "ping you" event.addresponse(u'%(who)s%(from_who)s asked me to %(what)s, %(ago)s ago.', { 'who': who, 'from_who': from_who, 'what': what, 'ago': ago(datetime.now()-from_when) })
def handler(self, event, who, source): account = None identity = event.session.query(Identity) \ .filter_by(source=(source or event.source), identity=who) \ .first() if identity and identity.account and not source: account = identity.account if not identity and not source: account = event.session.query(Account).filter_by(username=who) \ .first() if not identity and not account: event.addresponse(u"I don't know who %s is", who) return messages = [] states = [] if account: for identity in account.identities: for sighting in event.session.query(Sighting) \ .filter_by(identity_id=identity.id).all(): if sighting.type == 'message': messages.append(sighting) else: states.append(sighting) else: for sighting in event.session.query(Sighting) \ .filter_by(identity_id=identity.id).all(): if sighting.type == 'message': messages.append(sighting) else: states.append(sighting) if len(messages) == 0 and len(states) == 0: event.addresponse(u"I haven't seen %s", who) return messages.sort(key=lambda x: x.time, reverse=True) states.sort(key=lambda x: x.time, reverse=True) reply = u'' if len(messages) > 0: sighting = messages[0] delta = event.time - sighting.time reply = u'%s was last seen %s ago in %s on %s [%s]' %( who, ago(delta), sighting.channel or 'private', sighting.identity.source, format_date(sighting.time)) if len(states) > 0: sighting = states[0] if reply: reply += u', and' else: reply = who reply += u' has been %s on %s since %s' % ( sighting.value, sighting.identity.source, format_date(sighting.time)) event.addresponse(reply)
def remind(self, event, who, at, when, how, what): """This is the main handler that gets called on the above @match. This parses the date and sets up the "announce" function to be fired when the time is up.""" try: time = parser.parse(when) except: event.addresponse( u"Sorry, I couldn't understand the time you gave me") return now = datetime.now() if at == "in": midnight = now.replace(now.year, now.month, now.day, 0, 0, 0, 0) delta = time - midnight elif at in ("at", "on"): delta = time - now if what: what = how + " " + what.strip() if not who or who == "me": who = event.sender['nick'] elif not event.public: event.addresponse( u"It's just you and me in here. Tell me in " u"the channel where you want me to send the reminder.") return # this is total_seconds() in 2.7, it can be replaced when we require that version or above total_seconds = ( delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 if total_seconds < -24 * 60 * 60: event.addresponse( u"I can't travel in time back to %(ago)s ago " u"(yet)", {'ago': ago(-delta)}) return elif total_seconds < 0: delta += timedelta(days=1) total_seconds = ( delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 ibid.dispatcher.call_later(total_seconds, self.announce, event, who, what, event.sender['nick'], now) # this logic needs to be after the callback setting because we # want to ping the real nick, not "you" if who == event.sender['nick']: who = "you" # we say "ping" here to let the user learn about "ping" instead # of "remind" if what: action = 'remind' else: action = 'ping' if delta: time = " in " + ago(delta) else: time = "" event.addresponse(u"Okay, I will %(action)s %(who)s%(time)s", { 'action': action, 'who': who, 'time': time, })
def remind(self, event, who, at, when, how, what): """This is the main handler that gets called on the above @match. This parses the date and sets up the "announce" function to be fired when the time is up.""" try: time = parser.parse(when) except: event.addresponse(u"Sorry, I couldn't understand the time you gave me") return now = datetime.now() if at == "in": midnight = now.replace(now.year, now.month, now.day, 0, 0, 0, 0) delta = time - midnight elif at in ("at", "on"): delta = time - now if what: what = how + " " + what.strip() if not who or who == "me": who = event.sender['nick'] elif not event.public: event.addresponse(u"It's just you and me in here. Tell me in " u"the channel where you want me to send the reminder.") return # this is total_seconds() in 2.7, it can be replaced when we require that version or above total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 if total_seconds < -24*60*60: event.addresponse(u"I can't travel in time back to %(ago)s ago " u"(yet)", {'ago': ago(-delta)}) return elif total_seconds < 0: delta += timedelta(days=1) total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 ibid.dispatcher.call_later(total_seconds, self.announce, event, who, what, event.sender['nick'], now) # this logic needs to be after the callback setting because we # want to ping the real nick, not "you" if who == event.sender['nick']: who = "you" # we say "ping" here to let the user learn about "ping" instead # of "remind" if what: action = 'remind' else: action = 'ping' if delta: time = " in " + ago(delta) else: time = "" event.addresponse(u"Okay, I will %(action)s %(who)s%(time)s", { 'action': action, 'who': who, 'time': time, })
def format_log_message(self, log_message, full=False): """ author - string - the name of the author who committed the revision date - float time - the date of the commit message - string - the text of the log message for the commit revision - pysvn.Revision - the revision of the commit changed_paths - list of dictionaries. Each dictionary contains: path - string - the path in the repository action - string copyfrom_path - string - if copied, the original path, else None copyfrom_revision - pysvn.Revision - if copied, the revision of the original, else None """ revision_number = log_message['revision'].number author = log_message['author'] commit_message = log_message['message'] timestamp = log_message['date'] if full: pathinfo, delta = self._generate_delta(log_message['changed_paths']) changes = [] if delta.added: if self.multiline: changes.append('Added:\n\t%s' % '\n\t'.join([file[0] for file in delta.added])) else: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: if self.multiline: changes.append('Modified:\n\t%s' % '\n\t'.join([file[0] for file in delta.modified])) else: changes.append('Modified: %s' % '\, '.join([file[0] for file in delta.modified])) if delta.removed: if self.multiline: changes.append('Removed:\n\t%s' % '\n\t'.join([file[0] for file in delta.removed])) else: changes.append('Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join(['%s => %s' % (file[0], file[1]) for file in delta.renamed])) timestamp_dt = datetime.utcfromtimestamp(timestamp) if self.multiline: commit = 'Commit %s by %s to %s%s on %s at %s:\n\n\t%s \n\n%s\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), u'\n'.join(textwrap.wrap(commit_message, initial_indent=" ", subsequent_indent=" ")), '\n\n'.join(changes)) else: commit = 'Commit %s by %s to %s%s on %s at %s: %s (%s)\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), commit_message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision_number, author, self.repository, ago(datetime.now() - datetime.fromtimestamp(timestamp), 2), commit_message.replace('\n', ' ')) return commit
def format_log_message(self, log_message, full=False): """ author - string - the name of the author who committed the revision date - float time - the date of the commit message - string - the text of the log message for the commit revision - pysvn.Revision - the revision of the commit changed_paths - list of dictionaries. Each dictionary contains: path - string - the path in the repository action - string copyfrom_path - string - if copied, the original path, else None copyfrom_revision - pysvn.Revision - if copied, the revision of the original, else None """ revision_number = log_message['revision'].number author = log_message['author'] commit_message = log_message['message'] timestamp = log_message['date'] if full: pathinfo, delta = self._generate_delta( log_message['changed_paths']) changes = [] if delta.added: if self.multiline: changes.append( 'Added:\n\t%s' % '\n\t'.join([file[0] for file in delta.added])) else: changes.append('Added: %s' % ', '.join([file[0] for file in delta.added])) if delta.modified: if self.multiline: changes.append( 'Modified:\n\t%s' % '\n\t'.join([file[0] for file in delta.modified])) else: changes.append( 'Modified: %s' % '\, '.join([file[0] for file in delta.modified])) if delta.removed: if self.multiline: changes.append( 'Removed:\n\t%s' % '\n\t'.join([file[0] for file in delta.removed])) else: changes.append( 'Removed: %s' % ', '.join([file[0] for file in delta.removed])) if delta.renamed: changes.append('Renamed: %s' % ', '.join([ '%s => %s' % (file[0], file[1]) for file in delta.renamed ])) timestamp_dt = datetime.utcfromtimestamp(timestamp) if self.multiline: commit = 'Commit %s by %s to %s%s on %s at %s:\n\n\t%s \n\n%s\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), u'\n'.join( textwrap.wrap( commit_message, initial_indent=" ", subsequent_indent=" ")), '\n\n'.join(changes)) else: commit = 'Commit %s by %s to %s%s on %s at %s: %s (%s)\n' % ( revision_number, author, self.repository, pathinfo, format_date(timestamp_dt, 'date'), format_date(timestamp_dt, 'time'), commit_message.replace('\n', ' '), '; '.join(changes)) else: commit = 'Commit %s by %s to %s %s ago: %s\n' % ( revision_number, author, self.repository, ago(datetime.now() - datetime.fromtimestamp(timestamp), 2), commit_message.replace('\n', ' ')) return commit