def publish(self, post): """Push a Post to every publisher. :return: a list of Publications. """ if post.publish_at and post.publish_at > _now(): # This should never happen; the method should not have been # called. self.log.warn( "Not publishing %s until %s", post.content, post.publish_at.strftime(self.TIME_FORMAT) ) return [] publications = [] for publisher in self.publishers: publication, is_new = self.make_publication( publisher, post ) if not is_new and not publication.error: # There was a previous, successful attempt to publish # this Post. Skip this Publisher. continue try: self.post_to_publisher(publisher, post, publication) except Exception, e: message = repr(e.message) publication.report_failure("Uncaught exception: %s" % e.message) publications.append(publication)
def setup(self): super(TestBotModel, self).setup() self.now = _now() self.bot = self._botmodel() self.the_past = self.now - datetime.timedelta(days=1) self.the_future = self.now + datetime.timedelta(days=1)
def schedule_next_post(self, just_published=[]): """Assuming that a post was just published, set the time at which the next post should be published. """ how_long = self._next_scheduled_post(just_published) if how_long: self.model.next_post_time = _now() + how_long
def state_needs_update(self): """Does this bot's internal state need to be updated?""" if self.state_update_schedule is None: # This bot doesn't update state on a schedule. return False now = _now() update_at = now + datetime.timedelta( minutes=self.state_update_schedule ) last_update = self.model.last_state_update_time return not last_update or now > update_at
def process_bot(self, bot_model): implementation = bot_model.implementation if self.args.force: bot_model.next_post_time = _now() posts = implementation.publishable_posts if self.args.dry_run: print bot_model.name for post in posts: print post.content print "-" * 80 return # We're doing this for real. for post in posts: for publication in implementation.publish(post): publication.post.bot.log.info(publication.display()) self.config._db.commit()
def process_bot(self, bot_model): now = _now() recent = bot_model.recent_posts().limit(1).all() if not recent: bot_model.log.info("Has never posted.") else: [recent] = recent bot_model.log.info("Most recent post: %s" % recent.content) for publication in recent.publications: if publication.error: bot_model.log.info( "%s ERROR: %s" % (publication.service, publication.error)) else: bot_model.log.info("%s posted %dm ago (%s)" % ( publication.service, (now - publication.most_recent_attempt).total_seconds() / 60, publication.most_recent_attempt, )) def announce_list(count, content, what): if count == 1: item = "post" else: item = "posts" bot_model.log.info("%d %s %s" % (count, item, what)) bot_model.log.info("Next up: %s" % content) # Announce scheduled posts. scheduled = bot_model.scheduled next_post_time = bot_model.next_post_time if len(scheduled) > 0: first = scheduled[0] announce_list(len(scheduled), first.content, "scheduled") next_post_time = first.publish_at or bot_model.next_post_time # Announce backlog posts. try: backlog = bot_model.backlog if backlog: first = backlog[0] announce_list(len(backlog), first, "in backlog") except ValueError, e: pass
def new_post(self): """Scrape the site and get a number of new Posts out of it.""" response = self.make_request() if response.status_code == 304: # Not Modified return utcnow = datetime.datetime.utcnow() now = _now() new_last_update_time = None posts = [] for post in self.scrape(response): if not isinstance(post, Post): post, ignore = Post.from_content( bot=self.model, content=post ) if not post.publish_at: post.publish_at = now posts.append(post) self.model.last_state_update_time = utcnow return posts
def schedule_posts(self, filehandle): """Create some number of posts to be published at specific times. It's better to override _schedule_posts() -- this method just calls that method and does some error checking. :return: A list of newly scheduled Posts. """ scheduled = self._schedule_posts(filehandle) if isinstance(scheduled, Post): scheduled = [scheduled] now = _now() for post in scheduled: continue if post.publish_at and post.publish_at < now: raise InvalidPost( "A new post can't be scheduled for the past. (%s was scheduled for %s)" % ( post.content.encode("ascii", errors="replace"), post.publish_at ) ) return scheduled
def test_publishable_posts_returns_all_scheduled_posts(self): bot = self._bot() now = _now() yesterday = now - datetime.timedelta(days=1) day_before = now - datetime.timedelta(days=2) tomorrow = now + datetime.timedelta(days=1) publish_yesterday = self._post(bot.model, "yesterday", publish_at=yesterday) publish_earlier = self._post(bot.model, "day before", publish_at=day_before) publish_later = self._post(bot.model, "tomorrow", publish_at=tomorrow) # publishable_posts returns all posts that should have been # published by now. eq_([publish_earlier, publish_yesterday], bot.publishable_posts) # Since the scheduled posts weren't _created_ by the # publishable_posts, they don't go away when you call # publishable_posts once. They will stick around until they're # published. eq_([publish_earlier, publish_yesterday], bot.publishable_posts)
def _schedule_posts(self): yesterday = _now() - datetime.timedelta(days=1) post, is_new = Post.from_content(self.model, "the past!", publish_at=yesterday) return [post]
def _schedule_posts(self): tomorrow = _now() + datetime.timedelta(days=1) post, is_new = Post.from_content(self.model, "the future!", publish_at=tomorrow) return post