Esempio n. 1
0
  def get(self):
    auth_entity = None
    auth_entity_str_key = self.request.get('auth_entity')
    if auth_entity_str_key:
      auth_entity = ndb.Key(urlsafe=auth_entity_str_key).get()
      if not auth_entity.blog_ids or not auth_entity.blog_hostnames:
        auth_entity = None

    if not auth_entity:
      self.messages.add(
        "Couldn't fetch your blogs. Maybe you're not a Blogger user?")

    state = self.request.get('state')
    if not state:
      # state doesn't currently come through for Blogger. not sure why. doesn't
      # matter for now since we don't plan to implement listen or publish.
      state = self.construct_state_param_for_add(feature='webmention')

    if not auth_entity:
      self.maybe_add_or_delete_source(Blogger, auth_entity, state)
      return

    vars = {
      'action': '/blogger/add',
      'state': state,
      'auth_entity_key': auth_entity.key.urlsafe(),
      'blogs': [{'id': id, 'title': title, 'domain': host}
                for id, title, host in zip(auth_entity.blog_ids,
                                           auth_entity.blog_titles,
                                           auth_entity.blog_hostnames)],
      }
    logging.info('Rendering choose_blog.html with %s', vars)

    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write(JINJA_ENV.get_template('choose_blog.html').render(**vars))
Esempio n. 2
0
  def _render_preview(self, result, include_link=False):
    """Renders a preview CreationResult as HTML.

    Args:
      result: CreationResult
      include_link: boolean

    Returns: CreationResult with the rendered HTML in content
    """
    state = {
      'source_key': self.source.key.urlsafe().decode(),
      'source_url': self.source_url(),
      'target_url': self.target_url(),
      'include_link': include_link,
    }
    vars = {
      'source': self.preprocess_source(self.source),
      'preview': result.content,
      'description': result.description,
      'webmention_endpoint': util.host_url(self) + '/publish/webmention',
      'state': util.encode_oauth_state(state),
    }
    vars.update(state)
    logging.info('Rendering preview with template vars %s', pprint.pformat(vars))
    return gr_source.creation_result(
      JINJA_ENV.get_template('preview.html').render(**vars))
Esempio n. 3
0
    def finish(self, auth_entity, state=None):
        if auth_entity:
            if int(auth_entity.blog_id) == 0:
                self.messages.add(
                    'Please try again and choose a blog before clicking Authorize.'
                )
                return self.redirect('/')

            # Check if this is a self-hosted WordPress blog
            site_info = WordPress.get_site_info(self, auth_entity)
            if site_info is None:
                return
            elif site_info.get('jetpack'):
                logging.info('This is a self-hosted WordPress blog! %s %s',
                             auth_entity.key_id(), auth_entity.blog_id)
                self.response.headers['Content-Type'] = 'text/html'
                self.response.out.write(
                    JINJA_ENV.get_template(
                        'confirm_self_hosted_wordpress.html').render(
                            auth_entity_key=auth_entity.key.urlsafe().decode(),
                            state=state,
                        ))
                return

        self.maybe_add_or_delete_source(WordPress, auth_entity, state)
Esempio n. 4
0
    def finish(self, auth_entity, state=None):
        if not auth_entity:
            self.maybe_add_or_delete_source(Tumblr, auth_entity, state)
            return

        vars = {
            'action':
            '/tumblr/add',
            'state':
            state,
            'auth_entity_key':
            auth_entity.key.urlsafe().decode(),
            'blogs': [
                {
                    'id': b['name'],
                    'title': b.get('title', ''),
                    'domain': util.domain_from_link(b['url'])
                }
                # user_json is the user/info response:
                # http://www.tumblr.com/docs/en/api/v2#user-methods
                for b in json_loads(auth_entity.user_json)['user']['blogs']
                if b.get('name') and b.get('url')
            ],
        }
        logging.info('Rendering choose_blog.html with %s', vars)

        self.response.headers['Content-Type'] = 'text/html'
        self.response.out.write(
            JINJA_ENV.get_template('choose_blog.html').render(**vars))
Esempio n. 5
0
  def _render_preview(self, result, include_link=False):
    """Renders a preview CreationResult as HTML.

    Args:
      result: CreationResult
      include_link: boolean

    Returns: CreationResult with the rendered HTML in content
    """
    state = {
      'source_key': self.source.key.urlsafe(),
      'source_url': self.source_url(),
      'target_url': self.target_url(),
      'include_link': include_link,
    }
    vars = {
      'source': self.preprocess_source(self.source),
      'preview': result.content,
      'description': result.description,
      'webmention_endpoint': util.host_url(self) + '/publish/webmention',
      'state': util.encode_oauth_state(state),
    }
    vars.update(state)
    logging.info('Rendering preview with template vars %s', pprint.pformat(vars))
    return gr_source.creation_result(
      JINJA_ENV.get_template('preview.html').render(**vars))
Esempio n. 6
0
    def finish(self, auth_entity, state=None):
        if not auth_entity:
            self.maybe_add_or_delete_source(Medium, auth_entity, state)
            return

        user = json_loads(auth_entity.user_json)['data']
        username = user['username']
        if not username.startswith('@'):
            username = '******' + username

        # fetch publications this user contributes or subscribes to.
        # (sadly medium's API doesn't tell us the difference unless we fetch each
        # pub's metadata separately.)
        # https://github.com/Medium/medium-api-docs/#user-content-listing-the-users-publications
        auth_entity.publications_json = auth_entity.get(
            oauth_medium.API_BASE + 'users/%s/publications' % user['id']).text
        auth_entity.put()
        pubs = json_loads(auth_entity.publications_json).get('data')
        if not pubs:
            self.maybe_add_or_delete_source(Medium,
                                            auth_entity,
                                            state,
                                            id=username)
            return

        # add user profile to start of pubs list
        user['id'] = username
        pubs.insert(0, user)

        vars = {
            'action':
            '/medium/add',
            'state':
            state,
            'auth_entity_key':
            auth_entity.key.urlsafe(),
            'blogs': [{
                'id': p['id'],
                'title': p.get('name', ''),
                'url': p.get('url', ''),
                'pretty_url': util.pretty_link(str(p.get('url', ''))),
                'image': p.get('imageUrl', ''),
            } for p in pubs if p.get('id')],
        }
        logging.info('Rendering choose_blog.html with %s', vars)
        self.response.headers['Content-Type'] = 'text/html'
        self.response.out.write(
            JINJA_ENV.get_template('choose_blog.html').render(**vars))
Esempio n. 7
0
    def get(self):
        auth_entity = None
        auth_entity_str_key = self.request.get('auth_entity')
        if auth_entity_str_key:
            auth_entity = ndb.Key(urlsafe=auth_entity_str_key).get()
            if not auth_entity.blog_ids or not auth_entity.blog_hostnames:
                auth_entity = None

        if not auth_entity:
            self.messages.add(
                "Couldn't fetch your blogs. Maybe you're not a Blogger user?")

        state = self.request.get('state')
        if not state:
            # state doesn't currently come through for Blogger. not sure why. doesn't
            # matter for now since we don't plan to implement listen or publish.
            state = self.construct_state_param_for_add(feature='webmention')

        if not auth_entity:
            self.maybe_add_or_delete_source(Blogger, auth_entity, state)
            return

        vars = {
            'action':
            '/blogger/add',
            'state':
            state,
            'auth_entity_key':
            auth_entity.key.urlsafe(),
            'blogs': [{
                'id': id,
                'title': title,
                'domain': host
            } for id, title, host in
                      zip(auth_entity.blog_ids, auth_entity.blog_titles,
                          auth_entity.blog_hostnames)],
        }
        logging.info('Rendering choose_blog.html with %s', vars)

        self.response.headers['Content-Type'] = 'text/html'
        self.response.out.write(
            JINJA_ENV.get_template('choose_blog.html').render(**vars))
Esempio n. 8
0
  def finish(self, auth_entity, state=None):
    if not auth_entity:
      self.maybe_add_or_delete_source(Medium, auth_entity, state)
      return

    user = json.loads(auth_entity.user_json)['data']
    username = user['username']
    if not username.startswith('@'):
      username = '******' + username

    # fetch publications this user contributes or subscribes to.
    # (sadly medium's API doesn't tell us the difference unless we fetch each
    # pub's metadata separately.)
    # https://github.com/Medium/medium-api-docs/#user-content-listing-the-users-publications
    auth_entity.publications_json = auth_entity.get(
      oauth_medium.API_BASE + 'users/%s/publications' % user['id']).text
    auth_entity.put()
    pubs = json.loads(auth_entity.publications_json).get('data')
    if not pubs:
      self.maybe_add_or_delete_source(Medium, auth_entity, state,
                                      id=username)
      return

    # add user profile to start of pubs list
    user['id'] = username
    pubs.insert(0, user)

    vars = {
      'action': '/medium/add',
      'state': state,
      'auth_entity_key': auth_entity.key.urlsafe(),
      'blogs': [{
        'id': p['id'],
        'title': p.get('name', ''),
        'url': p.get('url', ''),
        'pretty_url': util.pretty_link(str(p.get('url', ''))),
        'image': p.get('imageUrl', ''),
      } for p in pubs if p.get('id')],
    }
    logging.info('Rendering choose_blog.html with %s', vars)
    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write(JINJA_ENV.get_template('choose_blog.html').render(**vars))
Esempio n. 9
0
  def finish(self, auth_entity, state=None):
    id = util.decode_oauth_state(state).get('id')

    if auth_entity and json.loads(auth_entity.pages_json) and not id:
      # this user has FB page(s), and we don't know whether they want to sign
      # themselves up or one of their pages, so ask them.
      vars = {
        'action': '/facebook/add',
        'state': state,
        'auth_entity_key': auth_entity.key.urlsafe(),
        'choices': [json.loads(auth_entity.user_json)] +
                   json.loads(auth_entity.pages_json),
        }
      logging.info('Rendering choose_facebook.html with %s', vars)
      self.response.headers['Content-Type'] = 'text/html'
      self.response.out.write(
        JINJA_ENV.get_template('choose_facebook.html').render(**vars))
      return

    # this user has no FB page(s), or we know the one they want to sign up.
    self.finish_oauth_flow(auth_entity, state)
Esempio n. 10
0
  def finish(self, auth_entity, state=None):
    if not auth_entity:
      self.maybe_add_or_delete_source(Tumblr, auth_entity, state)
      return

    vars = {
      'action': '/tumblr/add',
      'state': state,
      'auth_entity_key': auth_entity.key.urlsafe(),
      'blogs': [{'id': b['name'],
                 'title': b.get('title', ''),
                 'domain': util.domain_from_link(b['url'])}
                # user_json is the user/info response:
                # http://www.tumblr.com/docs/en/api/v2#user-methods
                for b in json.loads(auth_entity.user_json)['user']['blogs']
                if b.get('name') and b.get('url')],
      }
    logging.info('Rendering choose_blog.html with %s', vars)

    self.response.headers['Content-Type'] = 'text/html'
    self.response.out.write(JINJA_ENV.get_template('choose_blog.html').render(**vars))
Esempio n. 11
0
  def finish(self, auth_entity, state=None):
    if auth_entity:
      if int(auth_entity.blog_id) == 0:
        self.messages.add(
          'Please try again and choose a blog before clicking Authorize.')
        return self.redirect('/')

      # Check if this is a self-hosted WordPress blog
      site_info = WordPress.get_site_info(self, auth_entity)
      if site_info is None:
        return
      elif site_info.get('jetpack'):
        logging.info('This is a self-hosted WordPress blog! %s %s',
                     auth_entity.key.id(), auth_entity.blog_id)
        self.response.headers['Content-Type'] = 'text/html'
        self.response.out.write(
          JINJA_ENV.get_template('confirm_self_hosted_wordpress.html').render(
            auth_entity_key=auth_entity.key.urlsafe(),
            state=state,
          ))
        return

    self.maybe_add_or_delete_source(WordPress, auth_entity, state)
Esempio n. 12
0
  def attempt_single_item(self, item):
    """Attempts to preview or publish a single mf2 item.

    Args:
      item: mf2 item dict from mf2py

    Returns:
      CreationResult
    """
    self.maybe_inject_silo_content(item)
    obj = microformats2.json_to_object(item)

    ignore_formatting = self.ignore_formatting(item)
    if ignore_formatting:
      prop = microformats2.first_props(item.get('properties', {}))
      content = microformats2.get_text(prop.get('content'))
      if content:
        obj['content'] = content.strip()

    # which original post URL to include? in order of preference:
    # 1. rel-shortlink (background: https://github.com/snarfed/bridgy/issues/173)
    # 2. original user-provided URL if it redirected
    # 3. u-url if available
    # 4. actual final fetched URL
    if self.shortlink:
      obj['url'] = self.shortlink
    elif self.source_url() != self.fetched.url:
      obj['url'] = self.source_url()
    elif 'url' not in obj:
      obj['url'] = self.fetched.url
    logging.debug('Converted to ActivityStreams object: %s', json.dumps(obj, indent=2))

    # posts and comments need content
    obj_type = obj.get('objectType')
    if obj_type in ('note', 'article', 'comment'):
      if (not obj.get('content') and not obj.get('summary') and
          not obj.get('displayName')):
        return gr_source.creation_result(
          abort=False,
          error_plain='Could not find content in %s' % self.fetched.url,
          error_html='Could not find <a href="http://microformats.org/">content</a> in %s' % self.fetched.url)

    self.preprocess(obj)

    include_link = self.include_link(item)

    if not self.authorize():
      return gr_source.creation_result(abort=True)

    # RIP Facebook comments/likes. https://github.com/snarfed/bridgy/issues/350
    if (isinstance(self.source, FacebookPage) and
        (obj_type == 'comment' or obj.get('verb') == 'like')):
      return gr_source.creation_result(
        abort=True,
        error_plain='Facebook comments and likes are no longer supported. :(',
        error_html='<a href="https://github.com/snarfed/bridgy/issues/350">'
                   'Facebook comments and likes are no longer supported.</a> :(')

    if self.PREVIEW:
      result = self.source.gr_source.preview_create(
        obj, include_link=include_link, ignore_formatting=ignore_formatting)
      self.entity.published = result.content or result.description
      if not self.entity.published:
        return result  # there was an error
      state = {
        'source_key': self.source.key.urlsafe(),
        'source_url': self.source_url(),
        'target_url': self.target_url(),
        'include_link': include_link,
      }
      vars = {'source': self.preprocess_source(self.source),
              'preview': result.content,
              'description': result.description,
              'webmention_endpoint': self.request.host_url + '/publish/webmention',
              'state': util.encode_oauth_state(state),
              }
      vars.update(state)
      logging.info('Rendering preview with template vars %s', pprint.pformat(vars))
      return gr_source.creation_result(
        JINJA_ENV.get_template('preview.html').render(**vars))

    else:
      result = self.source.gr_source.create(
        obj, include_link=include_link, ignore_formatting=ignore_formatting)
      self.entity.published = result.content
      if not result.content:
        return result  # there was an error
      if 'url' not in self.entity.published:
        self.entity.published['url'] = obj.get('url')
      self.entity.type = self.entity.published.get('type') or models.get_type(obj)
      self.entity.type_label = self.source.TYPE_LABELS.get(self.entity.type)
      self.response.headers['Content-Type'] = 'application/json'
      logging.info('Returning %s', json.dumps(self.entity.published, indent=2))
      self.response.headers['Location'] = self.entity.published['url'].encode('utf-8')
      self.response.status = 201
      return gr_source.creation_result(
        json.dumps(self.entity.published, indent=2))
Esempio n. 13
0
  def attempt_single_item(self, item):
    """Attempts to preview or publish a single mf2 item.

    Args:
      item: mf2 item dict from mf2py

    Returns:
      CreationResult
    """
    self.maybe_inject_silo_content(item)
    obj = microformats2.json_to_object(item)

    ignore_formatting = self.ignore_formatting(item)
    if ignore_formatting:
      prop = microformats2.first_props(item.get('properties', {}))
      content = microformats2.get_text(prop.get('content'))
      if content:
        obj['content'] = content.strip()

    # which original post URL to include? in order of preference:
    # 1. rel-shortlink (background: https://github.com/snarfed/bridgy/issues/173)
    # 2. original user-provided URL if it redirected
    # 3. u-url if available
    # 4. actual final fetched URL
    if self.shortlink:
      obj['url'] = self.shortlink
    elif self.source_url() != self.fetched.url:
      obj['url'] = self.source_url()
    elif 'url' not in obj:
      obj['url'] = self.fetched.url
    logging.debug('Converted to ActivityStreams object: %s', json.dumps(obj, indent=2))

    # posts and comments need content
    obj_type = obj.get('objectType')
    if obj_type in ('note', 'article', 'comment'):
      if (not obj.get('content') and not obj.get('summary') and
          not obj.get('displayName')):
        return gr_source.creation_result(
          abort=False,
          error_plain='Could not find content in %s' % self.fetched.url,
          error_html='Could not find <a href="http://microformats.org/">content</a> in %s' % self.fetched.url)

    self.preprocess(obj)

    include_link = self.include_link(item)

    if not self.authorize():
      return gr_source.creation_result(abort=True)

    # RIP Facebook comments/likes. https://github.com/snarfed/bridgy/issues/350
    if (isinstance(self.source, FacebookPage) and
        (obj_type == 'comment' or obj.get('verb') == 'like')):
      return gr_source.creation_result(
        abort=True,
        error_plain='Facebook comments and likes are no longer supported. :(',
        error_html='<a href="https://github.com/snarfed/bridgy/issues/350">'
                   'Facebook comments and likes are no longer supported.</a> :(')

    if self.PREVIEW:
      result = self.source.gr_source.preview_create(
        obj, include_link=include_link, ignore_formatting=ignore_formatting)
      self.entity.published = result.content or result.description
      if not self.entity.published:
        return result  # there was an error
      state = {
        'source_key': self.source.key.urlsafe(),
        'source_url': self.source_url(),
        'target_url': self.target_url(),
        'include_link': include_link,
      }
      vars = {'source': self.preprocess_source(self.source),
              'preview': result.content,
              'description': result.description,
              'webmention_endpoint': self.request.host_url + '/publish/webmention',
              'state': util.encode_oauth_state(state),
              }
      vars.update(state)
      logging.info('Rendering preview with template vars %s', pprint.pformat(vars))
      return gr_source.creation_result(
        JINJA_ENV.get_template('preview.html').render(**vars))

    else:
      result = self.source.gr_source.create(
        obj, include_link=include_link, ignore_formatting=ignore_formatting)
      self.entity.published = result.content
      if not result.content:
        return result  # there was an error
      if 'url' not in self.entity.published:
        self.entity.published['url'] = obj.get('url')
      self.entity.type = self.entity.published.get('type') or models.get_type(obj)
      self.entity.type_label = self.source.TYPE_LABELS.get(self.entity.type)
      self.response.headers['Content-Type'] = 'application/json'
      logging.info('Returning %s', json.dumps(self.entity.published, indent=2))
      self.response.headers['Location'] = self.entity.published['url'].encode('utf-8')
      self.response.status = 201
      return gr_source.creation_result(
        json.dumps(self.entity.published, indent=2))