コード例 #1
0
ファイル: facebook.py プロジェクト: mongolsamurai/redwind
def authorize_facebook():
    import urllib.parse
    import urllib.request
    redirect_uri = url_for('.authorize_facebook', _external=True)
    params = {
        'client_id': get_settings().facebook_app_id,
        'redirect_uri': redirect_uri,
        'scope': 'publish_actions,user_photos',
    }

    code = request.args.get('code')
    if code:
        params['code'] = code
        params['client_secret'] = get_settings().facebook_app_secret

        r = urllib.request.urlopen(
            'https://graph.facebook.com/oauth/access_token?'
            + urllib.parse.urlencode(params))
        payload = urllib.parse.parse_qs(r.read())

        access_token = payload[b'access_token'][0].decode('ascii')
        Setting.query.get('facebook_access_token').value = access_token
        db.session.commit()
        return redirect(url_for('admin.edit_settings'))
    else:
        return redirect('https://graph.facebook.com/oauth/authorize?'
                        + urllib.parse.urlencode(params))
コード例 #2
0
ファイル: wordpress.py プロジェクト: TylerMorley/redwind
def authorize_wordpress():
    from redwind.extensions import db
    redirect_uri = url_for('.authorize_wordpress', _external=True)

    code = request.args.get('code')
    if code:
        r = requests.post(API_TOKEN_URL, data={
            'client_id': get_settings().wordpress_client_id,
            'redirect_uri': redirect_uri,
            'client_secret': get_settings().wordpress_client_secret,
            'code': code,
            'grant_type': 'authorization_code',
        })

        if r.status_code // 100 != 2:
            return make_response(
                'Code: {}. Message: {}'.format(r.status_code, r.text),
                r.status_code)

        payload = r.json()

        access_token = payload.get('access_token')
        Setting.query.get('wordpress_access_token').value = access_token
        db.session.commit()
        return redirect(url_for('admin.edit_settings'))
    else:
        return redirect(API_AUTHORIZE_URL + '?' + urllib.parse.urlencode({
            'client_id': get_settings().wordpress_client_id,
            'redirect_uri': redirect_uri,
            'response_type': 'code',
            'scope': 'global',
        }))
コード例 #3
0
ファイル: admin.py プロジェクト: TylerMorley/redwind
def login_facebook():
    redirect_uri = url_for('.login_facebook', _external=True)
    params = {
        'client_id': get_settings().facebook_app_id,
        'redirect_uri': redirect_uri,
    }

    if 'code' not in request.args:
        return redirect('https://www.facebook.com/dialog/oauth?'
                        + urllib.parse.urlencode(params))

    params['code'] = request.args.get('code')
    params['client_secret'] = get_settings().facebook_app_secret

    r = requests.get('https://graph.facebook.com/v2.3/oauth/access_token',
                     params=params)

    access_token = r.json().get('access_token')
    r = requests.get('https://graph.facebook.com/v2.2/me',
                     params={'access_token': access_token})

    user_json = r.json()
    fbid = user_json.get('id')
    name = user_json.get('name')

    cred = Credential.query.get(('facebook', fbid))
    if not cred:
        cred = Credential(type='facebook', value=fbid, display=name)
        db.session.add(cred)
        db.session.commit()

    return do_login(cred, user_json.get('name'))
コード例 #4
0
ファイル: facebook.py プロジェクト: kylewm/redwind
def share_on_facebook():
    from .twitter import collect_images

    if request.method == "GET":
        post = Post.load_by_id(request.args.get("id"))

        message, link, name, picture = guess_content(post)
        imgs = [urljoin(get_settings().site_url, img) for img in collect_images(post)]

        albums = []
        if imgs:
            current_app.logger.debug("fetching user albums")
            resp = requests.get(
                "https://graph.facebook.com/v2.2/me/albums",
                params={"access_token": get_settings().facebook_access_token},
            )
            resp.raise_for_status()
            current_app.logger.debug("user albums response %s: %s", resp, resp.text)
            albums = resp.json().get("data", [])

        return render_template(
            "admin/share_on_facebook.jinja2",
            post=post,
            preview=message,
            link=link,
            name=name,
            picture=picture,
            imgs=imgs,
            albums=albums,
        )

    try:
        post_id = request.form.get("post_id")
        preview = request.form.get("preview")
        img_url = request.form.get("img")
        is_photo = request.form.get("post_type") == "photo"
        album_id = request.form.get("album")
        link = request.form.get("link")

        if album_id == "new":
            album_id = create_album(request.form.get("new_album_name"), request.form.get("new_album_message"))

        post = Post.load_by_id(post_id)
        facebook_url = handle_new_or_edit(
            post, message=preview, link=link, name=None, picture=img_url, is_photo=is_photo, album_id=album_id
        )

        db.session.commit()
        if has_request_context():
            flash(
                'Shared on Facebook: <a href="{}">Original</a>, '
                '<a href="{}">On Facebook</a><br/>'.format(post.permalink, facebook_url)
            )
            return redirect(post.permalink)

    except Exception as e:
        if has_request_context():
            current_app.logger.exception("posting to facebook")
            flash("Share on Facebook Failed! Exception: {}".format(e))
        return redirect(url_for("views.index"))
コード例 #5
0
ファイル: admin.py プロジェクト: TylerMorley/redwind
def login_twitter():
    callback_url = url_for('.login_twitter', _external=True)
    try:
        oauth_session = OAuth1Session(
            client_key=get_settings().twitter_api_key,
            client_secret=get_settings().twitter_api_secret,
            callback_uri=callback_url)

        if 'oauth_token' not in request.args:
            oauth_session.fetch_request_token(
                'https://api.twitter.com/oauth/request_token')
            return redirect(oauth_session.authorization_url(
                'https://api.twitter.com/oauth/authenticate'))

        oauth_session.parse_authorization_response(request.url)
        oauth_session.fetch_access_token(
            'https://api.twitter.com/oauth/access_token')
        user_response = oauth_session.get(
            'https://api.twitter.com/1.1/account/verify_credentials.json')
        user_json = user_response.json()

        twid = user_json.get('id_str')
        screen_name = user_json.get('screen_name')
        cred = Credential.query.get(('twitter', twid))
        if not cred:
            cred = Credential(type='twitter', value=twid, display=screen_name)
            db.session.add(cred)
            db.session.commit()

        return do_login(cred, user_json.get('name'))

    except requests.RequestException as e:
        return make_response(str(e))
コード例 #6
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
def share_on_facebook():
    from .twitter import collect_images

    if request.method == 'GET':
        post = Post.load_by_id(request.args.get('id'))

        message, link, name, picture = guess_content(post)
        imgs = [urljoin(get_settings().site_url, img)
                for img in collect_images(post)]

        albums = []
        if imgs:
            current_app.logger.debug('fetching user albums')
            resp = requests.get(
                'https://graph.facebook.com/v2.2/me/albums',
                params={'access_token': get_settings().facebook_access_token})
            resp.raise_for_status()
            current_app.logger.debug(
                'user albums response %s: %s', resp, resp.text)
            albums = resp.json().get('data', [])

        return render_template('admin/share_on_facebook.jinja2', post=post,
                               preview=message, link=link, name=name,
                               picture=picture, imgs=imgs, albums=albums)

    try:
        post_id = request.form.get('post_id')
        preview = request.form.get('preview')
        img_url = request.form.get('img')
        is_photo = request.form.get('post_type') == 'photo'
        album_id = request.form.get('album')
        link = request.form.get('link')

        if album_id == 'new':
            album_id = create_album(
                request.form.get('new_album_name'),
                request.form.get('new_album_message'))

        post = Post.load_by_id(post_id)
        facebook_url = handle_new_or_edit(
            post, message=preview, link=link, name=None, picture=img_url,
            is_photo=is_photo, album_id=album_id)

        db.session.commit()
        if has_request_context():
            flash('Shared on Facebook: <a href="{}">Original</a>, '
                  '<a href="{}">On Facebook</a><br/>'
                  .format(post.permalink, facebook_url))
            return redirect(post.permalink)

    except Exception as e:
        if has_request_context():
            current_app.logger.exception('posting to facebook')
            flash('Share on Facebook Failed! Exception: {}'.format(e))
        return redirect(url_for('views.index'))
コード例 #7
0
ファイル: facebook.py プロジェクト: mongolsamurai/redwind
def share_on_facebook():
    from .twitter import collect_images

    if request.method == 'GET':
        post = Post.load_by_id(request.args.get('id'))

        message, link, name, picture = guess_content(post)
        imgs = [urllib.parse.urljoin(get_settings().site_url, img)
                for img in collect_images(post)]

        albums = []
        if imgs:
            current_app.logger.debug('fetching user albums')
            resp = requests.get(
                'https://graph.facebook.com/v2.2/me/albums',
                params={'access_token': get_settings().facebook_access_token})
            resp.raise_for_status()
            current_app.logger.debug(
                'user albums response %s: %s', resp, resp.text)
            albums = resp.json().get('data', [])

        return render_template('admin/share_on_facebook.jinja2', post=post,
                               preview=message, link=link, name=name,
                               picture=picture, imgs=imgs, albums=albums)

    try:
        post_id = request.form.get('post_id')
        preview = request.form.get('preview')
        img_url = request.form.get('img')
        is_photo = request.form.get('post_type') == 'photo'
        album_id = request.form.get('album')
        link = request.form.get('link')

        if album_id == 'new':
            album_id = create_album(
                request.form.get('new_album_name'),
                request.form.get('new_album_message'))

        post = Post.load_by_id(post_id)
        facebook_url = handle_new_or_edit(
            post, message=preview, link=link, name=None, picture=img_url,
            is_photo=is_photo, album_id=album_id)

        db.session.commit()
        if has_request_context():
            flash('Shared on Facebook: <a href="{}">Original</a>, '
                  '<a href="{}">On Facebook</a><br/>'
                  .format(post.permalink, facebook_url))
            return redirect(post.permalink)

    except Exception as e:
        if has_request_context():
            current_app.logger.exception('posting to facebook')
            flash('Share on Facebook Failed! Exception: {}'.format(e))
        return redirect(url_for('views.index'))
コード例 #8
0
def authorize_twitter():
    """Get an access token from Twitter and redirect to the
       authentication page"""
    callback_url = url_for('.twitter_callback', _external=True)
    try:
        oauth = OAuth1Session(client_key=get_settings().twitter_api_key,
                              client_secret=get_settings().twitter_api_secret,
                              callback_uri=callback_url)

        oauth.fetch_request_token(REQUEST_TOKEN_URL)
        return redirect(oauth.authorization_url(AUTHORIZE_URL))

    except requests.RequestException as e:
        return make_response(str(e))
コード例 #9
0
ファイル: twitter.py プロジェクト: kylewm/redwind
def authorize_twitter():
    """Get an access token from Twitter and redirect to the
       authentication page"""
    callback_url = url_for('.twitter_callback', _external=True)
    try:
        oauth = OAuth1Session(
            client_key=get_settings().twitter_api_key,
            client_secret=get_settings().twitter_api_secret,
            callback_uri=callback_url)

        oauth.fetch_request_token(REQUEST_TOKEN_URL)
        return redirect(oauth.authorization_url(AUTHORIZE_URL))

    except requests.RequestException as e:
        return make_response(str(e))
コード例 #10
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def time_filter(thedate):
    if thedate:
        if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
            tz = pytz.timezone(get_settings().timezone)
            thedate = pytz.utc.localize(thedate).astimezone(tz)
        if isinstance(thedate, datetime.datetime):
            return thedate.strftime('%-I:%M%P %Z')
コード例 #11
0
def time_filter(thedate):
    if thedate:
        if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
            tz = pytz.timezone(get_settings().timezone)
            thedate = pytz.utc.localize(thedate).astimezone(tz)
        if isinstance(thedate, datetime.datetime):
            return thedate.strftime('%-I:%M%P %Z')
コード例 #12
0
def index(before_ts=None):
    post_types = [type[0] for type in POST_TYPES if type[0] != 'event']
    posts, older = collect_posts(post_types,
                                 before_ts,
                                 int(get_settings().posts_per_page),
                                 None,
                                 include_hidden=False)

    if request.args.get('feed') == 'atom':
        return render_posts_atom('Stream', 'index.atom', posts)

    resp = make_response(
        render_posts('Stream',
                     posts,
                     older,
                     events=collect_upcoming_events(),
                     template='home.jinja2'))

    if 'PUSH_HUB' in current_app.config:
        resp.headers.add(
            'Link', '<{}>; rel="hub"'.format(current_app.config['PUSH_HUB']))
        resp.headers.add(
            'Link', '<{}>; rel="self"'.format(url_for('.index',
                                                      _external=True)))
    return resp
コード例 #13
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def everything(before_ts=None):
    posts, older = collect_posts(
        None, before_ts, int(get_settings().posts_per_page), None,
        include_hidden=True)

    if request.args.get('feed') == 'atom':
        return render_posts_atom('Everything', 'everything.atom', posts)
    return render_posts('Everything', posts, older)
コード例 #14
0
 def repl(m):
     url = m.group(2)
     # don't proxy images that come from this site
     if url.startswith(get_settings().site_url):
         return m.group(0)
     url = url.replace('&amp;', '&')
     return '<img{} src="{}"'.format(
         m.group(1), imageproxy.imageproxy_filter(url, side))
コード例 #15
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
 def repl(m):
     url = m.group(2)
     # don't proxy images that come from this site
     if url.startswith(get_settings().site_url):
         return m.group(0)
     url = url.replace('&amp;', '&')
     return '<img{} src="{}"'.format(
         m.group(1), imageproxy.imageproxy_filter(url, side))
コード例 #16
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def posts_by_tag(tag, before_ts=None):
    posts, older = collect_posts(
        None, before_ts, int(get_settings().posts_per_page), tag,
        include_hidden=True)
    title = '#' + tag

    if request.args.get('feed') == 'atom':
        return render_posts_atom(title, 'tag-' + tag + '.atom', posts)
    return render_posts(title, posts, older)
コード例 #17
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def isotime_filter(thedate):
    if thedate:
        thedate = thedate.replace(microsecond=0)
        if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
            tz = pytz.timezone(get_settings().timezone)
            thedate = pytz.utc.localize(thedate).astimezone(tz)
        if isinstance(thedate, datetime.datetime):
            return thedate.isoformat('T')
        return thedate.isoformat()
コード例 #18
0
ファイル: admin.py プロジェクト: TylerMorley/redwind
def login_callback():
    current_app.logger.debug('callback fields: %s', request.args)

    state = request.args.get('state')
    next_url = state or url_for('views.index')
    # TODO rediscover these endpoints based on 'me'. Assuming
    # they are the same is not totally safe.
    auth_url, token_url, micropub_url = session['endpoints']

    if not auth_url:
        flash('Login failed: No authorization URL in session')
        return redirect(next_url)

    code = request.args.get('code')
    client_id = get_settings().site_url
    redirect_uri = url_for('.login_callback', _external=True)

    current_app.logger.debug('callback with auth endpoint %s', auth_url)
    response = requests.post(auth_url, data={
        'code': code,
        'client_id': client_id,
        'redirect_uri': redirect_uri,
        'state': state,
    })

    rdata = urllib.parse.parse_qs(response.text)
    if response.status_code != 200:
        current_app.logger.debug('call to auth endpoint failed %s', response)
        flash('Login failed {}: {}'.format(rdata.get('error'),
                                           rdata.get('error_description')))
        return redirect(next_url)

    current_app.logger.debug('verify response %s', response.text)
    if 'me' not in rdata:
        current_app.logger.debug('Verify response missing required "me" field')
        flash('Verify response missing required "me" field {}'.format(
            response.text))
        return redirect(next_url)

    me = rdata.get('me')[0]
    scopes = rdata.get('scope')

    try_micropub_config(token_url, micropub_url, scopes, code, me,
                        redirect_uri, client_id, state)

    cred = Credential.query.get(('indieauth', me))
    if not cred:
        cred = Credential(type='indieauth', value=me, display=me)
        db.session.add(cred)
        db.session.commit()

    # offer to associate credential with existing user or create a new user
    p = mf2py.parse(url=me)
    hcard = mf2util.representative_hcard(p, me)
    author = hcard and mf2util.parse_author(hcard)

    return do_login(cred, author and author.get('name'), next_url)
コード例 #19
0
def isotime_filter(thedate):
    if thedate:
        thedate = thedate.replace(microsecond=0)
        if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
            tz = pytz.timezone(get_settings().timezone)
            thedate = pytz.utc.localize(thedate).astimezone(tz)
        if isinstance(thedate, datetime.datetime):
            return thedate.isoformat('T')
        return thedate.isoformat()
コード例 #20
0
ファイル: facebook.py プロジェクト: kylewm/redwind
    def get_taggable_friends(self):
        if not self.taggable_friends:
            r = requests.get(
                "https://graph.facebook.com/v2.0/me/taggable_friends",
                params={"access_token": get_settings().facebook_access_token},
            )
            self.taggable_friends = r.json()

        return self.taggable_friends or {}
コード例 #21
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def search(before_ts=None):
    q = request.args.get('q')
    if not q:
        abort(404)

    posts, older = collect_posts(
        None, before_ts, int(get_settings().posts_per_page), None,
        include_hidden=True, search=q)
    return render_posts('Search: ' + q, posts, older)
コード例 #22
0
ファイル: wm_receiver.py プロジェクト: mongolsamurai/redwind
def interpret_mention(source, target):
    current_app.logger.debug("processing webmention from %s to %s", source, target)
    if target and target.strip("/") == get_settings().site_url.strip("/"):
        # received a domain-level mention
        current_app.logger.debug("received domain-level webmention from %s", source)
        target_post = None
        target_urls = (target,)
        # TODO save domain-level webmention somewhere
        return ProcessResult(error="Receiving domain-level webmentions is not yet implemented")
    else:
        # confirm that target is a valid link to a post
        target_post = find_target_post(target)

        if not target_post:
            current_app.logger.warn("Webmention could not find target post: %s. Giving up", target)
            return ProcessResult(error="Webmention could not find target post: {}".format(target))
        target_urls = (target, target_post.permalink)

    if source in target_urls:
        return ProcessResult(error="{} and {} refer to the same post".format(source, target))

    # confirm that source actually refers to the post
    source_response = util.fetch_html(source)
    current_app.logger.debug("received response from source %s", source_response)

    if source_response.status_code == 410:
        current_app.logger.debug("Webmention indicates original was deleted")
        return ProcessResult(post=target_post, delete=True)

    if source_response.status_code // 100 != 2:
        current_app.logger.warn("Webmention could not read source post: %s. Giving up", source)
        return ProcessResult(
            post=target_post, error="Bad response when reading source post: {}, {}".format(source, source_response)
        )

    source_length = source_response.headers.get("Content-Length")

    if source_length and int(source_length) > 2097152:
        current_app.logger.warn("Very large source. length=%s", source_length)
        return ProcessResult(post=target_post, error="Source is very large. Length={}".format(source_length))

    link_to_target = find_link_to_target(source, source_response, target_urls)
    if not link_to_target:
        current_app.logger.warn(
            "Webmention source %s does not appear to link to target %s. " "Giving up", source, target
        )
        return ProcessResult(post=target_post, error="Could not find any links from source to target")

    mentions = create_mentions(target_post, source, source_response)
    if not mentions:
        return ProcessResult(post=target_post, error="Could not parse a mention from the source")

    result = ProcessResult(post=target_post)
    for mention in mentions:
        result.add_mention(mention, create=not mention.id)
    return result
コード例 #23
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def posts_by_type(plural_type, before_ts=None):
    post_type, _, title = next(tup for tup in POST_TYPES
                               if tup[1] == plural_type)
    posts, older = collect_posts(
        (post_type,), before_ts, int(get_settings().posts_per_page), None,
        include_hidden=True)

    if request.args.get('feed') == 'atom':
        return render_posts_atom(title, plural_type + '.atom', posts)
    return render_posts(title, posts, older)
コード例 #24
0
def everything(before_ts=None):
    posts, older = collect_posts(None,
                                 before_ts,
                                 int(get_settings().posts_per_page),
                                 None,
                                 include_hidden=True)

    if request.args.get('feed') == 'atom':
        return render_posts_atom('Everything', 'everything.atom', posts)
    return render_posts('Everything', posts, older)
コード例 #25
0
ファイル: imageproxy.py プロジェクト: kylewm/redwind
def construct_url(url, size=None, external=False):
    from redwind.models import get_settings
    if not url or 'PILBOX_URL' not in current_app.config:
        return url
    url = urllib.parse.urljoin(get_settings().site_url, url)
    query = [('url', url)]
    if size:
        query += [('w', size), ('h', size), ('mode', 'clip')]
    else:
        query += [('op', 'noop')]
    querystring = urllib.parse.urlencode(query)
    if 'PILBOX_KEY' in current_app.config:
        h = hmac.new(current_app.config['PILBOX_KEY'].encode(),
                     querystring.encode(), hashlib.sha1)
        querystring += '&sig=' + h.hexdigest()
    proxy_url = current_app.config['PILBOX_URL'] + '?' + querystring
    if external:
        proxy_url = urllib.parse.urljoin(get_settings().site_url, proxy_url)
    return proxy_url
コード例 #26
0
def construct_url(url, size=None, external=False):
    from redwind.models import get_settings
    if not url or 'PILBOX_URL' not in current_app.config:
        return url
    url = urllib.parse.urljoin(get_settings().site_url, url)
    query = [('url', url)]
    if size:
        query += [('w', size), ('h', size), ('mode', 'clip')]
    else:
        query += [('op', 'noop')]
    querystring = urllib.parse.urlencode(query)
    if 'PILBOX_KEY' in current_app.config:
        h = hmac.new(current_app.config['PILBOX_KEY'].encode(),
                     querystring.encode(), hashlib.sha1)
        querystring += '&sig=' + h.hexdigest()
    proxy_url = current_app.config['PILBOX_URL'] + '?' + querystring
    if external:
        proxy_url = urllib.parse.urljoin(get_settings().site_url, proxy_url)
    return proxy_url
コード例 #27
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
    def get_taggable_friends(self):
        if not self.taggable_friends:
            r = requests.get(
                'https://graph.facebook.com/v2.0/me/taggable_friends',
                params={
                    'access_token': get_settings().facebook_access_token
                })
            self.taggable_friends = r.json()

        return self.taggable_friends or {}
コード例 #28
0
def posts_by_tag(tag, before_ts=None):
    posts, older = collect_posts(None,
                                 before_ts,
                                 int(get_settings().posts_per_page),
                                 tag,
                                 include_hidden=True)
    title = '#' + tag

    if request.args.get('feed') == 'atom':
        return render_posts_atom(title, 'tag-' + tag + '.atom', posts)
    return render_posts(title, posts, older)
コード例 #29
0
def twitter_callback():
    """Receive the request token from Twitter and convert it to an
       access token"""
    try:
        oauth = OAuth1Session(client_key=get_settings().twitter_api_key,
                              client_secret=get_settings().twitter_api_secret)
        oauth.parse_authorization_response(request.url)

        response = oauth.fetch_access_token(ACCESS_TOKEN_URL)
        access_token = response.get('oauth_token')
        access_token_secret = response.get('oauth_token_secret')

        Setting.query.get('twitter_oauth_token').value = access_token
        Setting.query.get('twitter_oauth_token_secret').value \
            = access_token_secret

        db.session.commit()
        return redirect(url_for('admin.edit_settings'))
    except requests.RequestException as e:
        return make_response(str(e))
コード例 #30
0
def human_time(thedate, alternate=None):
    if not thedate:
        return alternate

    if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
        tz = pytz.timezone(get_settings().timezone)
        thedate = pytz.utc.localize(thedate).astimezone(tz)

    if (isinstance(thedate, datetime.datetime)):
        return thedate.strftime('%B %-d, %Y %-I:%M%P %Z')
    return thedate.strftime('%B %-d, %Y')
コード例 #31
0
ファイル: views.py プロジェクト: kylewm/redwind
def human_time(thedate, alternate=None):
    if not thedate:
        return alternate

    if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
        tz = pytz.timezone(get_settings().timezone)
        thedate = pytz.utc.localize(thedate).astimezone(tz)

    if (isinstance(thedate, datetime.datetime)):
        return thedate.strftime('%B %-d, %Y %-I:%M%P %Z')
    return thedate.strftime('%B %-d, %Y')
コード例 #32
0
def search(before_ts=None):
    q = request.args.get('q')
    if not q:
        abort(404)

    posts, older = collect_posts(None,
                                 before_ts,
                                 int(get_settings().posts_per_page),
                                 None,
                                 include_hidden=True,
                                 search=q)
    return render_posts('Search: ' + q, posts, older)
コード例 #33
0
def date_filter(thedate, first_only=False):
    if thedate:
        if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
            tz = pytz.timezone(get_settings().timezone)
            thedate = pytz.utc.localize(thedate).astimezone(tz)
        formatted = thedate.strftime('%B %-d, %Y')
        if first_only:
            previous = getattr(g, 'previous date', None)
            setattr(g, 'previous date', formatted)
            if previous == formatted:
                return None
        return formatted
コード例 #34
0
ファイル: twitter.py プロジェクト: kylewm/redwind
def twitter_callback():
    """Receive the request token from Twitter and convert it to an
       access token"""
    try:
        oauth = OAuth1Session(
            client_key=get_settings().twitter_api_key,
            client_secret=get_settings().twitter_api_secret)
        oauth.parse_authorization_response(request.url)

        response = oauth.fetch_access_token(ACCESS_TOKEN_URL)
        access_token = response.get('oauth_token')
        access_token_secret = response.get('oauth_token_secret')

        Setting.query.get('twitter_oauth_token').value = access_token
        Setting.query.get('twitter_oauth_token_secret').value \
            = access_token_secret

        db.session.commit()
        return redirect(url_for('admin.edit_settings'))
    except requests.RequestException as e:
        return make_response(str(e))
コード例 #35
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def date_filter(thedate, first_only=False):
    if thedate:
        if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
            tz = pytz.timezone(get_settings().timezone)
            thedate = pytz.utc.localize(thedate).astimezone(tz)
        formatted = thedate.strftime('%B %-d, %Y')
        if first_only:
            previous = getattr(g, 'previous date', None)
            setattr(g, 'previous date', formatted)
            if previous == formatted:
                return None
        return formatted
コード例 #36
0
ファイル: admin.py プロジェクト: Lancey6/redwind
def login_callback():
    current_app.logger.debug('callback fields: %s', request.args)

    state = request.args.get('state')
    next_url = state or url_for('views.index')
    auth_url, token_url, micropub_url = session['endpoints']

    if not auth_url:
        flash('Login failed: No authorization URL in session')
        return redirect(next_url)

    code = request.args.get('code')
    client_id = get_settings().site_url
    redirect_uri = url_for('.login_callback', _external=True)

    current_app.logger.debug('callback with auth endpoint %s', auth_url)
    response = requests.post(auth_url, data={
        'code': code,
        'client_id': client_id,
        'redirect_uri': redirect_uri,
        'state': state,
    })

    rdata = urllib.parse.parse_qs(response.text)
    if response.status_code != 200:
        current_app.logger.debug('call to auth endpoint failed %s', response)
        flash('Login failed {}: {}'.format(rdata.get('error'),
                                           rdata.get('error_description')))
        return redirect(next_url)

    current_app.logger.debug('verify response %s', response.text)
    if 'me' not in rdata:
        current_app.logger.debug('Verify response missing required "me" field')
        flash('Verify response missing required "me" field {}'.format(
            response.text))
        return redirect(next_url)

    me = rdata.get('me')[0]
    scopes = rdata.get('scope')
    user = auth.load_user(urllib.parse.urlparse(me).netloc)
    if not user:
        flash('No user for domain {}'.format(me))
        return redirect(next_url)

    try_micropub_config(token_url, micropub_url, scopes, code, me,
                        redirect_uri, client_id, state)

    current_app.logger.debug('Logging in user %s', user)
    flask_login.login_user(user, remember=True)
    flash('Logged in with domain {}'.format(me))
    current_app.logger.debug('Logged in with domain %s', me)

    return redirect(next_url)
コード例 #37
0
def posts_by_type(plural_type, before_ts=None):
    post_type, _, title = next(tup for tup in POST_TYPES
                               if tup[1] == plural_type)
    posts, older = collect_posts((post_type, ),
                                 before_ts,
                                 int(get_settings().posts_per_page),
                                 None,
                                 include_hidden=True)

    if request.args.get('feed') == 'atom':
        return render_posts_atom(title, plural_type + '.atom', posts)
    return render_posts(title, posts, older)
コード例 #38
0
ファイル: facebook.py プロジェクト: kylewm/redwind
def authorize_facebook():
    redirect_uri = url_for(".authorize_facebook", _external=True)
    params = {
        "client_id": get_settings().facebook_app_id,
        "redirect_uri": redirect_uri,
        "scope": "publish_actions,user_photos",
    }

    code = request.args.get("code")
    if code:
        params["code"] = code
        params["client_secret"] = get_settings().facebook_app_secret

        r = urlopen("https://graph.facebook.com/oauth/access_token?" + urlencode(params))
        payload = parse_qs(r.read())

        access_token = payload[b"access_token"][0].decode("ascii")
        Setting.query.get("facebook_access_token").value = access_token
        db.session.commit()
        return redirect(url_for("admin.edit_settings"))
    else:
        return redirect("https://graph.facebook.com/oauth/authorize?" + urlencode(params))
コード例 #39
0
ファイル: facebook.py プロジェクト: kylewm/redwind
def handle_new_or_edit(post, message, link, name, picture, is_photo, album_id):
    current_app.logger.debug("publishing to facebook")

    # TODO I cannot figure out how to tag people via the FB API

    post_args = {
        "access_token": get_settings().facebook_access_token,
        "message": message.strip(),
        "privacy": json.dumps({"value": "EVERYONE"}),
        #'privacy': json.dumps({'value': 'SELF'}),
    }

    if is_photo and picture:
        post_args["url"] = picture
        current_app.logger.debug("Sending photo %s to album %s", post_args, album_id)
        response = requests.post(
            "https://graph.facebook.com/v2.0/{}/photos".format(album_id if album_id else "me"), data=post_args
        )
    else:
        post_args.update(util.trim_nulls({"link": link, "name": name, "picture": picture}))
        current_app.logger.debug("Sending post %s", post_args)
        response = requests.post("https://graph.facebook.com/v2.0/me/feed", data=post_args)
    response.raise_for_status()
    current_app.logger.debug("Got response from facebook %s", response)

    if "json" in response.headers["content-type"]:
        result = response.json()

    current_app.logger.debug("published to facebook. response {}".format(result))

    if result:
        if is_photo:
            facebook_photo_id = result["id"]
            facebook_post_id = result["post_id"]  # actually the album

            split = facebook_post_id.split("_", 1)
            if split and len(split) == 2:
                user_id, post_id = split
                fb_url = "https://facebook.com/{}/posts/{}".format(user_id, facebook_photo_id)
                post.add_syndication_url(fb_url)
                return fb_url

        else:
            facebook_post_id = result["id"]
            split = facebook_post_id.split("_", 1)
            if split and len(split) == 2:
                user_id, post_id = split
                fb_url = "https://facebook.com/{}/posts/{}".format(user_id, post_id)
                post.add_syndication_url(fb_url)
                return fb_url
コード例 #40
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
def create_album(name, msg):
    current_app.logger.debug('creating new facebook album %s', name)
    resp = requests.post(
        'https://graph.facebook.com/v2.0/me/albums', data={
            'access_token': get_settings().facebook_access_token,
            'name': name,
            'message': msg,
            'privacy': json.dumps({'value': 'EVERYONE'}),
            #'privacy': json.dumps({'value': 'SELF'}),
        })
    resp.raise_for_status()
    current_app.logger.debug(
        'new facebook album response: %s, %s', resp, resp.text)
    return resp.json()['id']
コード例 #41
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def human_time(thedate, alternate=None):
    if not thedate:
        return alternate

    if hasattr(thedate, 'tzinfo') and not thedate.tzinfo:
        tz = pytz.timezone(get_settings().timezone)
        thedate = pytz.utc.localize(thedate).astimezone(tz)

    # limit full time to things that happen "today"
    # and datetime.datetime.now(TIMEZONE) - thedate < datetime.timedelta(days=1)):

    if (isinstance(thedate, datetime.datetime)):
        return thedate.strftime('%B %-d, %Y %-I:%M%P %Z')
    return thedate.strftime('%B %-d, %Y')
コード例 #42
0
ファイル: facebook.py プロジェクト: mongolsamurai/redwind
def create_album(name, msg):
    current_app.logger.debug('creating new facebook album %s', name)
    resp = requests.post(
        'https://graph.facebook.com/v2.0/me/albums', data={
            'access_token': get_settings().facebook_access_token,
            'name': name,
            'message': msg,
            'privacy': json.dumps({'value': 'EVERYONE'}),
            #'privacy': json.dumps({'value': 'SELF'}),
        })
    resp.raise_for_status()
    current_app.logger.debug(
        'new facebook album response: %s, %s', resp, resp.text)
    return resp.json()['id']
コード例 #43
0
ファイル: facebook.py プロジェクト: kylewm/redwind
def create_album(name, msg):
    current_app.logger.debug("creating new facebook album %s", name)
    resp = requests.post(
        "https://graph.facebook.com/v2.0/me/albums",
        data={
            "access_token": get_settings().facebook_access_token,
            "name": name,
            "message": msg,
            "privacy": json.dumps({"value": "EVERYONE"}),
            #'privacy': json.dumps({'value': 'SELF'}),
        },
    )
    resp.raise_for_status()
    current_app.logger.debug("new facebook album response: %s, %s", resp, resp.text)
    return resp.json()["id"]
コード例 #44
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
def authorize_facebook():
    redirect_uri = url_for('.authorize_facebook', _external=True)
    params = {
        'client_id': get_settings().facebook_app_id,
        'redirect_uri': redirect_uri,
        'scope': 'publish_actions,user_photos',
    }

    code = request.args.get('code')
    if code:
        params['code'] = code
        params['client_secret'] = get_settings().facebook_app_secret

        r = urlopen('https://graph.facebook.com/oauth/access_token?'
                    + urlencode(params))
        payload = parse_qs(r.read())

        access_token = payload[b'access_token'][0].decode('ascii')
        Setting.query.get('facebook_access_token').value = access_token
        db.session.commit()
        return redirect(url_for('admin.edit_settings'))
    else:
        return redirect('https://graph.facebook.com/oauth/authorize?'
                        + urlencode(params))
コード例 #45
0
ファイル: views.py プロジェクト: mongolsamurai/redwind
def index(before_ts=None):
    post_types = [type[0] for type in POST_TYPES if type[0] != 'event']
    posts, older = collect_posts(
        post_types, before_ts, int(get_settings().posts_per_page),
        None, include_hidden=False)

    if request.args.get('feed') == 'atom':
        return render_posts_atom('Stream', 'index.atom', posts)

    resp = make_response(
        render_posts('Stream', posts, older,
                     events=collect_upcoming_events(),
                     template='home.jinja2'))

    if 'PUSH_HUB' in current_app.config:
        resp.headers.add('Link', '<{}>; rel="hub"'.format(
            current_app.config['PUSH_HUB']))
        resp.headers.add('Link', '<{}>; rel="self"'.format(
            url_for('.index', _external=True)))
    return resp
コード例 #46
0
ファイル: wordpress.py プロジェクト: TylerMorley/redwind
def try_post_like(url, post):
    current_app.logger.debug('wordpress. posting like to %s', url)
    myid = find_my_id()
    siteid, postid = find_post_id(url)
    current_app.logger.debug(
        'wordpress. posting like to site-id %d, post-id %d', siteid, postid)
    if myid and siteid and postid:
        endpoint = API_NEW_LIKE_URL.format(siteid, postid)
        current_app.logger.debug('wordpress: POST to endpoint %s', endpoint)
        r = requests.post(endpoint, headers={
            'authorization': 'Bearer ' + get_settings().wordpress_access_token,
        })
        r.raise_for_status()
        if r.json().get('success'):
            wp_url = '{}#liked-by-{}'.format(url, myid)
            post.add_syndication_url(wp_url)
            db.session.commit()
            return wp_url

        current_app.logger.error(
            'failed to post wordpress like. response: %r: %r', r, r.text)
コード例 #47
0
ファイル: admin.py プロジェクト: TylerMorley/redwind
def login():
    me = request.args.get('me')
    if not me:
        return render_template('admin/login.jinja2',
                               next=request.args.get('next'))

    # if current_app.config.get('BYPASS_INDIEAUTH'):
    #     user = auth.load_user(urllib.parse.urlparse(me).netloc)
    #     current_app.logger.debug('Logging in user %s', user)
    #     flask_login.login_user(user, remember=True)
    #     flash('logged in as {}'.format(me))
    #     current_app.logger.debug('Logged in with domain %s', me)
    #     return redirect(request.args.get('next') or url_for('views.index'))

    if not me:
        return make_response('Missing "me" parameter', 400)
    if not me.startswith('http://') and not me.startswith('https://'):
        me = 'http://' + me
    auth_url, token_url, micropub_url = discover_endpoints(me)
    if not auth_url:
        auth_url = 'https://indieauth.com/auth'

    current_app.logger.debug('Found endpoints %s, %s, %s', auth_url, token_url,
                             micropub_url)
    state = request.args.get('next')
    session['endpoints'] = (auth_url, token_url, micropub_url)

    auth_params = {
        'me': me,
        'client_id': get_settings().site_url,
        'redirect_uri': url_for('.login_callback', _external=True),
        'state': state,
    }

    # if they support micropub try to get read indie-config permission
    if token_url and micropub_url:
        auth_params['scope'] = 'config'

    return redirect('{}?{}'.format(
        auth_url, urllib.parse.urlencode(auth_params)))
コード例 #48
0
ファイル: admin.py プロジェクト: Lancey6/redwind
def login():
    me = request.args.get('me')
    if not me:
        return render_template('admin/login.jinja2',
                               next=request.args.get('next'))

    if current_app.config.get('BYPASS_INDIEAUTH'):
        user = auth.load_user(urllib.parse.urlparse(me).netloc)
        current_app.logger.debug('Logging in user %s', user)
        flask_login.login_user(user, remember=True)
        flash('logged in as {}'.format(me))
        current_app.logger.debug('Logged in with domain %s', me)
        return redirect(request.args.get('next') or url_for('views.index'))

    if not me:
        return make_response('Missing "me" parameter', 400)
    if not me.startswith('http://') and not me.startswith('https://'):
        me = 'http://' + me
    auth_url, token_url, micropub_url = discover_endpoints(me)
    if not auth_url:
        auth_url = 'https://indieauth.com/auth'

    current_app.logger.debug('Found endpoints %s, %s, %s', auth_url, token_url,
                             micropub_url)
    state = request.args.get('next')
    session['endpoints'] = (auth_url, token_url, micropub_url)

    auth_params = {
        'me': me,
        'client_id': get_settings().site_url,
        'redirect_uri': url_for('.login_callback', _external=True),
        'state': state,
    }

    # if they support micropub try to get read indie-config permission
    if token_url and micropub_url:
        auth_params['scope'] = 'config'

    return redirect('{}?{}'.format(
        auth_url, urllib.parse.urlencode(auth_params)))
コード例 #49
0
def collect_images(post):
    """collect the images (if any) that are in an <img> tag
    in the rendered post"""

    if type(post) == Post and post.attachments:
        for photo in post.attachments:
            yield photo.url

    else:
        if type(post) == Post:
            html = util.markdown_filter(post.content,
                                        img_path=post.get_image_path())
        else:
            html = post.content

        if html:
            soup = BeautifulSoup(html)
            for img in soup.find_all('img'):
                if not img.find_parent(class_='h-card'):
                    src = img.get('src')
                    if src:
                        yield urljoin(get_settings().site_url, src)
コード例 #50
0
ファイル: wordpress.py プロジェクト: TylerMorley/redwind
def try_post_reply(url, post):
    current_app.logger.debug('wordpress. posting reply to %s', url)
    myid = find_my_id()
    siteid, postid = find_post_id(url)
    current_app.logger.debug(
        'wordpress. posting reply to site-id %d, post-id %d', siteid, postid)
    if myid and siteid and postid:
        endpoint = API_NEW_REPLY_URL.format(siteid, postid)
        current_app.logger.debug('wordpress: POST to endpoint %s', endpoint)
        r = requests.post(endpoint, headers={
            'authorization': 'Bearer ' + get_settings().wordpress_access_token,
        }, data={
            'content': post.content_html,
        })
        r.raise_for_status()
        wp_url = r.json().get('URL')
        if wp_url:
            post.add_syndication_url(wp_url)
            db.session.commit()
            return wp_url

        current_app.logger.error(
            'failed to post wordpress reply. response: %r: %r', r, r.text)
コード例 #51
0
def get_auth():
    return OAuth1(
        client_key=get_settings().twitter_api_key,
        client_secret=get_settings().twitter_api_secret,
        resource_owner_key=get_settings().twitter_oauth_token,
        resource_owner_secret=get_settings().twitter_oauth_token_secret)
コード例 #52
0
def is_twitter_authorized():
    return (get_settings().twitter_oauth_token
            and get_settings().twitter_oauth_token_secret)
コード例 #53
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
def handle_new_or_edit(post, message, link, name, picture,
                       is_photo, album_id):
    current_app.logger.debug('publishing to facebook')

    # TODO I cannot figure out how to tag people via the FB API

    post_args = {
        'access_token': get_settings().facebook_access_token,
        'message': message.strip(),
        'privacy': json.dumps({'value': 'EVERYONE'}),
        #'privacy': json.dumps({'value': 'SELF'}),
    }

    if is_photo and picture:
        post_args['url'] = picture
        current_app.logger.debug(
            'Sending photo %s to album %s', post_args, album_id)
        response = requests.post(
            'https://graph.facebook.com/v2.0/{}/photos'.format(
                album_id if album_id else 'me'),
            data=post_args)
    else:
        post_args.update(util.trim_nulls({
            'link': link,
            'name': name,
            'picture': picture,
        }))
        current_app.logger.debug('Sending post %s', post_args)
        response = requests.post('https://graph.facebook.com/v2.0/me/feed',
                                 data=post_args)
    response.raise_for_status()
    current_app.logger.debug("Got response from facebook %s", response)

    if 'json' in response.headers['content-type']:
        result = response.json()

    current_app.logger.debug(
        'published to facebook. response {}'.format(result))

    if result:
        if is_photo:
            facebook_photo_id = result['id']
            facebook_post_id = result['post_id']  # actually the album

            split = facebook_post_id.split('_', 1)
            if split and len(split) == 2:
                user_id, post_id = split
                fb_url = 'https://facebook.com/{}/posts/{}'.format(
                    user_id, facebook_photo_id)
                post.add_syndication_url(fb_url)
                return fb_url

        else:
            facebook_post_id = result['id']
            split = facebook_post_id.split('_', 1)
            if split and len(split) == 2:
                user_id, post_id = split
                fb_url = 'https://facebook.com/{}/posts/{}'.format(
                    user_id, post_id)
                post.add_syndication_url(fb_url)
                return fb_url
コード例 #54
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
def inject_settings_variable():
    return {
        'settings': get_settings()
    }
コード例 #55
0
ファイル: facebook.py プロジェクト: TylerMorley/redwind
def is_facebook_authorized():
    return get_settings().facebook_access_token