Esempio n. 1
0
def test_send_wms(client, mocker):
    getter = mocker.patch('requests.get')
    poster = mocker.patch('requests.post')
    urlopen = mocker.patch('urllib.request.urlopen')

    post = Post('note')
    post.content = 'This note links to [wikipedia](https://en.wikipedia.org/wiki/Webmention)'
    post.content_html = 'This note links to <a href="https://en.wikipedia.org/wiki/Webmention">wikipedia</a>'
    post.path = '2014/11/wm-sender-test'
    db.session.add(post)
    db.session.commit()

    urlopen.return_value = FakeUrlOpen(
        info=FakeUrlMetadata(content_type='text/html', content_length=256))

    getter.return_value = FakeResponse(text="""<!DOCTYPE html>
    <html>
      <link rel="webmention" href="https://en.wikipedia.org/endpoint">
    </html>""")

    wm_sender.do_send_webmentions(post.id)

    getter.assert_called_with('https://en.wikipedia.org/wiki/Webmention')
    poster.assert_called_with('https://en.wikipedia.org/endpoint', data={
        'source': post.permalink,
        'target': 'https://en.wikipedia.org/wiki/Webmention',
    }, headers={
        'content-type': 'application/x-www-form-urlencoded',
        'accept': 'application/json',
    })
Esempio n. 2
0
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"))
Esempio n. 3
0
def source_post(app, db):
    post = Post('note')
    post.content = 'This note links to [wikipedia](https://en.wikipedia.org/wiki/Webmention)'
    post.content_html = 'This note links to <a href="https://en.wikipedia.org/wiki/Webmention">wikipedia</a>'
    post.path = '2014/11/wm-sender-test'
    db.session.add(post)
    db.session.commit()
    return post
Esempio n. 4
0
def source_post(app, db):
    post = Post('note')
    post.content = 'This note links to [wikipedia](https://en.wikipedia.org/wiki/Webmention)'
    post.content_html = 'This note links to <a href="https://en.wikipedia.org/wiki/Webmention">wikipedia</a>'
    post.path = '2014/11/wm-sender-test'
    db.session.add(post)
    db.session.commit()
    return post
Esempio n. 5
0
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'))
Esempio n. 6
0
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'))
Esempio n. 7
0
def edit_by_id():
    id = request.args.get('id')
    if not id:
        abort(404)
    post = Post.load_by_id(id)
    if not post:
        abort(404)
    type = 'post'
    if not request.args.get('advanced') and post.post_type:
        type = post.post_type

    if post.draft:
        button_text = {
            'publish': 'Publish Draft',
            'publish_quietly': 'Publish Draft Quietly',
            'publish+tweet': 'Publish Draft & Tweet',
            'save_draft': 'Resave Draft',
        }
    else:
        button_text = {
            'publish': 'Republish',
            'publish_quietly': 'Republish Quietly',
            'publish+tweet': 'Republish & Tweet',
            'save_draft': 'Unpublish, Save as Draft',
        }

    template = 'admin/edit_' + type + '.jinja2'
    if request.args.get('full'):
        template = 'admin/edit_post_all.jinja2'

    venues = Venue.query.order_by(Venue.name).all()
    return render_template(template, edit_type='edit', post=post,
                           tags=get_tags(), top_tags=get_top_tags(20),
                           people=get_contact_nicks(),
                           button_text=button_text, venues=venues)
Esempio n. 8
0
def do_send_to_twitter(post_id, app_config):
    with async_app_context(app_config):
        current_app.logger.debug('auto-posting to twitter for %s', post_id)
        post = Post.load_by_id(post_id)

        in_reply_to, repost_of, like_of = util.posse_post_discovery(
            post, PERMALINK_RE)

        # cowardly refuse to auto-POSSE a reply/repost/like when the
        # target tweet is not found.
        if post.in_reply_to and not in_reply_to:
            current_app.logger.warn('could not find tweet to reply to for %s',
                                    post.in_reply_to)
            return None
        elif post.repost_of and not repost_of:
            current_app.logger.warn('could not find tweet to repost for %s',
                                    post.repost_of)
            preview, img_url = guess_raw_share_tweet_content(post)
        elif post.like_of and not like_of:
            current_app.logger.warn('could not find tweet to like for %s',
                                    post.like_of)
            return None
        else:
            preview, img_url = guess_tweet_content(post, in_reply_to)

        response = do_tweet(post_id, preview, img_url, in_reply_to, repost_of,
                            like_of)
        return str(response)
Esempio n. 9
0
def do_send_to_twitter(post_id, app_config):
    with async_app_context(app_config):
        current_app.logger.debug('auto-posting to twitter for %s', post_id)
        post = Post.load_by_id(post_id)

        in_reply_to, repost_of, like_of = util.posse_post_discovery(
            post, PERMALINK_RE)

        # cowardly refuse to auto-POSSE a reply/repost/like when the
        # target tweet is not found.
        if post.in_reply_to and not in_reply_to:
            current_app.logger.warn(
                'could not find tweet to reply to for %s', post.in_reply_to)
            return None
        elif post.repost_of and not repost_of:
            current_app.logger.warn(
                'could not find tweet to repost for %s', post.repost_of)
            preview, img_url = guess_raw_share_tweet_content(post)
        elif post.like_of and not like_of:
            current_app.logger.warn(
                'could not find tweet to like for %s', post.like_of)
            return None
        else:
            preview, img_url = guess_tweet_content(post, in_reply_to)

        response = do_tweet(post_id, preview, img_url, in_reply_to, repost_of,
                            like_of)
        return str(response)
Esempio n. 10
0
def post_associated_file_by_historic_path(post_type, year, month, day, index,
                                          filename):
    post = Post.load_by_historic_path('{}/{}/{:02d}/{:02d}/{}'.format(
        post_type, year, month, day, index))
    if not post:
        abort(404)
    return redirect('/{}/files/{}'.format(post.path, filename))
Esempio n. 11
0
def post_associated_file_by_historic_path(post_type, year, month, day,
                                          index, filename):
    post = Post.load_by_historic_path('{}/{}/{:02d}/{:02d}/{}'.format(
        post_type, year, month, day, index))
    if not post:
        abort(404)
    return redirect('/{}/files/{}'.format(post.path, filename))
Esempio n. 12
0
def do_send_to_wordpress(post_id, app_config):
    with async_app_context(app_config):
        post = Post.load_by_id(post_id)

        if post.like_of:
            for url in post.like_of:
                try_post_like(url, post)

        elif post.in_reply_to:
            for url in post.in_reply_to:
                try_post_reply(url, post)
Esempio n. 13
0
def do_reverse_geocode_post(postid, app_config):
    with async_app_context(app_config):
        post = Post.load_by_id(postid)
        if post.location and 'latitude' in post.location \
           and 'longitude' in post.location:
            adr = do_reverse_geocode(post.location['latitude'],
                                     post.location['longitude'])
            # copy the dict so that the ORM recognizes
            # that it changed
            post.location = dict(post.location)
            post.location.update(adr)
            db.session.commit()
Esempio n. 14
0
def delete_by_id():
    id = request.args.get('id')
    post = Post.load_by_id(id)
    if not post:
        abort(404)
    post.deleted = True
    db.session.commit()

    hooks.fire('post-deleted', post, request.args)
    redirect_url = request.args.get('redirect') or url_for('views.index')
    current_app.logger.debug('redirecting to {}'.format(redirect_url))
    return redirect(redirect_url)
Esempio n. 15
0
def delete_by_id():
    id = request.args.get('id')
    post = Post.load_by_id(id)
    if not post:
        abort(404)
    post.deleted = True
    db.session.commit()

    hooks.fire('post-deleted', post, request.args)
    redirect_url = request.args.get('redirect') or url_for('views.index')
    current_app.logger.debug('redirecting to {}'.format(redirect_url))
    return redirect(redirect_url)
Esempio n. 16
0
def do_reverse_geocode_post(postid, app_config):
    with async_app_context(app_config):
        post = Post.load_by_id(postid)
        if not post:
            return
        if post.location and 'latitude' in post.location \
           and 'longitude' in post.location:
            adr = do_reverse_geocode(post.location['latitude'],
                                     post.location['longitude'])
            # copy the dict so that the ORM recognizes
            # that it changed
            post.location = dict(post.location)
            post.location.update(adr)
            db.session.commit()
Esempio n. 17
0
def do_send_to_facebook(post_id, app_config):
    with async_app_context(app_config):
        current_app.logger.debug("auto-posting to facebook for %s", post_id)
        post = Post.load_by_id(post_id)

        message, link, name, picture = guess_content(post)
        facebook_url = handle_new_or_edit(post, message, link, name, picture, post.post_type == "photo", album_id=None)
        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)
Esempio n. 18
0
def do_send_to_facebook(post_id, app_config):
    with async_app_context(app_config):
        current_app.logger.debug('auto-posting to facebook for %s', post_id)
        post = Post.load_by_id(post_id)

        message, link, name, picture = guess_content(post)
        facebook_url = handle_new_or_edit(post, message, link, name, picture,
                                          post.post_type == 'photo',
                                          album_id=None)
        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)
Esempio n. 19
0
def do_tweet(post_id, preview, img_url, in_reply_to, repost_of, like_of):
    try:
        post = Post.load_by_id(post_id)
        twitter_url = handle_new_or_edit(post, preview, img_url, in_reply_to,
                                         repost_of, like_of)
        db.session.commit()

        if has_request_context():
            flash('Shared on Twitter: <a href="{}">Original</a>, '
                  '<a href="{}">On Twitter</a>'.format(post.permalink,
                                                       twitter_url))
            return redirect(post.permalink)

    except Exception as e:
        current_app.logger.exception('posting to twitter')
        if has_request_context():
            flash('Share on Twitter Failed!. Exception: {}'.format(e))
            return redirect(url_for('views.index'))
Esempio n. 20
0
def new_post(type):
    if type not in util.POST_TYPES:
        abort(404)

    post = Post(type)
    post.published = post.updated = datetime.datetime.utcnow()
    post.content = ''

    if type == 'reply':
        in_reply_to = request.args.get('url')
        if in_reply_to:
            post.in_reply_to = [in_reply_to]

    elif type == 'share':
        repost_of = request.args.get('url')
        if repost_of:
            post.repost_of = [repost_of]

    elif type == 'like':
        like_of = request.args.get('url')
        if like_of:
            post.like_of = [like_of]

    elif type == 'bookmark':
        bookmark_of = request.args.get('url')
        if bookmark_of:
            post.bookmark_of = [bookmark_of]

    post.content = request.args.get('content')
    button_text = {
        'publish': 'Publish',
        'publish_quietly': 'Publish Quietly',
        'publish+tweet': 'Publish & Tweet',
        'save_draft': 'Save as Draft',
    }

    venues = Venue.query.order_by(Venue.name).all()
    return render_template('admin/edit_' + type + '.jinja2',
                           edit_type='new', post=post,
                           tags=get_tags(), top_tags=get_top_tags(20),
                           people=get_contact_nicks(),
                           button_text=button_text, venues=venues)
Esempio n. 21
0
def share_on_twitter():
    if request.method == 'GET':
        id = request.args.get('id')
        if not id:
            abort(404)

        post = Post.load_by_id(id)
        if not post:
            abort(404)

        current_app.logger.debug('sharing on twitter. post: %s', post)

        in_reply_to, repost_of, like_of \
            = util.posse_post_discovery(post, PERMALINK_RE)

        current_app.logger.debug(
            'discovered in-reply-to: %s, repost-of: %s, like-of: %s',
            in_reply_to, repost_of, like_of)

        if post.repost_of and not repost_of:
            preview, _ = guess_raw_share_tweet_content(post)
            imgs = list(collect_images(post.repost_contexts[0]))
        else:
            preview, _ = guess_tweet_content(post, in_reply_to)
            imgs = list(collect_images(post))

        current_app.logger.debug('twitter post has images: %s', imgs)

        return render_template('admin/share_on_twitter.jinja2',
                               preview=preview,
                               post=post,
                               in_reply_to=in_reply_to,
                               repost_of=repost_of,
                               like_of=like_of,
                               imgs=imgs)

    post_id = request.form.get('post_id')
    preview = request.form.get('preview')
    img_url = request.form.get('img')
    in_reply_to = request.form.get('in_reply_to')
    repost_of = request.form.get('repost_of')
    like_of = request.form.get('like_of')

    return do_tweet(post_id, preview, img_url, in_reply_to, repost_of, like_of)
Esempio n. 22
0
def new_post(type):
    post = Post(type)
    post.published = post.updated = datetime.datetime.utcnow()
    post.content = ''

    if type == 'reply':
        in_reply_to = request.args.get('url')
        if in_reply_to:
            post.in_reply_to = [in_reply_to]
            # post.reply_contexts = [contexts.create_context(in_reply_to)]

    elif type == 'share':
        repost_of = request.args.get('url')
        if repost_of:
            post.repost_of = [repost_of]
            # post.repost_contexts = [contexts.create_context(repost_of)]

    elif type == 'like':
        like_of = request.args.get('url')
        if like_of:
            post.like_of = [like_of]
            # post.like_contexts = [contexts.create_context(like_of)]

    elif type == 'bookmark':
        bookmark_of = request.args.get('url')
        if bookmark_of:
            post.bookmark_of = [bookmark_of]
            # post.bookmark_contexts = [contexts.create_context(bookmark_of)]

    post.content = request.args.get('content')
    button_text = {
        'publish': 'Publish',
        'publish_quietly': 'Publish Quietly',
        'publish+tweet': 'Publish & Tweet',
        'save_draft': 'Save as Draft',
    }

    if type == 'event':
        venues = Venue.query.order_by(Venue.name).all()
    else:
        venues = []

    return render_template('admin/edit_' + type + '.jinja2',
                           edit_type='new', post=post,
                           tags=get_tags(), top_tags=get_top_tags(20),
                           button_text=button_text, venues=venues)
Esempio n. 23
0
def do_tweet(post_id, preview, img_url, in_reply_to,
             repost_of, like_of):
    try:
        post = Post.load_by_id(post_id)
        twitter_url = handle_new_or_edit(
            post, preview, img_url, in_reply_to, repost_of, like_of)
        db.session.commit()

        if has_request_context():
            flash('Shared on Twitter: <a href="{}">Original</a>, '
                  '<a href="{}">On Twitter</a>'
                  .format(post.permalink, twitter_url))
            return redirect(post.permalink)

    except Exception as e:
        current_app.logger.exception('posting to twitter')
        if has_request_context():
            flash('Share on Twitter Failed!. Exception: {}'.format(e))
            return redirect(url_for('views.index'))
Esempio n. 24
0
def share_on_twitter():
    if request.method == 'GET':
        id = request.args.get('id')
        if not id:
            abort(404)

        post = Post.load_by_id(id)
        if not post:
            abort(404)

        current_app.logger.debug('sharing on twitter. post: %s', post)

        in_reply_to, repost_of, like_of \
            = util.posse_post_discovery(post, PERMALINK_RE)

        current_app.logger.debug(
            'discovered in-reply-to: %s, repost-of: %s, like-of: %s',
            in_reply_to, repost_of, like_of)

        if post.repost_of and not repost_of:
            preview, _ = guess_raw_share_tweet_content(post)
            imgs = list(collect_images(post.repost_contexts[0]))
        else:
            preview, _ = guess_tweet_content(post, in_reply_to)
            imgs = list(collect_images(post))

        current_app.logger.debug('twitter post has images: %s', imgs)

        return render_template('admin/share_on_twitter.jinja2',
                               preview=preview,
                               post=post, in_reply_to=in_reply_to,
                               repost_of=repost_of, like_of=like_of, imgs=imgs)

    post_id = request.form.get('post_id')
    preview = request.form.get('preview')
    img_url = request.form.get('img')
    in_reply_to = request.form.get('in_reply_to')
    repost_of = request.form.get('repost_of')
    like_of = request.form.get('like_of')

    return do_tweet(post_id, preview, img_url, in_reply_to, repost_of,
                    like_of)
Esempio n. 25
0
def send_webmentions_manually():
    id = request.args.get('id')
    post = Post.load_by_id(id)
    return jsonify({
        'mentions': handle_new_or_edit(post),
    })
Esempio n. 26
0
def find_target_post(target_url):
    current_app.logger.debug("looking for target post at %s", target_url)

    # follow redirects if necessary
    redirect_url = urllib.request.urlopen(target_url).geturl()
    if redirect_url and redirect_url != target_url:
        current_app.logger.debug("followed redirection to %s", redirect_url)
        target_url = redirect_url

    parsed_url = urllib.parse.urlparse(target_url)

    if not parsed_url:
        current_app.logger.warn("Could not parse target_url of received webmention: %s", target_url)
        return None

    try:
        # FIXME this is a less-than-perfect fix for hosting from a
        # subdirectory. The url_map may have some clever work-around.
        parsed_site_root = urllib.parse.urlparse(get_settings().site_url)
        site_prefix = parsed_site_root.path
        if site_prefix.endswith("/"):
            site_prefix = site_prefix[:-1]
        if not parsed_url.path.startswith(parsed_site_root.path):
            raise NotFound

        urls = current_app.url_map.bind(get_settings().site_url)
        path = parsed_url.path[len(site_prefix) :]
        current_app.logger.debug("target path with no prefix %s", path)
        endpoint, args = urls.match(path)
        current_app.logger.debug("found match for target url %r: %r", endpoint, args)
    except NotFound:
        current_app.logger.warn("Webmention could not find target for %s", parsed_url.path)
        return None

    post = None
    if endpoint == "views.post_by_path":
        year = args.get("year")
        month = args.get("month")
        slug = args.get("slug")
        post = Post.load_by_path("{}/{:02d}/{}".format(year, month, slug))

    elif endpoint == "views.post_by_date":
        post_type = args.get("post_type")
        year = args.get("year")
        month = args.get("month")
        day = args.get("day")
        index = args.get("index")
        post = Post.load_by_date(post_type, year, month, day, index)

    elif endpoint == "views.post_by_old_date":
        post_type = args.get("post_type")
        yymmdd = args.get("yymmdd")
        year = int("20" + yymmdd[0:2])
        month = int(yymmdd[2:4])
        day = int(yymmdd[4:6])
        post = Post.load_by_date(post_type, year, month, day, index)

    elif endpoint == "views.post_by_id":
        dbid = args.get("dbid")
        post = Post.load_by_id(dbid)

    if not post:
        current_app.logger.warn("Webmention target points to unknown post: {}".format(args)),

    return post
Esempio n. 27
0
def post_by_short_path(tag, tail):
    post = Post.load_by_short_path('{}/{}'.format(tag, tail))
    if not post:
        abort(404)
    return redirect(post.permalink)
Esempio n. 28
0
def post_attachment(year, month, slug, filename):
    post = Post.load_by_path('{}/{:02d}/{}'.format(year, month, slug))
    return render_attachment(post, filename)
Esempio n. 29
0
def post_attachment(year, month, slug, filename):
    post = Post.load_by_path('{}/{:02d}/{}'.format(year, month, slug))
    return render_attachment(post, filename)
Esempio n. 30
0
def post_by_path(year, month, slug):
    post = Post.load_by_path('{}/{:02d}/{}'.format(year, month, slug))
    return render_post(post)
Esempio n. 31
0
def save_post(post):
    was_draft = post.draft
    pub_str = request.form.get('published')
    if pub_str:
        post.published = mf2util.parse_dt(pub_str)

    start_str = request.form.get('start')
    if start_str:
        start = mf2util.parse_dt(start_str)
        if start:
            post.start = start
            post.start_utcoffset = start.utcoffset()

    end_str = request.form.get('end')
    if end_str:
        end = mf2util.parse_dt(end_str)
        if end:
            post.end = end
            post.end_utcoffset = end.utcoffset()

    now = datetime.datetime.utcnow()
    if not post.published or was_draft:
        post.published = now
    post.updated = now

    # populate the Post object and save it to the database,
    # redirect to the view
    post.title = request.form.get('title', '')
    post.content = request.form.get('content')
    post.draft = request.form.get('action') == 'save_draft'
    post.hidden = request.form.get('hidden', 'false') == 'true'

    venue_name = request.form.get('new_venue_name')
    venue_lat = request.form.get('new_venue_latitude')
    venue_lng = request.form.get('new_venue_longitude')
    if venue_name and venue_lat and venue_lng:
        venue = Venue()
        venue.name = venue_name
        venue.location = {
            'latitude': float(venue_lat),
            'longitude': float(venue_lng),
        }
        venue.update_slug('{}-{}'.format(venue_lat, venue_lng))
        db.session.add(venue)
        db.session.commit()
        hooks.fire('venue-saved', venue, request.form)
        post.venue = venue

    else:
        venue_id = request.form.get('venue')
        if venue_id:
            post.venue = Venue.query.get(venue_id)

    lat = request.form.get('latitude')
    lon = request.form.get('longitude')
    if lat and lon:
        if post.location is None:
            post.location = {}

        post.location['latitude'] = float(lat)
        post.location['longitude'] = float(lon)
        loc_name = request.form.get('location_name')
        if loc_name is not None:
            post.location['name'] = loc_name
    else:
        post.location = None

    for url_attr, context_attr in (('in_reply_to', 'reply_contexts'),
                                   ('repost_of', 'repost_contexts'),
                                   ('like_of', 'like_contexts'),
                                   ('bookmark_of', 'bookmark_contexts')):
        url_str = request.form.get(url_attr)
        if url_str is not None:
            urls = util.multiline_string_to_list(url_str)
            setattr(post, url_attr, urls)

    # fetch contexts before generating a slug
    contexts.fetch_contexts(post)

    syndication = request.form.get('syndication')
    if syndication is not None:
        post.syndication = util.multiline_string_to_list(syndication)

    audience = request.form.get('audience')
    if audience is not None:
        post.audience = util.multiline_string_to_list(audience)

    tags = request.form.getlist('tags')
    if post.post_type != 'article' and post.content:
        # parse out hashtags as tag links from note-like posts
        tags += util.find_hashtags(post.content)
    tags = list(filter(None, map(util.normalize_tag, tags)))
    post.tags = [Tag.query.filter_by(name=tag).first() or Tag(tag)
                 for tag in tags]

    slug = request.form.get('slug')
    if slug:
        post.slug = util.slugify(slug)
    elif not post.slug or was_draft:
        post.slug = post.generate_slug()

    # events should use their start date for permalinks
    path_date = post.start or post.published

    if post.draft:
        m = hashlib.md5()
        m.update(bytes(path_date.isoformat() + '|' + post.slug,
                       'utf-8'))
        post.path = 'drafts/{}'.format(m.hexdigest())

    elif not post.path or was_draft:
        base_path = '{}/{:02d}/{}'.format(
            path_date.year, path_date.month, post.slug)
        # generate a unique path
        unique_path = base_path
        idx = 1
        while Post.load_by_path(unique_path):
            unique_path = '{}-{}'.format(base_path, idx)
            idx += 1
        post.path = unique_path

    # generate short path
    if not post.short_path:
        short_base = '{}/{}'.format(
            util.tag_for_post_type(post.post_type),
            util.base60_encode(util.date_to_ordinal(path_date)))
        short_paths = set(
            row[0] for row in db.session.query(Post.short_path).filter(
                Post.short_path.startswith(short_base)).all())
        for idx in itertools.count(1):
            post.short_path = short_base + util.base60_encode(idx)
            if post.short_path not in short_paths:
                break

    infiles = request.files.getlist('files') + request.files.getlist('photo')
    current_app.logger.debug('infiles: %s', infiles)
    for infile in infiles:
        if infile and infile.filename:
            current_app.logger.debug('receiving uploaded file %s', infile)
            attachment = create_attachment_from_file(post, infile)
            os.makedirs(os.path.dirname(attachment.disk_path), exist_ok=True)
            infile.save(attachment.disk_path)
            post.attachments.append(attachment)

    # pre-render the post html
    html = util.markdown_filter(post.content, img_path=post.get_image_path())
    html = util.autolink(html)
    if post.post_type == 'article':
        html = util.process_people_to_microcards(html)
    else:
        html = util.process_people_to_at_names(html)
    post.content_html = html

    if not post.id:
        db.session.add(post)
    db.session.commit()

    current_app.logger.debug('saved post %d %s', post.id, post.permalink)
    redirect_url = post.permalink

    hooks.fire('post-saved', post, request.form)
    return redirect(redirect_url)
import os
import json
from redwind import app
from redwind.models import Post


if __name__ == '__main__':
    obj = {}
    for post in Post.iterate_all():
        if post.facebook_url:
            obj[post.facebook_url] = post.path
        if post.twitter_url:
            obj[post.twitter_url] = post.path

    with open(os.path.join(app.root_path, '_data/syndication_index'), 'w') as f:
        json.dump(obj, f, indent=True)

Esempio n. 33
0
def post_by_date(post_type, year, month, day, index, slug):
    post = Post.load_by_historic_path('{}/{}/{:02d}/{:02d}/{}'.format(
        post_type, year, month, day, index))
    if not post:
        abort(404)
    return redirect(post.permalink)
Esempio n. 34
0
def post_by_date(post_type, year, month, day, index, slug):
    post = Post.load_by_historic_path('{}/{}/{:02d}/{:02d}/{}'.format(
        post_type, year, month, day, index))
    if not post:
        abort(404)
    return redirect(post.permalink)
Esempio n. 35
0
def find_target_post(target_url):
    current_app.logger.debug("looking for target post at %s", target_url)

    # follow redirects if necessary
    redirect_url = urllib.request.urlopen(target_url).geturl()
    if redirect_url and redirect_url != target_url:
        current_app.logger.debug("followed redirection to %s", redirect_url)
        target_url = redirect_url

    parsed_url = urllib.parse.urlparse(target_url)

    if not parsed_url:
        current_app.logger.warn(
            "Could not parse target_url of received webmention: %s",
            target_url)
        return None

    try:
        # FIXME this is a less-than-perfect fix for hosting from a
        # subdirectory. The url_map may have some clever work-around.
        parsed_site_root = urllib.parse.urlparse(get_settings().site_url)
        site_prefix = parsed_site_root.path
        if site_prefix.endswith('/'):
            site_prefix = site_prefix[:-1]
        if not parsed_url.path.startswith(parsed_site_root.path):
            raise NotFound

        urls = current_app.url_map.bind(get_settings().site_url)
        path = parsed_url.path[len(site_prefix):]
        current_app.logger.debug('target path with no prefix %s', path)
        endpoint, args = urls.match(path)
        current_app.logger.debug('found match for target url %r: %r', endpoint,
                                 args)
    except NotFound:
        current_app.logger.warn('Webmention could not find target for %s',
                                parsed_url.path)
        return None

    post = None
    if endpoint == 'views.post_by_path':
        year = args.get('year')
        month = args.get('month')
        slug = args.get('slug')
        post = Post.load_by_path('{}/{:02d}/{}'.format(year, month, slug))

    elif endpoint == 'views.post_by_date':
        post_type = args.get('post_type')
        year = args.get('year')
        month = args.get('month')
        day = args.get('day')
        index = args.get('index')
        post = Post.load_by_date(post_type, year, month, day, index)

    elif endpoint == 'views.post_by_old_date':
        post_type = args.get('post_type')
        yymmdd = args.get('yymmdd')
        year = int('20' + yymmdd[0:2])
        month = int(yymmdd[2:4])
        day = int(yymmdd[4:6])
        post = Post.load_by_date(post_type, year, month, day, index)

    elif endpoint == 'views.post_by_id':
        dbid = args.get('dbid')
        post = Post.load_by_id(dbid)

    if not post:
        current_app.logger.warn(
            "Webmention target points to unknown post: {}".format(args)),

    return post
Esempio n. 36
0
def draft_by_hash(hash):
    post = Post.load_by_path('drafts/{}'.format(hash))
    return render_post(post)
Esempio n. 37
0
def save_post(post):
    was_draft = post.draft
    pub_str = request.form.get('published')
    if pub_str:
        post.published = mf2util.parse_dt(pub_str)
        if post.published.tzinfo:
            post.published = post.published.astimezone(datetime.timezone.utc)\
                                           .replace(tzinfo=None)

    if 'post_type' in request.form:
        post.post_type = request.form.get('post_type')

    start_str = request.form.get('start')
    if start_str:
        start = mf2util.parse_dt(start_str)
        if start:
            post.start = start
            post.start_utcoffset = start.utcoffset()

    end_str = request.form.get('end')
    if end_str:
        end = mf2util.parse_dt(end_str)
        if end:
            post.end = end
            post.end_utcoffset = end.utcoffset()

    now = datetime.datetime.utcnow()
    if not post.published or was_draft:
        post.published = now
    post.updated = now

    # populate the Post object and save it to the database,
    # redirect to the view
    post.title = request.form.get('title', '')
    post.content = request.form.get('content')
    post.draft = request.form.get('action') == 'save_draft'
    post.hidden = request.form.get('hidden', 'false') == 'true'
    post.friends_only = request.form.get('friends_only', 'false') == 'true'

    venue_name = request.form.get('new_venue_name')
    venue_lat = request.form.get('new_venue_latitude')
    venue_lng = request.form.get('new_venue_longitude')
    if venue_name and venue_lat and venue_lng:
        venue = Venue()
        venue.name = venue_name
        venue.location = {
            'latitude': float(venue_lat),
            'longitude': float(venue_lng),
        }
        venue.update_slug('{}-{}'.format(venue_lat, venue_lng))
        db.session.add(venue)
        db.session.commit()
        hooks.fire('venue-saved', venue, request.form)
        post.venue = venue

    else:
        venue_id = request.form.get('venue')
        if venue_id:
            post.venue = Venue.query.get(venue_id)

    lat = request.form.get('latitude')
    lon = request.form.get('longitude')
    if lat and lon:
        if post.location is None:
            post.location = {}

        post.location['latitude'] = float(lat)
        post.location['longitude'] = float(lon)
        loc_name = request.form.get('location_name')
        if loc_name is not None:
            post.location['name'] = loc_name
    else:
        post.location = None

    for url_attr, context_attr in (('in_reply_to', 'reply_contexts'),
                                   ('repost_of', 'repost_contexts'),
                                   ('like_of', 'like_contexts'),
                                   ('bookmark_of', 'bookmark_contexts')):
        url_str = request.form.get(url_attr)
        if url_str is not None:
            urls = util.multiline_string_to_list(url_str)
            setattr(post, url_attr, urls)

    # fetch contexts before generating a slug
    contexts.fetch_contexts(post)

    if 'item-name' in request.form:
        post.item = util.trim_nulls({
            'name': request.form.get('item-name'),
            'author': request.form.get('item-author'),
            'photo': request.form.get('item-photo'),
        })
    if 'rating' in request.form:
        rating = request.form.get('rating')
        post.rating = int(rating) if rating else None

    syndication = request.form.get('syndication')
    if syndication is not None:
        post.syndication = util.multiline_string_to_list(syndication)

    audience = request.form.get('audience')
    if audience is not None:
        post.audience = util.multiline_string_to_list(audience)

    tags = request.form.getlist('tags')
    if post.post_type != 'article' and post.content:
        # parse out hashtags as tag links from note-like posts
        tags += util.find_hashtags(post.content)
    tags = list(filter(None, map(util.normalize_tag, tags)))
    post.tags = [Tag.query.filter_by(name=tag).first() or Tag(tag)
                 for tag in tags]

    post.people = []
    people = request.form.getlist('people')
    for person in people:
        nick = Nick.query.filter_by(name=person).first()
        if nick:
            post.people.append(nick.contact)

    slug = request.form.get('slug')
    if slug:
        post.slug = util.slugify(slug)
    elif not post.slug or was_draft:
        post.slug = post.generate_slug()

    # events should use their start date for permalinks
    path_date = post.start or post.published

    if post.draft:
        m = hashlib.md5()
        m.update(bytes(path_date.isoformat() + '|' + post.slug,
                       'utf-8'))
        post.path = 'drafts/{}'.format(m.hexdigest())

    elif not post.path or was_draft:
        base_path = '{}/{:02d}/{}'.format(
            path_date.year, path_date.month, post.slug)
        # generate a unique path
        unique_path = base_path
        idx = 1
        while Post.load_by_path(unique_path):
            unique_path = '{}-{}'.format(base_path, idx)
            idx += 1
        post.path = unique_path

    # generate short path
    if not post.short_path:
        short_base = '{}/{}'.format(
            util.tag_for_post_type(post.post_type),
            util.base60_encode(util.date_to_ordinal(path_date)))
        short_paths = set(
            row[0] for row in db.session.query(Post.short_path).filter(
                Post.short_path.startswith(short_base)).all())
        for idx in itertools.count(1):
            post.short_path = short_base + util.base60_encode(idx)
            if post.short_path not in short_paths:
                break

    infiles = request.files.getlist('files') + request.files.getlist('photo')
    current_app.logger.debug('infiles: %s', infiles)
    for infile in infiles:
        if infile and infile.filename:
            current_app.logger.debug('receiving uploaded file %s', infile)
            attachment = create_attachment_from_file(post, infile)
            os.makedirs(os.path.dirname(attachment.disk_path), exist_ok=True)
            infile.save(attachment.disk_path)
            post.attachments.append(attachment)

    photo_url = request.form.get('photo')
    if photo_url:
        current_app.logger.debug('downloading photo from url %s', photo_url)
        temp_filename, headers = urllib.request.urlretrieve(photo_url)
        content_type = headers.get('content-type', '')
        mimetype = content_type and content_type.split(';')[0].strip()
        filename = os.path.basename(urllib.parse.urlparse(photo_url).path)
        attachment = create_attachment(post, filename, mimetype)
        os.makedirs(os.path.dirname(attachment.disk_path), exist_ok=True)
        shutil.copyfile(temp_filename, attachment.disk_path)
        urllib.request.urlcleanup()
        post.attachments.append(attachment)

    # pre-render the post html
    html = util.markdown_filter(post.content, img_path=post.get_image_path())
    html = util.autolink(html)
    if post.post_type == 'article':
        html = util.process_people_to_microcards(html)
    else:
        html = util.process_people_to_at_names(html)
    post.content_html = html

    if not post.id:
        db.session.add(post)
    db.session.commit()

    current_app.logger.debug('saved post %d %s', post.id, post.permalink)
    redirect_url = post.permalink

    hooks.fire('post-saved', post, request.form)
    return redirect(redirect_url)
Esempio n. 38
0
def draft_by_hash(hash):
    post = Post.load_by_path('drafts/{}'.format(hash))
    return render_post(post)
Esempio n. 39
0
def save_edit():
    id = request.form.get('post_id')
    current_app.logger.debug('saving post %s', id)
    post = Post.load_by_id(id)
    return save_post(post)
Esempio n. 40
0
def draft_attachment(hash, filename):
    post = Post.load_by_path('drafts/{}'.format(hash))
    return render_attachment(post, filename)
Esempio n. 41
0
def do_send_webmentions(post_id, app_config):
    with async_app_context(app_config):
        current_app.logger.debug("sending mentions for {}".format(post_id))
        post = Post.load_by_id(post_id)
        if post:
            return handle_new_or_edit(post)
Esempio n. 42
0
def save_edit():
    id = request.form.get('post_id')
    current_app.logger.debug('saving post %s', id)
    post = Post.load_by_id(id)
    return save_post(post)
Esempio n. 43
0
def save_new():
    post_type = request.form.get('post_type', 'note')
    current_app.logger.debug('saving new post of type %s', post_type)
    post = Post(post_type)
    return save_post(post)
Esempio n. 44
0
def draft_attachment(hash, filename):
    post = Post.load_by_path('drafts/{}'.format(hash))
    return render_attachment(post, filename)
Esempio n. 45
0
def post_by_short_path(tag, tail):
    post = Post.load_by_short_path('{}/{}'.format(tag, tail))
    if not post:
        abort(404)
    return redirect(post.permalink)
Esempio n. 46
0
def post_by_path(year, month, slug):
    post = Post.load_by_path('{}/{:02d}/{}'.format(year, month, slug))
    return render_post(post)