示例#1
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))
示例#2
0
def create_form():
    """
    Display the form to create a new user account.
    """
    if not current_app.config.get('ALLOW_CREATION', False):
        abort(403, 'Disabled by site administrator')
    return render_response('users_create_form.tpl')
示例#3
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))
示例#4
0
def feed(tag_name, _user):
    """
    Display recent public posts on a particular topic (Tag).
    """
    from pyaspora.post.models import Post, Share
    from pyaspora.post.views import json_posts

    tag = Tag.get_by_name(tag_name, create=False)
    if not tag:
        abort(404, 'No such tag')

    data = json_tag(tag)

    posts = db.session.query(Post). \
        join(PostTag). \
        join(Tag). \
        join(Share). \
        filter(Tag.Queries.public_posts_for_tags([tag.id])). \
        order_by(desc(Post.thread_modified_at)). \
        group_by(Post.id). \
        limit(100)

    data['feed'] = json_posts([(p, None) for p in posts])

    add_logged_in_user_to_data(data, _user)

    return render_response('tags_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 项目: jaywink/pyaspora
def create_form():
    """
    Display the form to create a new user account.
    """
    if not _can_create_account():
        abort(403, 'Disabled by site administrator')
    return render_response('users_create_form.tpl')
示例#7
0
文件: views.py 项目: meZee/pyaspora
def create_form():
    """
    Display the form to create a new user account.
    """
    if not _can_create_account():
        abort(403, 'Disabled by site administrator')
    return render_response('users_create_form.tpl')
示例#8
0
def edit_contact_groups_form(contact_id, _user):
    """
    Form to edit which SubscriptionGroups a contact is in.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact')
    sub = _user.contact.subscribed_to(contact)
    if not sub:
        abort(404, 'No such contact')

    data = {
        'actions': {
            'save_groups': url_for(
                '.save_contact_groups',
                contact_id=contact.id,
                _external=True
            )
        },
        'subscription': json_contact_with_groups(sub, _user)
    }

    add_logged_in_user_to_data(data, _user)

    return render_response('roster_edit_group.tpl', data)
示例#9
0
文件: views.py 项目: meZee/pyaspora
def _get_share_for_post(post_id, _user):
    share = db.session.query(Share).filter(
        and_(Share.contact == _user.contact, Share.post_id == post_id,
             not_(Share.hidden))).first()
    if not share:
        abort(403, 'Not available')

    return share, _user
示例#10
0
def _get_share_for_post(post_id, _user):
    share = db.session.query(Share).filter(and_(
        Share.contact == _user.contact,
        Share.post_id == post_id,
        not_(Share.hidden))).first()
    if not share:
        abort(403, 'Not available')

    return share, _user
示例#11
0
def post_param(name, optional=False, template=None):
    try:
        val = request.form[name]
        if not val and not optional:
            raise ValueError()
        return val
    except (KeyError, ValueError):
        if optional:
            return None
        abort(400, 'Missing value for: {0}'.format(name), template=template)
示例#12
0
def profile(contact_id):
    """
    Display the profile (possibly with feed) for the contact.
    """
    data, contact = _profile_base(contact_id,
                                  request.args.get('public', False))
    if not contact.user and not logged_in_user():
        abort(404, 'No such contact', force_status=True)
    if contact.user and not contact.user.activated:
        abort(404, 'No such contact', force_status=True)
    return render_response('contacts_profile.tpl', data)
示例#13
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))
示例#14
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))
示例#15
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))
示例#16
0
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))
示例#17
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))
示例#18
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))
示例#19
0
def profile(contact_id):
    """
    Display the profile (possibly with feed) for the contact.
    """
    data, contact = _profile_base(
        contact_id,
        request.args.get('public', False)
    )
    if not contact.user and not logged_in_user():
        abort(404, 'No such contact', force_status=True)
    if contact.user and not contact.user.activated:
        abort(404, 'No such contact', force_status=True)
    return render_response('contacts_profile.tpl', data)
示例#20
0
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))
示例#21
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))
示例#22
0
def login():
    """
    Display the user login form.
    """
    user = logged_in_user()
    if user:
        data = {}
        add_logged_in_user_to_data(data, user)
        abort(400, 'Already logged in', data)

    data = {}
    add_logged_in_user_to_data(data, None)

    return render_response('users_login_form.tpl', data)
示例#23
0
def raw(part_id):
    """
    Return the part's body as a raw byte-stream for eg. serving images.
    """
    part = MimePart.get(part_id)
    logged_in = logged_in_user()
    if not part:
        abort(404, 'No such content item', force_status=True)

    # If anyone has shared this part with us (or the public), we get to view
    # it.
    for link in part.posts:
        if link.post.has_permission_to_view(logged_in):
            return raw_response(part.body, part.type)

    abort(403, 'Forbidden')
示例#24
0
文件: views.py 项目: jaywink/pyaspora
def _profile_base(contact_id, public=False):
    """
    Standard data for profile-alike pages, including the profile page and feed
    pages.
    """
    from pyaspora.post.models import Post, Share
    from pyaspora.post.views import json_posts

    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)

    viewing_as = None if public else logged_in_user()

    data = json_contact(contact, viewing_as)
    limit = int(request.args.get('limit', 25))

    if viewing_as and request.args.get('refresh', False) and contact.diasp:
        try:
            contact.diasp.import_public_posts()
            db.session.commit()
        except:
            current_app.logger.debug(format_exc())

    # If not local, we don't have a proper feed
    if viewing_as or contact.user:
        # user put it on their public wall
        feed_query = Post.Queries.public_wall_for_contact(contact)
        if viewing_as:
            # Also include things this user has shared with us
            shared_query = Post.Queries.author_shared_with(
                contact, viewing_as)
            feed_query = or_(feed_query, shared_query)

        feed = db.session.query(Share). \
            join(Post). \
            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], viewing_as)

    add_logged_in_user_to_data(data, viewing_as)
    return data, contact
示例#25
0
文件: views.py 项目: meZee/pyaspora
def _profile_base(contact_id, public=False):
    """
    Standard data for profile-alike pages, including the profile page and feed
    pages.
    """
    from pyaspora.post.models import Post, Share
    from pyaspora.post.views import json_posts

    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)

    viewing_as = None if public else logged_in_user()

    data = json_contact(contact, viewing_as)
    limit = int(request.args.get('limit', 25))

    if viewing_as and request.args.get('refresh', False) and contact.diasp:
        try:
            contact.diasp.import_public_posts()
            db.session.commit()
        except:
            current_app.logger.debug(format_exc())

    # If not local, we don't have a proper feed
    if viewing_as or contact.user:
        # user put it on their public wall
        feed_query = Post.Queries.public_wall_for_contact(contact)
        if viewing_as:
            # Also include things this user has shared with us
            shared_query = Post.Queries.author_shared_with(contact, viewing_as)
            feed_query = or_(feed_query, shared_query)

        feed = db.session.query(Share). \
            join(Post). \
            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], viewing_as)

    add_logged_in_user_to_data(data, viewing_as)
    return data, contact
示例#26
0
文件: views.py 项目: meZee/pyaspora
def view_group(group_id, _user):
    """
    Display the info and members of one SubscriptionGroup.
    """
    group = SubscriptionGroup.get(group_id)
    if not (group) or group.user_id != _user.id:
        abort(404, 'No such group')

    data = {
        'subscriptions':
        [json_contact_with_groups(s, _user) for s in group.subscriptions],
        'group':
        json_group(group)
    }

    add_logged_in_user_to_data(data, _user)

    return render_response('roster_view_group.tpl', data)
示例#27
0
文件: views.py 项目: meZee/pyaspora
def login():
    """
    Display the user login form.
    """
    user = logged_in_user()
    if user:
        data = {}
        add_logged_in_user_to_data(data, user)
        abort(400, 'Already logged in', data)

    data = {}
    add_logged_in_user_to_data(data, None)

    if _can_create_account():
        data['logged_in']['actions']['sign_up'] = url_for('users.create',
                                                          _external=True)

    return render_response('users_login_form.tpl', data)
示例#28
0
def view_group(group_id, _user):
    """
    Display the info and members of one SubscriptionGroup.
    """
    group = SubscriptionGroup.get(group_id)
    if not(group) or group.user_id != _user.id:
        abort(404, 'No such group')

    data = {
        'subscriptions': [
            json_contact_with_groups(s, _user)
            for s in group.subscriptions
        ],
        'group': json_group(group)
    }

    add_logged_in_user_to_data(data, _user)

    return render_response('roster_view_group.tpl', data)
示例#29
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)
示例#30
0
文件: views.py 项目: jaywink/pyaspora
def login():
    """
    Display the user login form.
    """
    user = logged_in_user()
    if user:
        data = {}
        add_logged_in_user_to_data(data, user)
        abort(400, 'Already logged in', data)

    data = {}
    add_logged_in_user_to_data(data, None)

    if _can_create_account():
        data['logged_in']['actions']['sign_up'] = url_for(
            'users.create',
            _external=True
        )

    return render_response('users_login_form.tpl', data)
示例#31
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)
示例#32
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))
示例#33
0
文件: views.py 项目: meZee/pyaspora
def comment(post_id, _user):
    """
    Comment on (reply to) an existing Post.
    """
    post = Post.get(post_id)
    if not post:
        abort(404, 'No such post', force_status=True)
    if not post.has_permission_to_view(_user.contact):
        abort(403, 'Forbidden')

    data = _base_create_form(_user, post)

    data.update({
        'relationship': {
            'type': 'comment',
            'object': json_post(post, children=False),
            'description': 'Comment on this item'
        }
    })

    return render_response('posts_create_form.tpl', data)
示例#34
0
def comment(post_id, _user):
    """
    Comment on (reply to) an existing Post.
    """
    post = Post.get(post_id)
    if not post:
        abort(404, 'No such post', force_status=True)
    if not post.has_permission_to_view(_user.contact):
        abort(403, 'Forbidden')

    data = _base_create_form(_user, post)

    data.update({
        'relationship': {
            'type': 'comment',
            'object': json_post(post, children=False),
            'description': 'Comment on this item'
        }
    })

    return render_response('posts_create_form.tpl', data)
示例#35
0
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))
示例#36
0
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))
示例#37
0
文件: views.py 项目: meZee/pyaspora
def share(post_id, _user):
    """
    Form to share an existing Post with more Contacts.
    """
    post = Post.get(post_id)
    if not post:
        abort(404, 'No such post', force_status=True)
    if not post.has_permission_to_view(_user.contact):
        abort(403, 'Forbidden')

    data = _base_create_form(_user)

    data.update({
        'relationship': {
            'type': 'share',
            'object': json_post(post, children=False),
            'description': 'Share this item'
        },
        'default_target': {
            'type': 'all_friends',
            'id': None
        }
    })
    return render_response('posts_create_form.tpl', data)
示例#38
0
def share(post_id, _user):
    """
    Form to share an existing Post with more Contacts.
    """
    post = Post.get(post_id)
    if not post:
        abort(404, 'No such post', force_status=True)
    if not post.has_permission_to_view(_user.contact):
        abort(403, 'Forbidden')

    data = _base_create_form(_user)

    data.update({
        'relationship': {
            'type': 'share',
            'object': json_post(post, children=False),
            'description': 'Share this item'
        },
        'default_target': {
            'type': 'all_friends',
            'id': None
        }
    })
    return render_response('posts_create_form.tpl', data)
示例#39
0
def create():
    """
    Create a new User (sign-up).
    """
    if not current_app.config.get('ALLOW_CREATION', False):
        abort(403, 'Disabled by site administrator')

    user = logged_in_user()
    if user:
        data = {}
        add_logged_in_user_to_data(data, user)
        abort(400, 'Already logged in', data)

    name = post_param('name', template='users_create_form.tpl')
    password = post_param('password', template='users_create_form.tpl')
    email = post_param('email', template='users_create_form.tpl')

    my_user = models.User()
    my_user.email = email
    my_user.contact.realname = name
    my_user.generate_keypair(password)
    db.session.commit()

    send_template(my_user.email, 'user_activate_email.tpl', {
        'link': url_for(
            '.activate',
            user_id=my_user.id,
            key_hash=_hash_for_pk(my_user),
            _external=True
        )
    })

    data = {}
    add_logged_in_user_to_data(data, None)

    return render_response('users_created.tpl', data)
示例#40
0
文件: views.py 项目: jaywink/pyaspora
def create():
    """
    Create a new User (sign-up).
    """
    if not _can_create_account():
        abort(403, 'Disabled by site administrator')

    user = logged_in_user()
    if user:
        data = {}
        add_logged_in_user_to_data(data, user)
        abort(400, 'Already logged in', data)

    name = post_param('name', template='users_create_form.tpl')
    password = post_param('password', template='users_create_form.tpl')
    email = post_param('email', template='users_create_form.tpl')

    my_user = models.User()
    my_user.email = email
    my_user.contact.realname = name
    my_user.generate_keypair(password)
    db.session.commit()

    send_template(my_user.email, 'user_activate_email.tpl', {
        'link': url_for(
            '.activate',
            user_id=my_user.id,
            key_hash=_hash_for_pk(my_user),
            _external=True
        )
    })

    data = {}
    add_logged_in_user_to_data(data, None)

    return render_response('users_created.tpl', data)
示例#41
0
文件: views.py 项目: meZee/pyaspora
def edit_contact_groups_form(contact_id, _user):
    """
    Form to edit which SubscriptionGroups a contact is in.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact')
    sub = _user.contact.subscribed_to(contact)
    if not sub:
        abort(404, 'No such contact')

    data = {
        'actions': {
            'save_groups':
            url_for('.save_contact_groups',
                    contact_id=contact.id,
                    _external=True)
        },
        'subscription': json_contact_with_groups(sub, _user)
    }

    add_logged_in_user_to_data(data, _user)

    return render_response('roster_edit_group.tpl', data)
示例#42
0
文件: views.py 项目: meZee/pyaspora
def search(_user):
    from pyaspora.diaspora.models import DiasporaContact
    term = request.args.get('searchterm', None) or \
        abort(400, 'No search term provided')
    if re_match('[A-Za-z0-9._]+@[A-Za-z0-9.]+$', term):
        try:
            DiasporaContact.get_by_username(term)
        except:
            current_app.logger.debug(format_exc())

    matches = db.session.query(Contact).outerjoin(DiasporaContact).filter(
        or_(DiasporaContact.username.contains(term),
            Contact.realname.contains(term))).order_by(
                Contact.realname).limit(99)

    data = {'contacts': [json_contact(c, _user) for c in matches]}

    add_logged_in_user_to_data(data, _user)

    return render_response('contacts_search_results.tpl', data)
示例#43
0
文件: views.py 项目: jaywink/pyaspora
def search(_user):
    from pyaspora.diaspora.models import DiasporaContact
    term = request.args.get('searchterm', None) or \
        abort(400, 'No search term provided')
    if re_match('[A-Za-z0-9._]+@[A-Za-z0-9.]+$', term):
        try:
            DiasporaContact.get_by_username(term)
        except:
            current_app.logger.debug(format_exc())

    matches = db.session.query(Contact).outerjoin(DiasporaContact).filter(or_(
        DiasporaContact.username.contains(term),
        Contact.realname.contains(term)
    )).order_by(Contact.realname).limit(99)

    data = {
        'contacts': [json_contact(c, _user) for c in matches]
    }

    add_logged_in_user_to_data(data, _user)

    return render_response('contacts_search_results.tpl', data)
示例#44
0
def avatar(contact_id):
    """
    Display the photo (or other media item) that represents a Contact.
    If the user is logged in they can view the avatar for any contact, but
    if not logged in then only locally-mastered contacts have their avatar
    displayed.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)
    if not contact.user and not logged_in_user():
        abort(404, 'No such contact', force_status=True)

    part = contact.avatar
    if not part:
        abort(404, 'Contact has no avatar', force_status=True)

    return raw_response(part.body, part.type)
示例#45
0
def avatar(contact_id):
    """
    Display the photo (or other media item) that represents a Contact.
    If the user is logged in they can view the avatar for any contact, but
    if not logged in then only locally-mastered contacts have their avatar
    displayed.
    """
    contact = Contact.get(contact_id)
    if not contact:
        abort(404, 'No such contact', force_status=True)
    if not contact.user and not logged_in_user():
        abort(404, 'No such contact', force_status=True)

    part = contact.avatar
    if not part:
        abort(404, 'Contact has no avatar', force_status=True)

    return raw_response(part.body, part.type)
示例#46
0
文件: views.py 项目: jaywink/pyaspora
def activate(user_id, key_hash):
    """
    Activate a user. This is intended to be a clickable link from the sign-up
    email that confirms the email address is valid.
    """
    matched_user = models.User.get(user_id)

    if not matched_user:
        abort(404, 'Not found')

    if matched_user.activated:
        abort(404, 'Not found')

    if key_hash != _hash_for_pk(matched_user):
        abort(404, 'Not found')

    matched_user.activate()
    db.session.commit()
    return render_response('users_activation_success.tpl')
示例#47
0
def activate(user_id, key_hash):
    """
    Activate a user. This is intended to be a clickable link from the sign-up
    email that confirms the email address is valid.
    """
    matched_user = models.User.get(user_id)

    if not matched_user:
        abort(404, 'Not found')

    if matched_user.activated:
        abort(404, 'Not found')

    if key_hash != _hash_for_pk(matched_user):
        abort(404, 'Not found')

    matched_user.activate()
    db.session.commit()
    return render_response('users_activation_success.tpl')
示例#48
0
def check_attachment_is_safe(attachment):
    if attachment.mimetype == 'text/html' or \
            attachment.mimetype.startswith('application/x-pyaspora'):
        abort(400, 'Invalid upload')

    return True
示例#49
0
文件: session.py 项目: meZee/pyaspora
 def _inner(*args, **kwargs):
     user = logged_in_user()
     if not user:
         abort(401, 'Not logged in')
     return fn(*args, _user=user, **kwargs)
示例#50
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))
示例#51
0
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)
示例#52
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))
示例#53
0
 def _inner(*args, **kwargs):
     user = logged_in_user()
     if not user:
         abort(401, 'Not logged in')
     return fn(*args, _user=user, **kwargs)
示例#54
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)