Exemple #1
0
 def find_tags(cls, text):
     """
     Parse <text> for things that look like tags and return matching Tag
     objects.
     """
     tl = ' '.join(m.group(0)[1:] for m in cls.tag_re.finditer(text))
     return Tag.parse_line(tl, create=True)
Exemple #2
0
 def find_tags(cls, text):
     """
     Parse <text> for things that look like tags and return matching Tag
     objects.
     """
     tl = ' '.join(m.group(0)[1:] for m in cls.tag_re.finditer(text))
     return Tag.parse_line(tl, create=True)
Exemple #3
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)
Exemple #4
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))
Exemple #5
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

    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)
Exemple #6
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))
Exemple #7
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)