コード例 #1
0
ファイル: feed.py プロジェクト: 0xMF/alpha
 def generate_obj_link(self):
     obj = self.interaction.objects[0] if self.interaction.objects else None
     if self.action == 'follow':
         return 'you'
     elif self.action in ('star', 'reply', 'repost'):
         return html.a(href=smart_reverse(self.request, 'post_detail_view', kwargs={'username': self.request.user.username,
                       'post_id': obj['id']}), *['your post'])
     elif self.action in ('broadcast_create', 'broadcast_subscribe', 'broadcast_unsubscribe'):
         return html.a(href=obj.canonical_url, *[obj.title])
     elif self.action == 'welcome':
         return 'App.net'
     return ''
コード例 #2
0
    def generate_html(self):
        truncated_description = ' '.join(self.target_description.get('text', '').split())
        if len(truncated_description) > 85:
            truncated_description = truncated_description[:82] + " ..."

        classes = ['user-follow-container compact yui3-u-1-4 m-yui3-u-1']
        if self.is_onboarding:
            classes.append('onboarding')

        tree = html.div(class_=classes, *[
            html.a(class_='x-button close icon-remove muted', href='#',
                   data={'not-interested-btn': 1, 'user-id': self.target_id}, alt='Not Interested'),
            html.div(class_='compact-inner', *[
                html.div(class_='yui3-u-1', *[
                    html.a_or_span(class_='avatar', make_link=not self.is_onboarding,
                                   style={'background-image': 'url(%s)' % self.target_avatar},
                                   href=self.target_user_detail_url),
                ]),
                html.div(class_='username ta-center', *[
                    html.a_or_span(href=self.target_user_detail_url, make_link=not self.is_onboarding, *[
                        self.target_username
                    ]),
                ]),
                html.div(class_='post-text note-style user-description-block yui3-u-1 ta-center', *[
                    html.span(truncated_description),
                ]),
                html.div(class_='follow-button-container ta-center', *[
                    self.follow_button_presenter.generate_html()
                ]),
            ])
        ])

        return tree
コード例 #3
0
    def generate_html(self):
        if not self.is_authenticated:
            return ''

        if not self.post_api_obj.user or self.request.user.adn_user.id == self.post_api_obj.user.id:
            return ''

        repost_class = 'icon-repost'
        repost_class += ' reposted' if self.viewer_has_reposted else ''
        title = 'remove repost' if self.viewer_has_reposted else 'repost'
        aria_label = title

        repost_inner = html.a(href='#repost',
                              title=title,
                              data={
                                  'repost-button': 1,
                                  'reposted': int(self.viewer_has_reposted),
                                  'post-id': self.post_api_obj['id']
                              },
                              *[
                                  html.i(class_=repost_class,
                                         **{'aria-label': aria_label}),
                              ])

        return repost_inner
コード例 #4
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_media_block(self, default_size=100):
        # Make a thumbnail for the first photo or video
        media_block = ''
        link_kwargs = None
        photo_annotations = get_photo_annotations(self.post_a.get('annotations', []))
        video_annotations = get_video_annotations(self.post_a.get('annotations', []))

        if photo_annotations:
            icon_class = 'icon-zoom-in'
            value = photo_annotations[0]['value']

            link_kwargs = {
                'href': value.get('embeddable_url', smart_reverse(self.request, 'photo',
                                                                  args=[self.post_a.user.username, self.post_a.id, 1])),
            }

            # keep the :// here
            photos_domain = '://photos.app.net'
            if photos_domain not in link_kwargs['href']:
                link_kwargs['target'] = '_blank'
                link_kwargs['rel'] = 'nofollow'
            else:
                link_kwargs['data-pjax-url'] = smart_reverse(self.request, 'pau.views.alpha.photo', args=[self.post_a.user.username,
                                                             self.post_a.id, 1], force_qualified=True)
        elif video_annotations:
            icon_class = 'icon-play-circle'
            value = video_annotations[0]['value']
            embeddable_url = value.get('embeddable_url')
            if embeddable_url:
                link_kwargs = {
                    'href': embeddable_url,
                    'target': '_blank',
                    'rel': 'nofollow'
                }

        if link_kwargs:
            thumbnail_width = value['thumbnail_width']
            thumbnail_height = value['thumbnail_height']
            thumbnail_url = value.get('thumbnail_url_secure', value['thumbnail_url'])

            try:
                max_width = int(self.request.GET.get('max_width', default_size))
                max_height = int(self.request.GET.get('max_height', default_size))
            except:
                max_width = max_height = default_size

            include_zoom = bool(self.request.GET.get('include_zoom', True))
            display_width, display_height = map(str, fit_to_box(thumbnail_width, thumbnail_height, max_width, max_height))

            media_block = [
                html.div(class_='post-media', *[
                    html.a(class_="shadow-overlay", data=self.click_data, *[
                        html.i(class_=icon_class) if include_zoom else ''
                    ], **link_kwargs),
                    html.div(class_='inner-shadow-overlay'),
                    html.img(src=thumbnail_url, width=display_width, height=display_height)
                ])
            ]

        return media_block
コード例 #5
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def _generate_facepile(self, user):
        facepile_size = 40 * 2
        facepile_img_url = append_query_string(user.avatar_image.url, params={'w': facepile_size, 'h': facepile_size})

        facepile_block = html.a(href=self._user_link(user), *[
            html.img(class_=('interaction-facepile',), alt=user['username'], title=user['username'], src=facepile_img_url)
        ])
        return facepile_block
コード例 #6
0
ファイル: messages.py プロジェクト: jvimedia/alpha
 def generate_in_reply_to_container(self):
     return html.div(class_='hide in-reply-to layout-like-p subpixel', data={'in-reply-to': 1}, *[
         html.div(html.em(*['In Reply To:'])),
         html.div(class_='well-style reply-to', *[
             html.a(href='#', class_='close relative space-5', data={'remove-reply': 1}, *[
                 html.i(class_='icon-remove')
             ]),
             html.div(class_='post-container subpixel', data={'post-copy': 1})
         ])
     ])
コード例 #7
0
ファイル: feed.py プロジェクト: 0xMF/alpha
 def generate_html(self):
     avatar_size = '30s'
     max_num_faces = 5
     li_fn = lambda user: html.li(class_='yui3-u', title=user.username, *[
         html.a(href=smart_reverse(self.request, 'user_detail_view', args=[user.username]), class_='avatar facepile-size', style={'background-image': 'url(%s)' % user.avatar_image.get(avatar_size, '')})
     ])
     tree = html.ul(
         *[li_fn(user) for user in self.starred_by[:max_num_faces]]
     )
     return tree
コード例 #8
0
 def generate_obj_link(self):
     obj = self.interaction.objects[0] if self.interaction.objects else None
     if self.action == 'follow':
         return 'you'
     elif self.action in ('star', 'reply', 'repost'):
         return html.a(href=smart_reverse(self.request,
                                          'post_detail_view',
                                          kwargs={
                                              'username':
                                              self.request.user.username,
                                              'post_id': obj['id']
                                          }),
                       *['your post'])
     elif self.action in ('broadcast_create', 'broadcast_subscribe',
                          'broadcast_unsubscribe'):
         return html.a(href=obj.canonical_url, *[obj.title])
     elif self.action == 'welcome':
         return 'App.net'
     return ''
コード例 #9
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_html(self):
        if self.post_a.get('is_deleted') and not self.show_deleted:
            return ''

        post_data = {
            'post-id': self.post_a.id,
            # Should the post be remove from the page.
            # or should we insert [deleted] text
            'post-remove-from-page': '0' if self.show_deleted else '1'
        }

        if self.post_a.user:
            post_data['post-author-username'] = self.post_a.user.username
            post_data['post-author-id'] = self.post_a.user.id
        else:
            post_data['post-author-deleted'] = '1'

        if self.repost:
            post_data['post-parent-id'] = self.repost.id

        classes = ['post-container', 'subpixel']
        if not self.single_post and self.in_conversation:
            classes += ['p-in-reply-to', 'h-cite']
        else:
            classes += ['h-entry']

        if self.post_a.get('is_deleted'):
            classes.append('deleted')
        if self.hidden:
            classes.append('hide')

        avatar_size = 114
        avatar_classes = ['avatar']
        if self.single_post:
            classes.append('single-post-container')
            avatar_classes.append('large')
            avatar_size = 160

        avatar_block = ''
        if self.post_a.user:
            avatar_url = append_query_string(self.post_a.user.avatar_image.url, params={'w': avatar_size, 'h': avatar_size})
            avatar_block = html.div(class_='media', *[
                html.a(class_=avatar_classes, data=self.click_data, style={'background-image': 'url(%s)' % avatar_url},
                       href=self.user_detail_url)
            ])

        tree = html.div(class_=classes, data=post_data, name=str(self.post_a.id), *[
            html.div(class_='content', *[
                avatar_block,
                self.generate_post_header(),
                self.generate_post_body(),
                self.generate_post_footer()
            ]),
        ])
        return tree
コード例 #10
0
 def reply_button(self):
     href = '#' if self.reply_link_format == 'to_self' else self.post_detail_url
     data = {'reply-to': ''}
     data.update(self.click_data)
     tree = html.li(class_='show-on-hover yui3-u',
                    *[
                        html.a(href=href,
                               data=data,
                               *[html.i(class_='icon-share-alt'), " Reply"])
                    ])
     return tree
コード例 #11
0
ファイル: feed.py プロジェクト: 0xMF/alpha
 def reply_button(self):
     href = '#' if self.reply_link_format == 'to_self' else self.post_detail_url
     data = {'reply-to': ''}
     data.update(self.click_data)
     tree = html.li(class_='show-on-hover yui3-u', *[
         html.a(href=href, data=data, *[
             html.i(class_='icon-share-alt'),
             " Reply"
         ])
     ])
     return tree
コード例 #12
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_html(self):
        if not self.is_authenticated:
            return ''

        star_class = 'icon-star-empty'
        aria_label = 'star'
        if self.viewer_has_starred:
            star_class = 'icon-star'
            aria_label = 'unstar'

        star_inner = html.a(href='#star', data={'star-button': 1, 'starred': int(self.viewer_has_starred), 'post-id': self.post_api_obj['id']}, *[
            html.i(class_=star_class, **{'aria-label': aria_label})
        ])

        return star_inner
コード例 #13
0
    def _generate_facepile(self, user):
        facepile_size = 40 * 2
        facepile_img_url = append_query_string(user.avatar_image.url,
                                               params={
                                                   'w': facepile_size,
                                                   'h': facepile_size
                                               })

        facepile_block = html.a(href=self._user_link(user),
                                *[
                                    html.img(class_=('interaction-facepile', ),
                                             alt=user['username'],
                                             title=user['username'],
                                             src=facepile_img_url)
                                ])
        return facepile_block
コード例 #14
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_html(self):
        if not self.is_authenticated:
            return ''

        if not self.post_api_obj.user or self.request.user.adn_user.id == self.post_api_obj.user.id:
            return ''

        repost_class = 'icon-repost'
        repost_class += ' reposted' if self.viewer_has_reposted else ''
        title = 'remove repost' if self.viewer_has_reposted else 'repost'
        aria_label = title

        repost_inner = html.a(href='#repost', title=title, data={'repost-button': 1, 'reposted': int(self.viewer_has_reposted), 'post-id': self.post_api_obj['id']}, *[
            html.i(class_=repost_class, **{'aria-label': aria_label}),
        ])

        return repost_inner
コード例 #15
0
 def generate_html(self):
     avatar_size = '30s'
     max_num_faces = 5
     li_fn = lambda user: html.li(
         class_='yui3-u',
         title=user.username,
         *[
             html.a(href=smart_reverse(
                 self.request, 'user_detail_view', args=[user.username]),
                    class_='avatar facepile-size',
                    style={
                        'background-image':
                        'url(%s)' % user.avatar_image.get(avatar_size, '')
                    })
         ])
     tree = html.ul(
         *[li_fn(user) for user in self.starred_by[:max_num_faces]])
     return tree
コード例 #16
0
    def generate_html(self):
        if not self.is_authenticated:
            return ''

        star_class = 'icon-star-empty'
        aria_label = 'star'
        if self.viewer_has_starred:
            star_class = 'icon-star'
            aria_label = 'unstar'

        star_inner = html.a(
            href='#star',
            data={
                'star-button': 1,
                'starred': int(self.viewer_has_starred),
                'post-id': self.post_api_obj['id']
            },
            *[html.i(class_=star_class, **{'aria-label': aria_label})])

        return star_inner
コード例 #17
0
    def generate_post_header(self):
        username_block = html.span(class_='username')

        if self.post_a.user:
            username_block = html.span(class_='username p-author h-card',
                                       *[
                                           html.a(href=self.user_detail_url,
                                                  data=self.click_data,
                                                  class_='p-nickname u-url',
                                                  *[self.post_a.user.username])
                                       ])

        header_items = []

        # star this post
        if self.is_authenticated:
            if self.show_star_button:
                star_presenter = StarPresenter.from_data(
                    self.request, self.post_a)
                star_html = star_presenter.generate_html()
                header_items.append(html.li(class_='yui3-u', *[star_html]))

            if self.show_repost_button:
                repost_button = RepostButtonPresenter.from_data(
                    self.request, self.post_a)
                repost_button_html = repost_button.generate_html()
                if repost_button_html != '':
                    header_items.append(
                        html.li(class_='yui3-u repost', *[repost_button_html]))

        return html.div(
            class_='post-header',
            *[
                username_block,
                html.
                ul(class_='ul-horizontal unstyled yui3-u fixed-right ta-right',
                   *header_items)
            ])
        return username_block
コード例 #18
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_post_header(self):
        username_block = html.span(class_='username')

        if self.post_a.user:
            username_block = html.span(class_='username p-author h-card', *[
                html.a(href=self.user_detail_url, data=self.click_data, class_='p-nickname u-url', *[
                    self.post_a.user.username
                ])
            ])

        header_items = []

        # star this post
        if self.is_authenticated:
            if self.show_star_button:
                star_presenter = StarPresenter.from_data(self.request, self.post_a)
                star_html = star_presenter.generate_html()
                header_items.append(
                    html.li(class_='yui3-u', *[
                        star_html
                    ])
                )

            if self.show_repost_button:
                repost_button = RepostButtonPresenter.from_data(self.request, self.post_a)
                repost_button_html = repost_button.generate_html()
                if repost_button_html != '':
                    header_items.append(
                        html.li(class_='yui3-u repost', *[
                            repost_button_html
                        ])
                    )

        return html.div(class_='post-header', *[
            username_block,
            html.ul(class_='ul-horizontal unstyled yui3-u fixed-right ta-right', *header_items)
        ])
        return username_block
コード例 #19
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_html(self):
        data = {
            'backfill-control': 1,
            'before-id': self.min_id,
            'since-id': self.marker_id,
        }

        return [
            html.div(class_='backfill-container', *[
                html.div(class_='content ta-center', *[
                    html.a(href='#', data=data, *[
                        html.span(class_='yui3-u', *[
                            html.i(class_='icon-circle-arrow-up')
                        ]),
                        html.span(class_='yui3-u text', *[
                            ' Load More'
                        ])
                    ]),
                    html.div(class_='hide spinner-container', *[
                        html.span(class_='loading-spinner hide', *[''])
                    ]),
                ]),
            ])]
コード例 #20
0
    def generate_html(self):
        data = {
            'backfill-control': 1,
            'before-id': self.min_id,
            'since-id': self.marker_id,
        }

        return [
            html.div(
                class_='backfill-container',
                *[
                    html.div(
                        class_='content ta-center',
                        *[
                            html.a(
                                href='#',
                                data=data,
                                *[
                                    html.span(
                                        class_='yui3-u',
                                        *[
                                            html.i(
                                                class_='icon-circle-arrow-up')
                                        ]),
                                    html.span(class_='yui3-u text',
                                              *[' Load More'])
                                ]),
                            html.div(class_='hide spinner-container',
                                     *[
                                         html.span(
                                             class_='loading-spinner hide',
                                             *[''])
                                     ]),
                        ]),
                ])
        ]
コード例 #21
0
ファイル: feed.py プロジェクト: 0xMF/alpha
def build_tree_from_text_entity_pack(request, text_entity_pack, itemscope='https://join.app.net/schemas/Post', convert_new_lines=False):
    # adapted from omo models TextEntityPack.html
    def entity_text(e):
        return text_entity_pack['text'][e['pos']:e['pos'] + e['len']]

    mention_builder = lambda m: html.a(
        itemprop='mention',
        data={
            'mention-name': m['name'], 'mention-id': m['id']
        },
        href=smart_reverse(request, 'user_detail_view', args=[m['name']], force_qualified=True),
        *[entity_text(m)]
    )
    hashtag_builder = lambda h: html.a(
        itemprop='hashtag',
        data={
            'hashtag-name': h['name']
        },
        href=smart_reverse(request, 'hashtags', args=[h['name']], force_qualified=True),
        *[entity_text(h)]
    )
    link_builder = lambda l: html.a(href=l['url'], target="_blank", rel='nofollow', *[entity_text(l)])

    # map starting position, length of entity placeholder to the replacement html
    entity_map = {}
    for entity_key, builder in [('mentions', mention_builder), ('hashtags', hashtag_builder), ('links', link_builder)]:
        for entity in text_entity_pack.get('entities', {}).get(entity_key, []):
            try:
                entity_map[(entity['pos'], entity['len'])] = builder(entity)
            except NoReverseMatch:
                logger.warning('Could not build link for entity=%s in Pau path %s.', entity.get('name'), request.path)

    # replace strings with html
    html_pieces = []
    text_idx = 0  # our current place in the original text string
    for entity_start, entity_len in sorted(entity_map.keys()):
        if text_idx != entity_start:
            # if our current place isn't the start of an entity, bring in text until the next entity
            html_pieces.append(text_entity_pack.get('text', "")[text_idx:entity_start])

        # pull out the entity html
        entity_html = entity_map[(entity_start, entity_len)]
        html_pieces.append(entity_html)

        # move past the entity we just added
        text_idx = entity_start + entity_len

    # clean up any remaining text
    html_pieces.append(text_entity_pack.get('text', "")[text_idx:])
    if convert_new_lines:
        new_html_pieces = []
        for piece in html_pieces:
            if isinstance(piece, basestring) and '\n' in piece:
                new_html_pieces += list(intersperse(html.br(), piece.split('\n')))
            else:
                new_html_pieces.append(piece)

        html_pieces = new_html_pieces

    # TODO: link to schema
    return html.span(itemscope=itemscope, *html_pieces)
コード例 #22
0
ファイル: feed.py プロジェクト: 0xMF/alpha
    def generate_post_footer(self):
        if self.post_a.get('is_deleted'):
            return ''

        footer_top_row = []
        # repost
        # N.B. if you change this html (reposts), make sure to change the ajax handler for repost,
        # which duplicates this html to provide client-side feedback
        viewer_has_reposted = self.post_a.get('you_reposted')
        if self.repost or viewer_has_reposted:
            # yes, there is a priority order of reposter info - viewer trumps everyone else
            if viewer_has_reposted:
                reposter_username = self.request.user.username
                reposter_display = 'you'
            elif self.repost:
                reposter_username = self.repost.user.username
                reposter_display = '@' + reposter_username
            footer_top_row.append(
                html.div(class_='post-reposted-by yui3-u', *[
                    html.span(class_='reposted-by-text', *[
                        html.i(class_='icon-repost'),
                        html.span(' Reposted by ', *[
                            html.a(href=smart_reverse(self.request, 'user_detail_view', args=[reposter_username]),
                                   data=self.click_data, *[reposter_display]),
                        ])
                    ])
                ])
            )

        # place
        place_annotation = get_place_annotation(self.post_a.get('annotations', []))
        if place_annotation:
            if place_annotation['value'].get('address'):
                place_pretty = u'%s \u2014 %s' % (place_annotation['value']['name'], place_annotation['value']['address'])
            else:
                place_pretty = u'%s' % place_annotation['value']['name']

            tags_html = []
            if place_annotation.get('type') == 'net.app.core.checkin':
                factual_url = urljoin('http://factual.com/', place_annotation['value']['factual_id'])
                tags_html.append(html.meta(name="factual", content=factual_url))
            tags_html.append(html.span(class_='posted-from-text', *[
                html.i(class_='icon-pushpin'),
                html.span(' at %s' % place_pretty),
            ]))
            footer_top_row.append(html.div(class_='post-posted-from-place yui3-u', *tags_html))
        footer_bottom_row = []

        # timestamp
        timezone_str = self.request.user.adn_user.timezone if self.is_authenticated else 'America/Los_Angeles'
        viewers_timezone = pytz.timezone(timezone_str)
        non_relative_timestamp = pytz.utc.localize(self.post_a.created_at).astimezone(viewers_timezone)
        datetime_formatted = non_relative_timestamp.strftime("%I:%M %p - %d %b %Y")
        footer_bottom_row.append(html.li(
            html.a(href=self.post_detail_url, data=self.click_data, class_='timestamp u-url', title=datetime_formatted, *[
                html.time(class_='dt-published', datetime=datetime_formatted, *[
                    html.i(class_='icon-time yui3-u'),
                    " " + naturaldate(self.post_a.created_at),
                ])
            ])),
        )

        is_reply = hasattr(self.post_a, 'reply_to') and self.post_a.reply_to
        reply_to_hash = "#" + str(self.post_a.reply_to) if is_reply else ''
        # conversation active?
        if is_reply or (self.post_a.num_replies > 0 and not self.single_post):
            footer_bottom_row.append(
                html.li(class_='in-reply-to yui3-u', *[
                    html.a(href=self.post_detail_url + reply_to_hash, data=self.click_data, title='In Reply To...', *[
                        html.i(class_='icon-comments', **{'aria-label': 'In Reply To...'})
                        ])
                ])
            )

        # reply
        if self.is_authenticated and self.show_reply_button:
            footer_bottom_row.append(self.reply_button())

        if self.show_stream_marker:
            data = {
                'set-stream-marker': ''
            }

            footer_bottom_row.append(
                html.li(class_='show-on-hover yui3-u stream-marker-button', *[
                    html.a(href='#', data=data, *[
                        html.i(class_='icon-bookmark'),
                        ""
                        ])
                ])
            )

        if self.post_a.source and self.show_via_attribution:
            source_link = getattr(self.post_a.source, 'link', None)
            source_name = getattr(self.post_a.source, 'name', None)
            if source_link and source_name:
                footer_bottom_row.append(
                    html.li(class_='show-on-hover post-source yui3-u', *[
                        html.a(href=self.post_a.source.link, rel='nofollow', target='_blank', *[
                            html.i(class_='icon-share'),
                            ' via ' + source_name
                            ])
                    ])
                )

        # crosspost
        annotations = self.post_a.get('annotations', [])
        cp_url = None
        for a in annotations:
            annotation_type = a.get('type')
            if annotation_type == "net.app.core.crosspost":
                cp_url = a.get('value', {}).get('canonical_url')
                if cp_url and not re.match('^https?://', cp_url, re.IGNORECASE):
                    cp_url = "http://" + cp_url

        if cp_url:
            cp_url_display = urlparse(cp_url).netloc
            if cp_url_display.startswith('www.'):
                cp_url_display = cp_url_display[4:]
            footer_bottom_row.append(
                html.li(class_='show-on-hover crossposted-from yui3-u', *[
                    html.a(href=cp_url, target='_blank', *[
                        html.i(class_='icon-random'),
                        ' from ' + cp_url_display
                        ])
                ])
            )

        # report this post to app.net
        if self.show_report_button:
            if self.is_authenticated and self.request.user.adn_user.id != self.post_a.user.id:
                footer_bottom_row.append(
                    html.li(class_='show-on-hover last pull-right yui3-u', *[
                        html.a(href='#report', data={'post-report': ''}, *[
                            html.i(class_='icon-flag'),
                            html.span(class_='t-yui3-u-none m-yui3-u-none', *[' Report']),
                            ])
                    ])
                )

        # mute this user--it's not really an if/else with the delete case so I'm not combining the conditions
        if self.show_mute_button:
            if self.is_authenticated and self.request.user.adn_user.id != self.post_a.user.id and not self.post_a.user.you_muted:
                footer_bottom_row.append(
                    html.li(class_='show-on-hover pull-right yui3-u', *[
                        html.a(href='#mute-user', data={'post-mute-user': ''}, *[
                            html.i(class_='icon-minus-sign'),
                            html.span(class_='t-yui3-u-none m-yui3-u-none', *[' Mute user']),
                            ])
                    ])
                )

        # delete this post
        if self.show_delete_button:
            if self.is_authenticated and self.request.user.adn_user.id == self.post_a.user.id:
                footer_bottom_row.append(
                    html.li(class_='show-on-hover last pull-right yui3-u', *[
                        html.a(href='#delete', data={'post-delete': ''}, *[
                            html.i(class_='icon-remove'),
                            html.span(class_='t-yui3-u-none m-yui3-u-none', *[' Delete']),
                            ])
                    ])
                )

        tree = html.div(class_='post-footer', *[
            html.ul(class_='ul-horizontal unstyled footer-top', *footer_top_row),
            html.ul(class_='ul-horizontal unstyled footer-bottom', *footer_bottom_row)
        ])

        return tree
コード例 #23
0
    def generate_post_footer(self):
        if self.post_a.get('is_deleted'):
            return ''

        footer_top_row = []
        # repost
        # N.B. if you change this html (reposts), make sure to change the ajax handler for repost,
        # which duplicates this html to provide client-side feedback
        viewer_has_reposted = self.post_a.get('you_reposted')
        if self.repost or viewer_has_reposted:
            # yes, there is a priority order of reposter info - viewer trumps everyone else
            if viewer_has_reposted:
                reposter_username = self.request.user.username
                reposter_display = 'you'
            elif self.repost:
                reposter_username = self.repost.user.username
                reposter_display = '@' + reposter_username
            footer_top_row.append(
                html.div(class_='post-reposted-by yui3-u',
                         *[
                             html.span(
                                 class_='reposted-by-text',
                                 *[
                                     html.i(class_='icon-repost'),
                                     html.span(
                                         ' Reposted by ', *[
                                             html.a(href=smart_reverse(
                                                 self.request,
                                                 'user_detail_view',
                                                 args=[reposter_username]),
                                                    data=self.click_data,
                                                    *[reposter_display]),
                                         ])
                                 ])
                         ]))

        # place
        place_annotation = get_place_annotation(
            self.post_a.get('annotations', []))
        if place_annotation:
            if place_annotation['value'].get('address'):
                place_pretty = u'%s \u2014 %s' % (
                    place_annotation['value']['name'],
                    place_annotation['value']['address'])
            else:
                place_pretty = u'%s' % place_annotation['value']['name']

            tags_html = []
            if place_annotation.get('type') == 'net.app.core.checkin':
                factual_url = urljoin('http://factual.com/',
                                      place_annotation['value']['factual_id'])
                tags_html.append(html.meta(name="factual",
                                           content=factual_url))
            tags_html.append(
                html.span(class_='posted-from-text',
                          *[
                              html.i(class_='icon-pushpin'),
                              html.span(' at %s' % place_pretty),
                          ]))
            footer_top_row.append(
                html.div(class_='post-posted-from-place yui3-u', *tags_html))
        footer_bottom_row = []

        # timestamp
        timezone_str = self.request.user.adn_user.timezone if self.is_authenticated else 'America/Los_Angeles'
        viewers_timezone = pytz.timezone(timezone_str)
        non_relative_timestamp = pytz.utc.localize(
            self.post_a.created_at).astimezone(viewers_timezone)
        datetime_formatted = non_relative_timestamp.strftime(
            "%I:%M %p - %d %b %Y")
        footer_bottom_row.append(
            html.li(
                html.a(href=self.post_detail_url,
                       data=self.click_data,
                       class_='timestamp u-url',
                       title=datetime_formatted,
                       *[
                           html.time(class_='dt-published',
                                     datetime=datetime_formatted,
                                     *[
                                         html.i(class_='icon-time yui3-u'),
                                         " " +
                                         naturaldate(self.post_a.created_at),
                                     ])
                       ])), )

        is_reply = hasattr(self.post_a, 'reply_to') and self.post_a.reply_to
        reply_to_hash = "#" + str(self.post_a.reply_to) if is_reply else ''
        # conversation active?
        if is_reply or (self.post_a.num_replies > 0 and not self.single_post):
            footer_bottom_row.append(
                html.li(class_='in-reply-to yui3-u',
                        *[
                            html.a(href=self.post_detail_url + reply_to_hash,
                                   data=self.click_data,
                                   title='In Reply To...',
                                   *[
                                       html.i(
                                           class_='icon-comments',
                                           **{'aria-label': 'In Reply To...'})
                                   ])
                        ]))

        # reply
        if self.is_authenticated and self.show_reply_button:
            footer_bottom_row.append(self.reply_button())

        if self.show_stream_marker:
            data = {'set-stream-marker': ''}

            footer_bottom_row.append(
                html.li(class_='show-on-hover yui3-u stream-marker-button',
                        *[
                            html.a(href='#',
                                   data=data,
                                   *[html.i(class_='icon-bookmark'), ""])
                        ]))

        if self.post_a.source and self.show_via_attribution:
            source_link = getattr(self.post_a.source, 'link', None)
            source_name = getattr(self.post_a.source, 'name', None)
            if source_link and source_name:
                footer_bottom_row.append(
                    html.li(class_='show-on-hover post-source yui3-u',
                            *[
                                html.a(href=self.post_a.source.link,
                                       rel='nofollow',
                                       target='_blank',
                                       *[
                                           html.i(class_='icon-share'),
                                           ' via ' + source_name
                                       ])
                            ]))

        # crosspost
        annotations = self.post_a.get('annotations', [])
        cp_url = None
        for a in annotations:
            annotation_type = a.get('type')
            if annotation_type == "net.app.core.crosspost":
                cp_url = a.get('value', {}).get('canonical_url')
                if cp_url and not re.match('^https?://', cp_url,
                                           re.IGNORECASE):
                    cp_url = "http://" + cp_url

        if cp_url:
            cp_url_display = urlparse(cp_url).netloc
            if cp_url_display.startswith('www.'):
                cp_url_display = cp_url_display[4:]
            footer_bottom_row.append(
                html.li(class_='show-on-hover crossposted-from yui3-u',
                        *[
                            html.a(href=cp_url,
                                   target='_blank',
                                   *[
                                       html.i(class_='icon-random'),
                                       ' from ' + cp_url_display
                                   ])
                        ]))

        # report this post to app.net
        if self.show_report_button:
            if self.is_authenticated and self.request.user.adn_user.id != self.post_a.user.id:
                footer_bottom_row.append(
                    html.li(
                        class_='show-on-hover last pull-right yui3-u',
                        *[
                            html.a(
                                href='#report',
                                data={'post-report': ''},
                                *[
                                    html.i(class_='icon-flag'),
                                    html.span(
                                        class_='t-yui3-u-none m-yui3-u-none',
                                        *[' Report']),
                                ])
                        ]))

        # mute this user--it's not really an if/else with the delete case so I'm not combining the conditions
        if self.show_mute_button:
            if self.is_authenticated and self.request.user.adn_user.id != self.post_a.user.id and not self.post_a.user.you_muted:
                footer_bottom_row.append(
                    html.li(
                        class_='show-on-hover pull-right yui3-u',
                        *[
                            html.a(
                                href='#mute-user',
                                data={'post-mute-user': ''},
                                *[
                                    html.i(class_='icon-minus-sign'),
                                    html.span(
                                        class_='t-yui3-u-none m-yui3-u-none',
                                        *[' Mute user']),
                                ])
                        ]))

        # delete this post
        if self.show_delete_button:
            if self.is_authenticated and self.request.user.adn_user.id == self.post_a.user.id:
                footer_bottom_row.append(
                    html.li(
                        class_='show-on-hover last pull-right yui3-u',
                        *[
                            html.a(
                                href='#delete',
                                data={'post-delete': ''},
                                *[
                                    html.i(class_='icon-remove'),
                                    html.span(
                                        class_='t-yui3-u-none m-yui3-u-none',
                                        *[' Delete']),
                                ])
                        ]))

        tree = html.div(class_='post-footer',
                        *[
                            html.ul(class_='ul-horizontal unstyled footer-top',
                                    *footer_top_row),
                            html.ul(
                                class_='ul-horizontal unstyled footer-bottom',
                                *footer_bottom_row)
                        ])

        return tree
コード例 #24
0
 def generate_html(self):
     tree = html.a(href=self.target_user_detail_url, data=self.click_data, *[
         self.target_username
     ])
     return tree
コード例 #25
0
    def generate_media_block(self, default_size=100):
        # Make a thumbnail for the first photo or video
        media_block = ''
        link_kwargs = None
        photo_annotations = get_photo_annotations(
            self.post_a.get('annotations', []))
        video_annotations = get_video_annotations(
            self.post_a.get('annotations', []))

        if photo_annotations:
            icon_class = 'icon-zoom-in'
            value = photo_annotations[0]['value']

            link_kwargs = {
                'href':
                value.get(
                    'embeddable_url',
                    smart_reverse(
                        self.request,
                        'photo',
                        args=[self.post_a.user.username, self.post_a.id, 1])),
            }

            # keep the :// here
            photos_domain = '://photos.app.net'
            if photos_domain not in link_kwargs['href']:
                link_kwargs['target'] = '_blank'
                link_kwargs['rel'] = 'nofollow'
            else:
                link_kwargs['data-pjax-url'] = smart_reverse(
                    self.request,
                    'pau.views.alpha.photo',
                    args=[self.post_a.user.username, self.post_a.id, 1],
                    force_qualified=True)
        elif video_annotations:
            icon_class = 'icon-play-circle'
            value = video_annotations[0]['value']
            embeddable_url = value.get('embeddable_url')
            if embeddable_url:
                link_kwargs = {
                    'href': embeddable_url,
                    'target': '_blank',
                    'rel': 'nofollow'
                }

        if link_kwargs:
            thumbnail_width = value['thumbnail_width']
            thumbnail_height = value['thumbnail_height']
            thumbnail_url = value.get('thumbnail_url_secure',
                                      value['thumbnail_url'])

            try:
                max_width = int(self.request.GET.get('max_width',
                                                     default_size))
                max_height = int(
                    self.request.GET.get('max_height', default_size))
            except:
                max_width = max_height = default_size

            include_zoom = bool(self.request.GET.get('include_zoom', True))
            display_width, display_height = map(
                str,
                fit_to_box(thumbnail_width, thumbnail_height, max_width,
                           max_height))

            media_block = [
                html.div(class_='post-media',
                         *[
                             html.a(class_="shadow-overlay",
                                    data=self.click_data,
                                    *[
                                        html.i(class_=icon_class)
                                        if include_zoom else ''
                                    ],
                                    **link_kwargs),
                             html.div(class_='inner-shadow-overlay'),
                             html.img(src=thumbnail_url,
                                      width=display_width,
                                      height=display_height)
                         ])
            ]

        return media_block
コード例 #26
0
def build_tree_from_text_entity_pack(
        request,
        text_entity_pack,
        itemscope='https://join.app.net/schemas/Post',
        convert_new_lines=False):
    # adapted from omo models TextEntityPack.html
    def entity_text(e):
        return text_entity_pack['text'][e['pos']:e['pos'] + e['len']]

    mention_builder = lambda m: html.a(itemprop='mention',
                                       data={
                                           'mention-name': m['name'],
                                           'mention-id': m['id']
                                       },
                                       href=smart_reverse(request,
                                                          'user_detail_view',
                                                          args=[m['name']],
                                                          force_qualified=True
                                                          ),
                                       *[entity_text(m)])
    hashtag_builder = lambda h: html.a(
        itemprop='hashtag',
        data={'hashtag-name': h['name']},
        href=smart_reverse(
            request, 'hashtags', args=[h['name']], force_qualified=True),
        *[entity_text(h)])
    link_builder = lambda l: html.a(
        href=l['url'], target="_blank", rel='nofollow', *[entity_text(l)])

    # map starting position, length of entity placeholder to the replacement html
    entity_map = {}
    for entity_key, builder in [('mentions', mention_builder),
                                ('hashtags', hashtag_builder),
                                ('links', link_builder)]:
        for entity in text_entity_pack.get('entities', {}).get(entity_key, []):
            try:
                entity_map[(entity['pos'], entity['len'])] = builder(entity)
            except NoReverseMatch:
                logger.warning(
                    'Could not build link for entity=%s in Pau path %s.',
                    entity.get('name'), request.path)

    # replace strings with html
    html_pieces = []
    text_idx = 0  # our current place in the original text string
    for entity_start, entity_len in sorted(entity_map.keys()):
        if text_idx != entity_start:
            # if our current place isn't the start of an entity, bring in text until the next entity
            html_pieces.append(
                text_entity_pack.get('text', "")[text_idx:entity_start])

        # pull out the entity html
        entity_html = entity_map[(entity_start, entity_len)]
        html_pieces.append(entity_html)

        # move past the entity we just added
        text_idx = entity_start + entity_len

    # clean up any remaining text
    html_pieces.append(text_entity_pack.get('text', "")[text_idx:])
    if convert_new_lines:
        new_html_pieces = []
        for piece in html_pieces:
            if isinstance(piece, basestring) and '\n' in piece:
                new_html_pieces += list(
                    intersperse(html.br(), piece.split('\n')))
            else:
                new_html_pieces.append(piece)

        html_pieces = new_html_pieces

    # TODO: link to schema
    return html.span(itemscope=itemscope, *html_pieces)
コード例 #27
0
    def generate_html(self):
        if self.post_a.get('is_deleted') and not self.show_deleted:
            return ''

        post_data = {
            'post-id': self.post_a.id,
            # Should the post be remove from the page.
            # or should we insert [deleted] text
            'post-remove-from-page': '0' if self.show_deleted else '1'
        }

        if self.post_a.user:
            post_data['post-author-username'] = self.post_a.user.username
            post_data['post-author-id'] = self.post_a.user.id
        else:
            post_data['post-author-deleted'] = '1'

        if self.repost:
            post_data['post-parent-id'] = self.repost.id

        classes = ['post-container', 'subpixel']
        if not self.single_post and self.in_conversation:
            classes += ['p-in-reply-to', 'h-cite']
        else:
            classes += ['h-entry']

        if self.post_a.get('is_deleted'):
            classes.append('deleted')
        if self.hidden:
            classes.append('hide')

        avatar_size = 114
        avatar_classes = ['avatar']
        if self.single_post:
            classes.append('single-post-container')
            avatar_classes.append('large')
            avatar_size = 160

        avatar_block = ''
        if self.post_a.user:
            avatar_url = append_query_string(self.post_a.user.avatar_image.url,
                                             params={
                                                 'w': avatar_size,
                                                 'h': avatar_size
                                             })
            avatar_block = html.div(
                class_='media',
                *[
                    html.a(class_=avatar_classes,
                           data=self.click_data,
                           style={'background-image': 'url(%s)' % avatar_url},
                           href=self.user_detail_url)
                ])

        tree = html.div(class_=classes,
                        data=post_data,
                        name=str(self.post_a.id),
                        *[
                            html.div(class_='content',
                                     *[
                                         avatar_block,
                                         self.generate_post_header(),
                                         self.generate_post_body(),
                                         self.generate_post_footer()
                                     ]),
                        ])
        return tree
コード例 #28
0
 def _generate_source_user(self, user):
     if user['id'] == self.request.user.adn_user.id:
         return 'You'
     else:
         return html.a(href=self._user_link(user), *[user['username']])
コード例 #29
0
 def generate_html(self):
     tree = html.a(class_='avatar', style={'background-image': 'url(%s)' % self.target_avatar},
                   href=self.target_user_detail_url, data=self.click_data)
     return tree
コード例 #30
0
ファイル: feed.py プロジェクト: 0xMF/alpha
 def _generate_source_user(self, user):
     if user['id'] == self.request.user.adn_user.id:
         return 'You'
     else:
         return html.a(href=self._user_link(user), *[user['username']])