コード例 #1
0
ファイル: __init__.py プロジェクト: Zauberstuhl/pyaspora
def index():
    from pyaspora.user.session import logged_in_user
    from pyaspora.utils.rendering import redirect
    if logged_in_user(fetch=False):
        return redirect(url_for('feed.view'))
    else:
        return redirect(url_for('users.login'))
コード例 #2
0
def index():
    from pyaspora.user.session import logged_in_user
    from pyaspora.utils.rendering import redirect
    if logged_in_user(fetch=False):
        return redirect(url_for('feed.view'))
    else:
        return redirect(url_for('users.login'))
コード例 #3
0
def view(_user):
    """
    Show the logged-in user their own feed.
    """
    from pyaspora.diaspora.models import MessageQueue
    if MessageQueue.has_pending_items(_user):
        return redirect(url_for('diaspora.run_queue', _external=True))

    limit = int(request.args.get('limit', 99))
    friend_ids = [f.id for f in _user.contact.friends()]
    clauses = [Post.Queries.shared_with_contact(_user.contact)]
    if friend_ids:
        clauses.append(
            Post.Queries.authored_by_contacts_and_public(friend_ids))
    tag_ids = [t.id for t in _user.contact.interests]
    if tag_ids:
        clauses.append(Tag.Queries.public_posts_for_tags(tag_ids))
    feed_query = or_(*clauses)
    feed = db.session.query(Share).join(Post). \
        outerjoin(PostTag).outerjoin(Tag). \
        filter(feed_query). \
        order_by(desc(Post.thread_modified_at)). \
        group_by(Post.id). \
        options(contains_eager(Share.post)). \
        limit(limit)

    data = {'feed': json_posts([(s.post, s) for s in feed], _user, True)}

    add_logged_in_user_to_data(data, _user)

    return render_response('feed.tpl', data)
コード例 #4
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def view(_user):
    """
    Show the logged-in user their own feed.
    """
    from pyaspora.diaspora.models import MessageQueue
    if MessageQueue.has_pending_items(_user):
        return redirect(url_for('diaspora.run_queue', _external=True))

    limit = int(request.args.get('limit', 99))
    friend_ids = [f.id for f in _user.contact.friends()]
    clauses = [Post.Queries.shared_with_contact(_user.contact)]
    if friend_ids:
        clauses.append(
            Post.Queries.authored_by_contacts_and_public(friend_ids))
    tag_ids = [t.id for t in _user.contact.interests]
    if tag_ids:
        clauses.append(Tag.Queries.public_posts_for_tags(tag_ids))
    feed_query = or_(*clauses)
    feed = db.session.query(Share).join(Post). \
        outerjoin(PostTag).outerjoin(Tag). \
        filter(feed_query). \
        order_by(desc(Post.thread_modified_at)). \
        group_by(Post.id). \
        options(contains_eager(Share.post)). \
        limit(limit)

    data = {
        'feed': json_posts([(s.post, s) for s in feed], _user, True)
    }

    add_logged_in_user_to_data(data, _user)

    return render_response('feed.tpl', data)
コード例 #5
0
def set_public(post_id, toggle):
    """
    Make the Post appear-on/disappear-from the User's public wall. If toggle
    is True then the post will appear.
    """
    share, user = _get_share_for_post(post_id)
    post = share.post
    toggle = bool(toggle)

    if not post.can_change_privacy(toggle):
        abort(403, 'Not available')

    if share.public != toggle:
        share.public = toggle
        db.session.add(share)
        if toggle:
            # If it's going public, it'll be visible to more people
            post.thread_modified()
            db.session.add(post)
            db.session.commit()  # Write out the updated share
            if post.author_id == user.contact_id:
                post.author.user = user  # So we have the key
                post.implicit_share([
                    c for c in post.author.followers()
                    if not post.shared_with(c)
                ])
        db.session.commit()

    return redirect(url_for('feed.view', _external=True))
コード例 #6
0
ファイル: views.py プロジェクト: meZee/pyaspora
def save_contact_groups(contact_id, _user):
    """
    Change which SubscriptionGroups a contact is in by parsing a string
    of keywords (like tag processing). Any new terms will create new
    groups; any now-empty groups will be deleted.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)

    sub = _user.contact.subscribed_to(contact)
    if not sub:
        abort(400, 'Not subscribed')

    groups = post_param(
        'groups', template='roster_edit_group.tpl', optional=True) or ''
    new_groups = dict(
        (g.name, g)
        for g in SubscriptionGroup.parse_line(groups, create=True, user=_user))
    old_groups = dict((g.name, g) for g in sub.groups)

    for group_name, group in old_groups.items():
        if group_name not in new_groups:
            other_members = [
                s for s in group.subscriptions if s.to_id != contact.id
            ]
            if not other_members:
                db.session.delete(group)
    sub.groups = list(new_groups.values())
    db.session.add(sub)
    db.session.commit()

    return redirect(url_for('.view', _external=True))
コード例 #7
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def set_public(post_id, toggle):
    """
    Make the Post appear-on/disappear-from the User's public wall. If toggle
    is True then the post will appear.
    """
    share, user = _get_share_for_post(post_id)
    post = share.post
    toggle = bool(toggle)

    if not post.can_change_privacy(toggle):
        abort(403, 'Not available')

    if share.public != toggle:
        share.public = toggle
        db.session.add(share)
        if toggle:
            # If it's going public, it'll be visible to more people
            post.thread_modified()
            db.session.add(post)
            db.session.commit() # Write out the updated share
            if post.author_id == user.contact_id:
                post.author.user = user # So we have the key
                post.implicit_share([
                    c for c in post.author.followers()
                    if not post.shared_with(c)
                ])
        db.session.commit()

    return redirect(url_for('feed.view', _external=True))
コード例 #8
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def hide(post_id):
    """
    Hide an existing Post from the user's wall and profile.
    """
    share, user = _get_share_for_post(post_id)

    share.hidden = True
    db.session.add(share)
    db.session.commit()

    return redirect(url_for('feed.view', _external=True))
コード例 #9
0
ファイル: views.py プロジェクト: jaywink/pyaspora
def process_login():
    """
    Log the user in, checking their credentials and configuring the session,
    and redirect them to the home page.
    """
    password = post_param('password', template='users_login_form.tpl')
    email = post_param('email', template='users_login_form.tpl')
    user = log_in_user(email, password)
    if not user:
        abort(403, 'Login failed')
    return redirect(url_for('index', _external=True))
コード例 #10
0
def process_login():
    """
    Log the user in, checking their credentials and configuring the session,
    and redirect them to the home page.
    """
    password = post_param('password', template='users_login_form.tpl')
    email = post_param('email', template='users_login_form.tpl')
    user = log_in_user(email, password)
    if not user:
        abort(403, 'Login failed')
    return redirect(url_for('index', _external=True))
コード例 #11
0
def hide(post_id):
    """
    Hide an existing Post from the user's wall and profile.
    """
    share, user = _get_share_for_post(post_id)

    share.hidden = True
    db.session.add(share)
    db.session.commit()

    return redirect(url_for('feed.view', _external=True))
コード例 #12
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def subscribe(contact_id, _user):
    """
    Add a contact to the logged-in users roster.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)

    _user.contact.subscribe(contact)

    db.session.commit()
    return redirect(url_for('contacts.profile', contact_id=contact.id))
コード例 #13
0
ファイル: views.py プロジェクト: sant0sh/pyaspora
def hide(post_id, _user):
    """
    Hide an existing Post from the user's wall and profile.
    """
    post = Post.get(post_id)
    if not post:
        abort(404, 'No such post', force_status=True)

    post.hide(_user)
    db.session.commit()

    return redirect(url_for('feed.view', _external=True))
コード例 #14
0
ファイル: views.py プロジェクト: meZee/pyaspora
def hide(post_id, _user):
    """
    Hide an existing Post from the user's wall and profile.
    """
    post = Post.get(post_id)
    if not post:
        abort(404, 'No such post', force_status=True)

    post.hide(_user)
    db.session.commit()

    return redirect(url_for('feed.view', _external=True))
コード例 #15
0
ファイル: views.py プロジェクト: meZee/pyaspora
def subscribe(contact_id, _user):
    """
    Add a contact to the logged-in users roster.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)

    _user.contact.subscribe(contact)

    db.session.commit()
    return redirect(url_for('contacts.profile', contact_id=contact.id))
コード例 #16
0
ファイル: views.py プロジェクト: meZee/pyaspora
def rename_group(group_id, _user):
    """
    Change the name of an existing group.
    """
    group = SubscriptionGroup.get(group_id)
    if not (group) or group.user_id != _user.id:
        abort(404, 'No such group')

    group.name = post_param('name')
    if group.name_is_valid(group.name):
        db.session.add(group)
        db.session.commit()

    return redirect(url_for('.view', _external=True))
コード例 #17
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def rename_group(group_id, _user):
    """
    Change the name of an existing group.
    """
    group = SubscriptionGroup.get(group_id)
    if not(group) or group.user_id != _user.id:
        abort(404, 'No such group')

    group.name = post_param('name')
    if group.name_is_valid(group.name):
        db.session.add(group)
        db.session.commit()

    return redirect(url_for('.view', _external=True))
コード例 #18
0
ファイル: views.py プロジェクト: meZee/pyaspora
def view(_user):
    """
    Show the logged-in user their own feed.
    """
    from pyaspora.diaspora.models import MessageQueue
    if MessageQueue.has_pending_items(_user):
        return redirect(url_for('diaspora.run_queue', _external=True))

    limit = int(request.args.get('limit', 10))
    friend_ids = [f.id for f in _user.contact.friends()]
    clauses = [Post.Queries.shared_with_contact(_user.contact)]
    if friend_ids:
        clauses.append(
            Post.Queries.authored_by_contacts_and_public(friend_ids))
    tag_ids = [t.id for t in _user.contact.interests]
    if tag_ids:
        clauses.append(Tag.Queries.public_posts_for_tags(tag_ids))
    feed_query = or_(*clauses)
    my_share = aliased(Share)
    feed = db.session.query(Share).join(Post). \
        outerjoin(  # Stuff user hasn't hidden
            my_share,
            and_(
                Post.id == my_share.post_id,
                my_share.contact == _user.contact
            )
        ). \
        outerjoin(PostTag).outerjoin(Tag). \
        filter(feed_query). \
        filter(or_(my_share.hidden == None, not_(my_share.hidden))). \
        filter(Post.parent == None). \
        order_by(desc(Post.thread_modified_at)). \
        group_by(Post.id). \
        options(contains_eager(Share.post)). \
        options(joinedload(Share.post, Post.diasp)). \
        limit(limit)

    data = {
        'feed': json_posts([(s.post, s) for s in feed], _user, True),
        'limit': limit,
    }
    if len(data['feed']) >= limit:
        data['actions'] = {
            'more': url_for('feed.view', limit=limit + 10, _external=True)
        }

    add_logged_in_user_to_data(data, _user)

    return render_response('feed.tpl', data)
コード例 #19
0
ファイル: views.py プロジェクト: ktalik/pyaspora
def view(_user):
    """
    Show the logged-in user their own feed.
    """
    from pyaspora.diaspora.models import MessageQueue
    if MessageQueue.has_pending_items(_user):
        return redirect(url_for('diaspora.run_queue', _external=True))

    limit = int(request.args.get('limit', 10))
    friend_ids = [f.id for f in _user.contact.friends()]
    clauses = [Post.Queries.shared_with_contact(_user.contact)]
    if friend_ids:
        clauses.append(
            Post.Queries.authored_by_contacts_and_public(friend_ids))
    tag_ids = [t.id for t in _user.contact.interests]
    if tag_ids:
        clauses.append(Tag.Queries.public_posts_for_tags(tag_ids))
    feed_query = or_(*clauses)
    my_share = aliased(Share)
    feed = db.session.query(Share).join(Post). \
        outerjoin(  # Stuff user hasn't hidden
            my_share,
            and_(
                Post.id == my_share.post_id,
                my_share.contact == _user.contact
            )
        ). \
        outerjoin(PostTag).outerjoin(Tag). \
        filter(feed_query). \
        filter(or_(my_share.hidden == None, not_(my_share.hidden))). \
        filter(Post.parent == None). \
        order_by(desc(Post.thread_modified_at)). \
        group_by(Post.id). \
        options(contains_eager(Share.post)). \
        options(joinedload(Share.post, Post.diasp)). \
        limit(limit)

    data = {
        'feed': json_posts([(s.post, s) for s in feed], _user, True),
        'limit': limit,
        'actions': {},
    }

    if len(data['feed']) >= limit:
        data['actions']['more'] = url_for('feed.view', limit=limit + 10, _external=True)

    add_logged_in_user_to_data(data, _user)

    return render_response('feed.tpl', data)
コード例 #20
0
def subscriptions(contact_id, _user):
    """
    Display the friend list for the contact (who must be local to this server,
    because this server doesn't hold the full friend list for remote users).
    """
    contact = Contact.get(contact_id)
    if not (contact.user and contact.user.activated):
        abort(404, 'No such contact', force_status=True)

    # Looking at our own list? You'll be wanting the edit view.
    if contact.id == _user.contact.id:
        return redirect(url_for('roster.view', _external=True))

    data = json_contact(contact, _user)
    data['subscriptions'] = [json_contact(c, _user) for c in contact.friends()]

    add_logged_in_user_to_data(data, _user)

    return render_response('contacts_friend_list.tpl', data)
コード例 #21
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def run_public_queue(_user):
    queue_items = db.session.query(MessageQueue).filter(
        MessageQueue.Queries.pending_public_items()
    ).order_by(MessageQueue.created_at)
    for qi in queue_items:
        if qi.error:
            break

        try:
            qi.process_incoming()
        except Exception:
            err = format_exc()
            qi.error = err.encode('utf-8')
            current_app.logger.error(err)
            db.session.add(qi)
            break
        else:
            db.session.delete(qi)
    db.session.commit()
    return redirect(url_for('feed.view'))
コード例 #22
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def subscriptions(contact_id, _user):
    """
    Display the friend list for the contact (who must be local to this server,
    because this server doesn't hold the full friend list for remote users).
    """
    contact = Contact.get(contact_id)
    if not(contact.user and contact.user.activated):
        abort(404, 'No such contact', force_status=True)

    # Looking at our own list? You'll be wanting the edit view.
    if contact.id == _user.contact.id:
        return redirect(url_for('roster.view', _external=True))

    data = json_contact(contact, _user)
    data['subscriptions'] = [json_contact(c, _user)
                             for c in contact.friends()]

    add_logged_in_user_to_data(data, _user)

    return render_response('contacts_friend_list.tpl', data)
コード例 #23
0
def run_public_queue(_user):
    queue_items = db.session.query(MessageQueue).filter(
        MessageQueue.Queries.pending_public_items()).order_by(
            MessageQueue.created_at)
    for qi in queue_items:
        if qi.error:
            break

        try:
            qi.process_incoming()
        except Exception:
            err = format_exc()
            qi.error = err.encode('utf-8')
            current_app.logger.error(err)
            db.session.add(qi)
            break
        else:
            db.session.delete(qi)
    db.session.commit()
    return redirect(url_for('feed.view'))
コード例 #24
0
ファイル: views.py プロジェクト: meZee/pyaspora
def remove_contact(group_id, contact_id, _user):
    """
    Remove a contact from an existing SubscriptionGroup. The Subscription
    remains. If the SubscriptionGroup becomes empty it will be removed.
    """
    group = SubscriptionGroup.get(group_id)
    if not (group) or group.user_id != _user.id:
        abort(404, 'No such group')

    new_list = [
        s for s in group.subscriptions if s.to_contact.id != contact_id
    ]
    group.subscriptions = new_list

    if not new_list:
        db.session.delete(group)

    db.session.commit()

    return redirect(url_for('.view', _external=True))
コード例 #25
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def remove_contact(group_id, contact_id, _user):
    """
    Remove a contact from an existing SubscriptionGroup. The Subscription
    remains. If the SubscriptionGroup becomes empty it will be removed.
    """
    group = SubscriptionGroup.get(group_id)
    if not(group) or group.user_id != _user.id:
        abort(404, 'No such group')

    new_list = [
        s for s in group.subscriptions
        if s.to_contact.id != contact_id
    ]
    group.subscriptions = new_list

    if not new_list:
        db.session.delete(group)

    db.session.commit()

    return redirect(url_for('.view', _external=True))
コード例 #26
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def save_contact_groups(contact_id, _user):
    """
    Change which SubscriptionGroups a contact is in by parsing a string
    of keywords (like tag processing). Any new terms will create new
    groups; any now-empty groups will be deleted.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)

    sub = _user.contact.subscribed_to(contact)
    if not sub:
        abort(400, 'Not subscribed')

    groups = post_param(
        'groups',
        template='roster_edit_group.tpl',
        optional=True
    ) or ''
    new_groups = dict(
        (g.name, g) for g in
        SubscriptionGroup.parse_line(groups, create=True, user=_user)
    )
    old_groups = dict((g.name, g) for g in sub.groups)

    for group_name, group in old_groups.items():
        if group_name not in new_groups:
            other_members = [
                s for s in group.subscriptions
                if s.to_id != contact.id
            ]
            if not other_members:
                db.session.delete(group)
    sub.groups = list(new_groups.values())
    db.session.add(sub)
    db.session.commit()

    return redirect(url_for('.view', _external=True))
コード例 #27
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def run_queue(_user):
    start = datetime.now()
    retry = True
    processed = int(request.args.get('processed', 0))
    while datetime.now() < start + timedelta(seconds=3):
        if not MessageQueue.has_pending_items(_user):
            retry = False
            break
        MessageQueue.process_incoming_queue(_user, max_items=1)
        processed += 1

    data = {
        'count': processed,
        'next': url_for('.run_queue', processed=processed, _external=True)
    }
    add_logged_in_user_to_data(data, _user)

    if retry:
        resp = make_response(render_response('diaspora_queue.tpl', data))
        resp.headers['Refresh'] = '1;{0}'.format(data['next'])
        return resp
    else:
        return redirect(url_for('feed.view'))
コード例 #28
0
def run_queue(_user):
    start = datetime.now()
    retry = True
    processed = int(request.args.get('processed', 0))
    while datetime.now() < start + timedelta(seconds=3):
        if not MessageQueue.has_pending_items(_user):
            retry = False
            break
        MessageQueue.process_incoming_queue(_user, max_items=1)
        processed += 1

    data = {
        'count': processed,
        'next': url_for('.run_queue', processed=processed, _external=True)
    }
    add_logged_in_user_to_data(data, _user)

    if retry:
        resp = make_response(render_response('diaspora_queue.tpl', data))
        resp.headers['Refresh'] = '1;{0}'.format(data['next'])
        return resp
    else:
        return redirect(url_for('feed.view'))
コード例 #29
0
def edit(_user):
    """
    Apply the changes from the user edit form. This updates such varied things
    as the profile photo and bio, the email address, name, password and
    interests.
    """
    from pyaspora.post.models import Post

    p = Post(author=_user.contact)
    changed = []
    order = 0

    notif_freq = post_param(
        'notification_frequency_hours',
        template='users_edit.tpl',
        optional=True
    )
    _user.notification_hours = int(notif_freq) if notif_freq else None

    email = post_param('email', optional=True)
    if email and email != _user.email:
        _user.email = email

    old_pw = post_param('current_password', optional=True)
    new_pw1 = post_param('new_password', optional=True)
    new_pw2 = post_param('new_password2', optional=True)
    if old_pw and new_pw1 and new_pw2:
        if new_pw1 != new_pw2:
            abort(400, 'New passwords do not match')
        try:
            _user.change_password(old_pw, new_pw1)
        except ValueError:
            abort(400, 'Old password is incorrect')
    db.session.add(_user)

    attachment = request.files.get('avatar', None)
    if attachment and attachment.filename:
        changed.append('avatar')
        order += 1
        check_attachment_is_safe(attachment)

        if not renderer_exists(attachment.mimetype) or \
                not attachment.mimetype.startswith('image/'):
            abort(400, 'Avatar format unsupported')

        attachment_part = MimePart(
            type=attachment.mimetype,
            body=attachment.stream.read(),
            text_preview=attachment.filename
        )

        p.add_part(attachment_part, order=order, inline=True)
        _user.contact.avatar = attachment_part

    name = post_param('name', template='users_edit.tpl', optional=True)
    if name and name != _user.contact.realname:
        _user.contact.realname = name
        changed.append('name')

    bio = post_param('bio', template='users_edit.tpl', optional=True)
    if bio:
        bio = bio.encode('utf-8')
    else:
        bio = b''
    if bio and (not _user.contact.bio or _user.contact.bio.body != bio):
        changed.append('bio')
        order += 1
        bio_part = MimePart(body=bio, type='text/plain', text_preview=None)
        p.add_part(
            order=order,
            inline=True,
            mime_part=bio_part
        )
        _user.contact.bio = bio_part

    tags = post_param('tags', optional=True)
    if tags is not None:
        tag_objects = Tag.parse_line(tags, create=True)
        old_tags = set([t.id for t in _user.contact.interests])
        new_tags = set([t.id for t in tag_objects])
        if old_tags != new_tags:
            changed.append('tags')
            _user.contact.interests = tag_objects

    p.add_part(
        order=0,
        inline=True,
        mime_part=MimePart(
            body=json_dumps({
                'fields_changed': changed
            }).encode('utf-8'),
            type='application/x-pyaspora-profile-update',
            text_preview='updated their profile'
        )
    )

    if changed:
        db.session.add(p)
        db.session.add(_user.contact)
        p.share_with([_user.contact])
        p.thread_modified()

    db.session.commit()

    return redirect(url_for('contacts.profile', contact_id=_user.contact.id))
コード例 #30
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def create(_user):
    """
    Create a new Post and Share it with the selected Contacts.
    """
    body = post_param('body')
    relationship = {
        'type': post_param('relationship_type', optional=True),
        'id': post_param('relationship_id', optional=True),
    }

    target = {
        'type': post_param('target_type'),
        'id': post_param('target_id', optional=True),
    }

    assert(target['type'] in targets_by_name)

    # Loathe inflexible HTML forms
    if target['id'] is None:
        target['id'] = post_param(
            'target_%s_id' % target['type'], optional=True)

    if relationship['type']:
        post = Post.get(relationship['id'])
        if not post:
            abort(404, 'No such post', force_status=True)
        if not post.has_permission_to_view(_user.contact):
            abort(403, 'Forbidden')
        relationship['post'] = post

    post = Post(author=_user.contact)
    body_part = MimePart(type='text/x-markdown', body=body.encode('utf-8'),
                         text_preview=None)

    topics = post_param('tags', optional=True)
    if topics:
        post.tags = Tag.parse_line(topics, create=True)

    if relationship['type'] == 'comment':
        post.parent = relationship['post']
        post.add_part(body_part, order=0, inline=True)
    elif relationship['type'] == 'share':
        shared = relationship['post']
        share_part = MimePart(
            type='application/x-pyaspora-share',
            body=dumps({
                'post': {'id': shared.id},
                'author': {
                    'id': shared.author_id,
                    'name': shared.author.realname,
                }
            }).encode('utf-8'),
            text_preview="shared {0}'s post".format(shared.author.realname)
        )
        post.add_part(share_part, order=0, inline=True)
        post.add_part(body_part, order=1, inline=True)
        order = 1
        for part in shared.parts:
            if part.mime_part.type != 'application/x-pyaspora-share':
                order += 1
                post.add_part(part.mime_part, inline=part.inline, order=order)
        if not post.tags:
            post.tags = shared.tags
    else:  # Naked post
        post.add_part(body_part, order=0, inline=True)
        attachment = request.files.get('attachment', None)
        if attachment and attachment.filename:
            check_attachment_is_safe(attachment)
            attachment_part = MimePart(
                type=attachment.mimetype,
                body=attachment.stream.read(),
                text_preview=attachment.filename
            )
            post.add_part(attachment_part, order=1,
                          inline=bool(renderer_exists(attachment.mimetype)))

    post.thread_modified()

    # Sigh, need an ID for the post for making shares
    db.session.add(post)
    db.session.commit()

    targets_by_name[target['type']].make_shares(post, target['id'])
    db.session.commit()

    data = json_post(post)
    return redirect(url_for('feed.view', _external=True), data_structure=data)
コード例 #31
0
def run_public_queue(_user):
    queue_items = db.session.query(MessageQueue).filter(
        MessageQueue.Queries.pending_public_items()
    ).order_by(MessageQueue.created_at)
    MessageQueue.process_queue(queue_items, None)
    return redirect(url_for('feed.view'))
コード例 #32
0
ファイル: views.py プロジェクト: jaywink/pyaspora
def edit(_user):
    """
    Apply the changes from the user edit form. This updates such varied things
    as the profile photo and bio, the email address, name, password and
    interests.
    """
    from pyaspora.post.models import Post

    p = Post(author=_user.contact)
    changed = []
    order = 0

    notif_freq = post_param(
        'notification_frequency_hours',
        template='users_edit.tpl',
        optional=True
    )
    _user.notification_hours = int(notif_freq) if notif_freq else None

    email = post_param('email', optional=True)
    if email and email != _user.email:
        _user.email = email

    old_pw = post_param('current_password', optional=True)
    new_pw1 = post_param('new_password', optional=True)
    new_pw2 = post_param('new_password2', optional=True)
    if old_pw and new_pw1 and new_pw2:
        if new_pw1 != new_pw2:
            abort(400, 'New passwords do not match')
        try:
            _user.change_password(old_pw, new_pw1)
        except ValueError:
            abort(400, 'Old password is incorrect')
    db.session.add(_user)

    attachment = request.files.get('avatar', None)
    if attachment and attachment.filename:
        changed.append('avatar')
        order += 1
        check_attachment_is_safe(attachment)

        if not renderer_exists(attachment.mimetype) or \
                not attachment.mimetype.startswith('image/'):
            abort(400, 'Avatar format unsupported')

        attachment_part = MimePart(
            type=attachment.mimetype,
            body=attachment.stream.read(),
            text_preview=attachment.filename
        )

        p.add_part(attachment_part, order=order, inline=True)
        _user.contact.avatar = attachment_part

    name = post_param('name', template='users_edit.tpl', optional=True)
    if name and name != _user.contact.realname:
        _user.contact.realname = name
        changed.append('name')

    bio = post_param('bio', template='users_edit.tpl', optional=True)
    if bio:
        bio = bio.encode('utf-8')
    else:
        bio = b''
    if bio and (not _user.contact.bio or _user.contact.bio.body != bio):
        changed.append('bio')
        order += 1
        bio_part = MimePart(body=bio, type='text/plain', text_preview=None)
        p.add_part(
            order=order,
            inline=True,
            mime_part=bio_part
        )
        _user.contact.bio = bio_part

    tags = post_param('tags', optional=True)
    if tags is not None:
        tag_objects = Tag.parse_line(tags, create=True)
        old_tags = set([t.id for t in _user.contact.interests])
        new_tags = set([t.id for t in tag_objects])
        if old_tags != new_tags:
            changed.append('tags')
            _user.contact.interests = tag_objects

    p.add_part(
        order=0,
        inline=True,
        mime_part=MimePart(
            body=json_dumps({
                'fields_changed': changed
            }).encode('utf-8'),
            type='application/x-pyaspora-profile-update',
            text_preview='updated their profile'
        )
    )

    if changed:
        db.session.add(p)
        db.session.add(_user.contact)
        p.share_with([_user.contact])
        p.thread_modified()

    db.session.commit()

    return redirect(url_for('contacts.profile', contact_id=_user.contact.id))
コード例 #33
0
ファイル: views.py プロジェクト: meZee/pyaspora
def create(_user):
    """
    Create a new Post and Share it with the selected Contacts.
    """
    body = post_param('body')
    relationship = {
        'type': post_param('relationship_type', optional=True),
        'id': post_param('relationship_id', optional=True),
    }

    target = {
        'type': post_param('target_type'),
        'id': post_param('target_id', optional=True),
    }

    assert (target['type'] in targets_by_name)

    # Loathe inflexible HTML forms
    if target['id'] is None:
        target['id'] = post_param('target_%s_id' % target['type'],
                                  optional=True)

    if relationship['type']:
        post = Post.get(relationship['id'])
        if not post:
            abort(404, 'No such post', force_status=True)
        if not post.has_permission_to_view(_user.contact):
            abort(403, 'Forbidden')
        relationship['post'] = post

    shared = None
    post = Post(author=_user.contact)
    body_part = MimePart(type='text/x-markdown',
                         body=body.encode('utf-8'),
                         text_preview=None)

    topics = post_param('tags', optional=True)
    if topics:
        post.tags = Tag.parse_line(topics, create=True)

    if relationship['type'] == 'comment':
        post.parent = relationship['post']
        post.add_part(body_part, order=0, inline=True)
    elif relationship['type'] == 'share':
        shared = relationship['post']
        share_part = MimePart(type='application/x-pyaspora-share',
                              body=dumps({
                                  'post': {
                                      'id': shared.id
                                  },
                                  'author': {
                                      'id': shared.author_id,
                                      'name': shared.author.realname,
                                  }
                              }).encode('utf-8'),
                              text_preview=u"shared {0}'s post".format(
                                  shared.author.realname))
        post.add_part(share_part, order=0, inline=True)
        post.add_part(body_part, order=1, inline=True)
        order = 1
        for part in shared.parts:
            if part.mime_part.type != 'application/x-pyaspora-share':
                order += 1
                post.add_part(part.mime_part, inline=part.inline, order=order)
        if not post.tags:
            post.tags = shared.tags
    else:  # Naked post
        post.add_part(body_part, order=0, inline=True)
        attachment = request.files.get('attachment', None)
        if attachment and attachment.filename:
            check_attachment_is_safe(attachment)
            attachment_part = MimePart(type=attachment.mimetype,
                                       body=attachment.stream.read(),
                                       text_preview=attachment.filename)
            post.add_part(attachment_part,
                          order=1,
                          inline=bool(renderer_exists(attachment.mimetype)))

    post.thread_modified()

    # Sigh, need an ID for the post for making shares
    db.session.add(post)
    db.session.commit()

    targets_by_name[target['type']].make_shares(post,
                                                target['id'],
                                                reshare_of=shared)
    db.session.commit()

    data = json_post(post)
    return redirect(url_for('feed.view', _external=True), data_structure=data)