コード例 #1
0
ファイル: models.py プロジェクト: meZee/pyaspora
    def import_contact(cls, addr):
        """
        Fetch information about a Diaspora user and import it into the Contact
        provided.
        """
        try:
            wf = WebfingerRequest(addr).fetch()
        except URLError as e:
            current_app.logger.warning(e)
            current_app.logger.warning(e.readlines())
            return None
        if not wf:
            return None

        NS = {'XRD': 'http://docs.oasis-open.org/ns/xri/xrd-1.0'}

        c = Contact()

        pk = wf.xpath('//XRD:Link[@rel="diaspora-public-key"]/@href',
                      namespaces=NS)[0]
        c.public_key = b64decode(pk).decode("ascii")

        hcard_url = wf.xpath(
            '//XRD:Link[@rel="http://microformats.org/profile/hcard"]/@href',
            namespaces=NS)[0]
        req = Request(hcard_url)
        req.add_header('User-Agent', USER_AGENT)
        hcard = html.parse(urlopen(req, timeout=10))
        c.realname = hcard.xpath('//*[@class="fn"]')[0].text

        pod_loc = hcard.xpath('//*[@id="pod_location"]')[0].text
        photo_url = hcard.xpath('//*[@class="entity_photo"]//img/@src')[0]
        if photo_url:
            try:
                mp = import_url_as_mimepart(urljoin(pod_loc, photo_url))
            except:
                current_app.logger.debug(format_exc())
            else:
                mp.text_preview = u'(picture for {0})'.format(c.realname
                                                              or '(anonymous)')
                c.avatar = mp

        username = wf.xpath('//XRD:Subject/text()',
                            namespaces=NS)[0].split(':')[1]
        guid = wf.xpath(".//XRD:Link[@rel='http://joindiaspora.com/guid']",
                        namespaces=NS)[0].get("href")
        server = wf.xpath(
            ".//XRD:Link[@rel='http://joindiaspora.com/seed_location']",
            namespaces=NS)[0].get("href")
        d = cls(contact=c, guid=guid, username=username, server=server)
        db.session.add(d)
        db.session.add(c)

        try:
            d.import_public_posts()
        except:
            current_app.logger.debug(format_exc())

        return d
コード例 #2
0
ファイル: models.py プロジェクト: Zauberstuhl/pyaspora
    def import_contact(cls, addr):
        """
        Fetch information about a Diaspora user and import it into the Contact
        provided.
        """
        try:
            wf = WebfingerRequest(addr).fetch()
        except URLError:
            return None
        if not wf:
            return None

        NS = {'XRD': 'http://docs.oasis-open.org/ns/xri/xrd-1.0'}

        c = Contact()

        pk = wf.xpath('//XRD:Link[@rel="diaspora-public-key"]/@href',
                      namespaces=NS)[0]
        c.public_key = b64decode(pk).decode("ascii")

        hcard_url = wf.xpath(
            '//XRD:Link[@rel="http://microformats.org/profile/hcard"]/@href',
            namespaces=NS
        )[0]
        hcard = html.parse(urlopen(hcard_url))
        c.realname = hcard.xpath('//*[@class="fn"]')[0].text

        pod_loc = hcard.xpath('//*[@id="pod_location"]')[0].text
        photo_url = hcard.xpath('//*[@class="entity_photo"]//img/@src')[0]
        if photo_url:
            mp = import_url_as_mimepart(urljoin(pod_loc, photo_url))
            mp.text_preview = '(picture for {0})'.format(
                c.realname or '(anonymous)'
            )
            c.avatar = mp

        username = wf.xpath(
            '//XRD:Subject/text()',
            namespaces=NS
        )[0].split(':')[1]
        guid = wf.xpath(
            ".//XRD:Link[@rel='http://joindiaspora.com/guid']",
            namespaces=NS
        )[0].get("href")
        server = wf.xpath(
            ".//XRD:Link[@rel='http://joindiaspora.com/seed_location']",
            namespaces=NS
        )[0].get("href")
        d = cls(
            contact=c,
            guid=guid,
            username=username,
            server=server
        )
        db.session.add(d)
        db.session.add(c)

        return d
コード例 #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
ファイル: views.py プロジェクト: Zauberstuhl/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)
コード例 #5
0
ファイル: models.py プロジェクト: meZee/pyaspora
 def __init__(self, contact=None):
     """
     Creates a new user, creating a new Contact for the user if none is
     supplied. The contact is then associated with the newly created User.
     """
     db.Model.__init__(self)
     if not contact:
         contact = Contact()
     self.contact = contact
     db.session.add(self)
コード例 #6
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def webfinger(contact_addr):
    """
    Returns the Webfinger profile for a contact called <contact> (in
    "user@host" form).
    """
    contact_id, _ = contact_addr.split('@')
    c = Contact.get(int(contact_id))
    if not c or not c.user or not c.user.activated:
        abort(404, 'No such contact')
    diasp = DiasporaContact.get_for_contact(c)

    ns = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
    doc = etree.Element("{%s}XRD" % ns, nsmap={None: ns})
    etree.SubElement(doc, "Subject").text = "acct:%s" % diasp.username
    etree.SubElement(doc, "Alias").text = \
        '"{0}"'.format(url_for('index', _external=True))
    etree.SubElement(
        doc, "Link",
        rel='http://microformats.org/profile/hcard',
        type='text/html',
        href=url_for('.hcard', guid=diasp.guid, _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='http://joindiaspora.com/seed_location',
        type='text/html',
        href=url_for('index', _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='http://joindiaspora.com/guid',
        type='text/html',
        href=diasp.guid
    )
    etree.SubElement(
        doc, "Link",
        rel='http://webfinger.net/rel/profile-page',
        type='text/html',
        href=url_for('contacts.profile', contact_id=c.id, _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='http://schemas.google.com/g/2010#updates-from',
        type='application/atom+xml',
        href=url_for('contacts.feed', contact_id=c.id, _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='diaspora-public-key',
        type='RSA',
        href=b64encode(c.public_key.encode('ascii'))
    )

    return send_xml(doc)
コード例 #7
0
def webfinger(contact_addr):
    """
    Returns the Webfinger profile for a contact called <contact> (in
    "user@host" form).
    """
    contact_id, _ = contact_addr.split('@')
    c = Contact.get(int(contact_id))
    if not c or not c.user or not c.user.activated:
        abort(404, 'No such contact')
    diasp = DiasporaContact.get_for_contact(c)

    ns = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
    doc = etree.Element("{%s}XRD" % ns, nsmap={None: ns})
    etree.SubElement(doc, "Subject").text = "acct:%s" % diasp.username
    etree.SubElement(doc, "Alias").text = \
        '"{0}"'.format(url_for('index', _external=True))
    etree.SubElement(
        doc, "Link",
        rel='http://microformats.org/profile/hcard',
        type='text/html',
        href=url_for('.hcard', guid=diasp.guid, _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='http://joindiaspora.com/seed_location',
        type='text/html',
        href=url_for('index', _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='http://joindiaspora.com/guid',
        type='text/html',
        href=diasp.guid
    )
    etree.SubElement(
        doc, "Link",
        rel='http://webfinger.net/rel/profile-page',
        type='text/html',
        href=url_for('contacts.profile', contact_id=c.id, _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='http://schemas.google.com/g/2010#updates-from',
        type='application/atom+xml',
        href=url_for('contacts.feed', contact_id=c.id, _external=True)
    )
    etree.SubElement(
        doc, "Link",
        rel='diaspora-public-key',
        type='RSA',
        href=b64encode(c.public_key.encode('ascii'))
    )

    return send_xml(doc)
コード例 #8
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))
コード例 #9
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))
コード例 #10
0
def pyaspora_subscribe(part, fmt, url):
    """
    Standard message for when a contact subscribes to you.
    """
    from pyaspora.contact.models import Contact
    if fmt != 'text/html' or not part.inline:
        return None

    payload = loads(part.mime_part.body.decode('utf-8'))
    to_contact = Contact.get(payload['to'])
    return render_template_string(
        'subscribed to <a href="{{profile}}">{{name}}</a>',
        profile=url_for('contacts.profile',
                        contact_id=to_contact.id,
                        _external=True),
        name=to_contact.realname)
コード例 #11
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
コード例 #12
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
コード例 #13
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
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)
コード例 #14
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)
コード例 #15
0
ファイル: rendering.py プロジェクト: Zauberstuhl/pyaspora
def pyaspora_subscribe(part, fmt, url):
    """
    Standard message for when a contact subscribes to you.
    """
    from pyaspora.contact.models import Contact
    if fmt != 'text/html' or not part.inline:
        return None

    payload = loads(part.mime_part.body.decode('utf-8'))
    to_contact = Contact.get(payload['to'])
    return render_template_string(
        'subscribed to <a href="{{profile}}">{{name}}</a>',
        profile=url_for(
            'contacts.profile',
            contact_id=to_contact.id,
            _external=True
        ),
        name=to_contact.realname
    )
コード例 #16
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)
コード例 #17
0
def _fill_cache(c, show_shares=False):
    # Fill the cache in bulk, which will also fill the entries
    post_ids = c['post'].keys()
    if post_ids:
        for post_tag in PostTag.get_tags_for_posts(post_ids):
            c['post'][post_tag.post_id]['tags'].append(json_tag(post_tag.tag))
        post_parts = PostPart.get_parts_for_posts(post_ids). \
            order_by(PostPart.order)
        for post_part in post_parts:
            c['post'][post_part.post_id]['parts'].append(json_part(post_part))
        if show_shares:
            for post_share in Share.get_for_posts(post_ids):
                post_id = post_share.post_id
                if not c['post'][post_id]['shares']:
                    c['post'][post_id]['shares'] = []
                c['post'][post_id]['shares'].append(
                    json_share(post_share, cache=c))
    if c['contact']:
        for contact in Contact.get_many(c['contact'].keys()):
            c['contact'][contact.id].update(json_contact(contact))
コード例 #18
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)
コード例 #19
0
ファイル: views.py プロジェクト: Zauberstuhl/pyaspora
def _fill_cache(c, show_shares=False):
    # Fill the cache in bulk, which will also fill the entries
    post_ids = c['post'].keys()
    if post_ids:
        for post_tag in PostTag.get_tags_for_posts(post_ids):
            c['post'][post_tag.post_id]['tags'].append(json_tag(post_tag.tag))
        post_parts = PostPart.get_parts_for_posts(post_ids). \
            order_by(PostPart.order)
        for post_part in post_parts:
            c['post'][post_part.post_id]['parts'].append(json_part(post_part))
        if show_shares:
            for post_share in Share.get_for_posts(post_ids):
                post_id = post_share.post_id
                if not c['post'][post_id]['shares']:
                    c['post'][post_id]['shares'] = []
                c['post'][post_id]['shares'].append(
                    json_share(post_share, cache=c)
                )
    if c['contact']:
        for contact in Contact.get_many(c['contact'].keys()):
            c['contact'][contact.id].update(json_contact(contact))
コード例 #20
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))
コード例 #21
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)