def ajax_author_overview(user_id, page): author = Author.get(id=user_id) if not author: abort(404) comments_list = StoryComment.select(lambda x: x.author == author and not x.deleted and x.story_published) comments_list = comments_list.order_by(StoryComment.id.desc()) comments_count = comments_list.count() paged = Paginator( number=page, total=comments_count, per_page=current_app.config['COMMENTS_COUNT']['author_page'], ) # TODO: restore orphans? comments = paged.slice(comments_list) if not comments and page != 1: abort(404) data = { 'author': author, 'comments': comments, 'page_obj': paged, 'comments_short': True, } data.update(cached_lists([x.story.id for x in comments])) return jsonify({ 'success': True, 'link': url_for('author.info', user_id=author.id, comments_page=page), 'comments_count': comments_count, 'comments_list': render_template('includes/story_comments_list.html', **data), 'pagination': render_template('includes/comments_pagination_author_overview.html', **data), })
def comments(page): objects = StoryComment.select(lambda x: x.story_published) filter_deleted = current_user.is_staff and request.args.get( 'deleted') == '1' if filter_deleted: objects = objects.filter(lambda x: x.deleted).order_by( StoryComment.last_deleted_at.desc()) else: objects = objects.filter(lambda x: not x.deleted).order_by( StoryComment.id.desc()) page_obj = Paginator( page, objects.count(), per_page=current_app.config['COMMENTS_COUNT']['stream']) objects = [('story', x) for x in page_obj.slice_or_404(objects)] comment_votes_cache = Story.bl.select_comment_votes( current_user._get_current_object(), [x[1].id for x in objects]) if current_user.is_authenticated else {} return render_template('stream/comments.html', page_title='Лента комментариев', tab='story', comments=objects, filter_deleted=filter_deleted, with_target_link=True, comment_votes_cache=comment_votes_cache, page_obj=page_obj, robots_noindex=True, **cached_lists([x[1].story.id for x in objects]))
def comments(page): objects = StoryComment.select(lambda x: x.story_published) filter_deleted = current_user.is_staff and request.args.get('deleted') == '1' if filter_deleted: objects = objects.filter(lambda x: x.deleted).order_by(StoryComment.last_deleted_at.desc()) else: objects = objects.filter(lambda x: not x.deleted).order_by(StoryComment.id.desc()) page_obj = Paginator(page, objects.count(), per_page=current_app.config['COMMENTS_COUNT']['stream']) objects = [('story', x) for x in page_obj.slice_or_404(objects)] comment_votes_cache = Story.bl.select_comment_votes( current_user._get_current_object(), [x[1].id for x in objects] ) if current_user.is_authenticated else {} return render_template( 'stream/comments.html', page_title='Лента комментариев', tab='story', comments=objects, filter_deleted=filter_deleted, with_target_link=True, comment_votes_cache=comment_votes_cache, page_obj=page_obj, robots_noindex=True, **cached_lists([x[1].story.id for x in objects]) )
def edit(story_id, local_id): comment = StoryComment.get(story=story_id, local_id=local_id, deleted=False) if not comment: abort(404) return common_comment.edit( 'story', comment, template='story_comment_work.html', )
def comments_updates(params): comments_html = None if not current_user.is_authenticated: comments_html = current_app.cache.get('index_comments_html_guest') if not comments_html: # Старая логика, при которой могли появляться несколько комментариев одной сущности # story_comments = StoryComment.select(lambda x: x.story_published and not x.deleted).order_by(StoryComment.id.desc()) # story_comments = story_comments[:current_app.config['COMMENTS_COUNT']['main']] # news_comments = NewsComment.select(lambda x: not x.deleted).order_by(NewsComment.id.desc()) # news_comments = news_comments[:current_app.config['COMMENTS_COUNT']['main']] stories = select(x for x in Story if x.published and x.last_comment_id > 0).order_by( Story.last_comment_id.desc( ))[:current_app.config['COMMENTS_COUNT']['main']] story_comment_ids = [x.last_comment_id for x in stories] story_comments = StoryComment.select( lambda x: x.id in story_comment_ids).order_by(StoryComment.id.desc( ))[:current_app.config['COMMENTS_COUNT']['main']] news_list = select( x for x in NewsItem if x.last_comment_id > 0).order_by(NewsItem.last_comment_id.desc( ))[:current_app.config['COMMENTS_COUNT']['main']] news_comment_ids = [x.last_comment_id for x in news_list] news_comments = NewsComment.select( lambda x: x.id in news_comment_ids).order_by(NewsComment.id.desc( ))[:current_app.config['COMMENTS_COUNT']['main']] comments = [('story', x) for x in story_comments] comments += [('news', x) for x in news_comments] comments.sort(key=lambda x: x[1].date, reverse=True) comments = comments[:current_app.config['COMMENTS_COUNT']['main']] data = dict( comments=comments, comments_short=True, ) # Для счётчика непрочитанных комментариев data.update(cached_lists([x.id for x in stories])) comments_html = render_template('includes/comments_list.html', **data) if not current_user.is_authenticated: current_app.cache.set('index_comments_html_guest', comments_html, 3600) return render_template('sidebar/comments_updates.html', comments_html=comments_html)
def restore(story_id, local_id): comment = StoryComment.get(story=story_id, local_id=local_id, deleted=True) if not comment: abort(404) return common_comment.restore( 'story', comment, template='story_comment_restore.html', template_ajax='includes/ajax/story_comment_restore.html', template_ajax_modal=True, )
def show(story_id, local_id): story = Story.get(id=story_id) if not story: abort(404) if not story.bl.has_comments_access(current_user._get_current_object()): abort(403) comment = StoryComment.get(story=story_id, local_id=local_id) if not comment or (comment.deleted and not current_user.is_staff): abort(404) return common_comment.show('story', comment)
def comments_updates(params): comments_html = None if not current_user.is_authenticated: comments_html = current_app.cache.get('index_comments_html_guest') if not comments_html: # Старая логика, при которой могли появляться несколько комментариев одной сущности # story_comments = StoryComment.select(lambda x: x.story_published and not x.deleted).order_by(StoryComment.id.desc()) # story_comments = story_comments[:current_app.config['COMMENTS_COUNT']['main']] # news_comments = NewsComment.select(lambda x: not x.deleted).order_by(NewsComment.id.desc()) # news_comments = news_comments[:current_app.config['COMMENTS_COUNT']['main']] stories = select(x for x in Story if x.published and x.last_comment_id > 0).order_by(Story.last_comment_id.desc())[:current_app.config['COMMENTS_COUNT']['main']] story_comment_ids = [x.last_comment_id for x in stories] story_comments = StoryComment.select(lambda x: x.id in story_comment_ids).order_by(StoryComment.id.desc())[:current_app.config['COMMENTS_COUNT']['main']] news_list = select(x for x in NewsItem if x.last_comment_id > 0).order_by(NewsItem.last_comment_id.desc())[:current_app.config['COMMENTS_COUNT']['main']] news_comment_ids = [x.last_comment_id for x in news_list] news_comments = NewsComment.select(lambda x: x.id in news_comment_ids).order_by(NewsComment.id.desc())[:current_app.config['COMMENTS_COUNT']['main']] comments = [('story', x) for x in story_comments] comments += [('news', x) for x in news_comments] comments.sort(key=lambda x: x[1].date, reverse=True) comments = comments[:current_app.config['COMMENTS_COUNT']['main']] data = dict( comments=comments, comments_short=True, ) # Для счётчика непрочитанных комментариев data.update(cached_lists([x.id for x in stories])) comments_html = render_template( 'includes/comments_list.html', **data ) if not current_user.is_authenticated: current_app.cache.set('index_comments_html_guest', comments_html, 3600) return render_template('sidebar/comments_updates.html', comments_html=comments_html)
def get_notifications(self, older=None, offset=0, count=50): from mini_fiction.models import Notification, Story, Chapter, StoryComment, StoryLocalThread, StoryLocalComment, NewsComment user = self.model if older is None and offset == 0 and count <= 101: result = current_app.cache.get('bell_content_{}'.format(user.id)) if result is not None: return result[:count] result = [] # Забираем уведомления items = user.notifications.filter(lambda x: x.id < older) if older is not None else user.notifications items = items.order_by(Notification.id.desc()).prefetch(Notification.caused_by_user)[offset:offset + count] # Группируем таргеты по типам, чтобы брать их одним sql-запросом story_ids = set() chapter_ids = set() story_comment_ids = set() local_comment_ids = set() news_comment_ids = set() for n in items: if n.type in ('story_publish', 'story_draft', 'author_story'): story_ids.add(n.target_id) elif n.type == 'story_chapter': chapter_ids.add(n.target_id) elif n.type in ('story_reply', 'story_comment'): story_comment_ids.add(n.target_id) elif n.type in ('story_lreply', 'story_lcomment'): local_comment_ids.add(n.target_id) elif n.type in ('news_reply', 'news_comment'): news_comment_ids.add(n.target_id) # И забираем все эти таргеты stories = { x.id: x for x in Story.select( lambda x: x.id in story_ids ) } if story_ids else {} chapters = { x.id: x for x in Chapter.select( lambda x: x.id in chapter_ids ) } if chapter_ids else {} story_comments = { x.id: x for x in StoryComment.select( lambda x: x.id in story_comment_ids ).prefetch(StoryComment.story) } if story_comment_ids else {} local_comments = { x.id: x for x in StoryLocalComment.select( lambda x: x.id in local_comment_ids ).prefetch(StoryLocalComment.local, StoryLocalThread.story) } if local_comment_ids else {} news_comments = { x.id: x for x in NewsComment.select( lambda x: x.id in news_comment_ids ).prefetch(NewsComment.newsitem) } if news_comment_ids else {} # Преобразуем каждое уведомление в json-совместимый формат со всеми дополнениями for n in items: item = { 'id': n.id, 'created_at': n.created_at, 'type': n.type, 'viewed': n.id <= user.last_viewed_notification_id, 'user': { 'id': n.caused_by_user.id, 'username': n.caused_by_user.username, 'is_staff': n.caused_by_user.is_staff, } if n.caused_by_user else None, 'extra': json.loads(n.extra or '{}'), } if n.type in ('story_publish', 'story_draft', 'author_story'): if n.target_id not in stories: item['broken'] = True result.append(item) continue item['story'] = { 'id': n.target_id, 'title': stories[n.target_id].title, } if n.type == 'author_story': item['story']['words'] = stories[n.target_id].words item['story']['authors'] = [{'id': x.id, 'username': x.username} for x in stories[n.target_id].authors] elif n.type == 'story_chapter': c = chapters.get(n.target_id) if not c: item['broken'] = True result.append(item) continue item['story'] = {'id': c.story.id, 'title': c.story.title} item['chapter'] = {'id': c.id, 'order': c.order, 'title': c.title, 'autotitle': c.autotitle, 'words': c.words} elif n.type in ('story_reply', 'story_comment', 'story_lreply', 'story_lcomment', 'news_reply', 'news_comment'): if n.type in ('story_reply', 'story_comment'): c = story_comments.get(n.target_id) elif n.type in ('story_lreply', 'story_lcomment'): c = local_comments.get(n.target_id) elif n.type in ('news_reply', 'news_comment'): c = news_comments.get(n.target_id) if not c: item['broken'] = True result.append(item) continue if c.deleted and not user.is_staff: item['comment'] = { 'id': c.id, 'local_id': c.local_id, 'permalink': c.bl.get_permalink(), 'can_vote': c.bl.can_vote, 'deleted': True, } else: item['comment'] = { 'id': c.id, 'local_id': c.local_id, 'permalink': c.bl.get_permalink(), 'date': c.date, 'brief_text_as_html': str(c.brief_text_as_html), 'can_vote': c.bl.can_vote, 'deleted': c.deleted, 'author': { 'id': c.author.id if c.author else None, 'username': c.author.username if c.author else c.author_username, } } if hasattr(c, 'vote_total'): item['comment']['vote_total'] = c.vote_total if n.type in ('story_reply', 'story_comment'): item['story'] = {'id': c.story.id, 'title': c.story.title} elif n.type in ('story_lreply', 'story_lcomment'): item['story'] = {'id': c.local.story.id, 'title': c.local.story.title} elif n.type in ('news_reply', 'news_comment'): item['newsitem'] = {'id': c.newsitem.id, 'name': c.newsitem.name, 'title': c.newsitem.title} result.append(item) if older is None and offset == 0 and count >= 101: current_app.cache.set('bell_content_{}'.format(user.id), result[:101], 600) return result
def get_notifications(self, older=None, offset=0, count=50): from mini_fiction.models import Notification, Story, Chapter, StoryComment, StoryLocalThread, StoryLocalComment, NewsComment user = self.model if older is None and offset == 0 and count <= 101: result = current_app.cache.get('bell_content_{}'.format(user.id)) if result is not None: return result[:count] result = [] # Забираем уведомления items = user.notifications.filter( lambda x: x.id < older ) if older is not None else user.notifications items = items.order_by(Notification.id.desc()).prefetch( Notification.caused_by_user)[offset:offset + count] # Группируем таргеты по типам, чтобы брать их одним sql-запросом story_ids = set() chapter_ids = set() story_comment_ids = set() local_comment_ids = set() news_comment_ids = set() for n in items: if n.type in ('story_publish', 'story_draft', 'author_story'): story_ids.add(n.target_id) elif n.type == 'story_chapter': chapter_ids.add(n.target_id) elif n.type in ('story_reply', 'story_comment'): story_comment_ids.add(n.target_id) elif n.type in ('story_lreply', 'story_lcomment'): local_comment_ids.add(n.target_id) elif n.type in ('news_reply', 'news_comment'): news_comment_ids.add(n.target_id) # И забираем все эти таргеты stories = {x.id: x for x in Story.select(lambda x: x.id in story_ids) } if story_ids else {} chapters = { x.id: x for x in Chapter.select(lambda x: x.id in chapter_ids) } if chapter_ids else {} story_comments = { x.id: x for x in StoryComment.select(lambda x: x.id in story_comment_ids). prefetch(StoryComment.story) } if story_comment_ids else {} local_comments = { x.id: x for x in StoryLocalComment.select( lambda x: x.id in local_comment_ids).prefetch( StoryLocalComment.local, StoryLocalThread.story) } if local_comment_ids else {} news_comments = { x.id: x for x in NewsComment.select(lambda x: x.id in news_comment_ids). prefetch(NewsComment.newsitem) } if news_comment_ids else {} # Преобразуем каждое уведомление в json-совместимый формат со всеми дополнениями for n in items: item = { 'id': n.id, 'created_at': n.created_at, 'type': n.type, 'viewed': n.id <= user.last_viewed_notification_id, 'user': { 'id': n.caused_by_user.id, 'username': n.caused_by_user.username, 'is_staff': n.caused_by_user.is_staff, } if n.caused_by_user else None, 'extra': json.loads(n.extra or '{}'), } if n.type in ('story_publish', 'story_draft', 'author_story'): if n.target_id not in stories: item['broken'] = True result.append(item) continue item['story'] = { 'id': n.target_id, 'title': stories[n.target_id].title, } if n.type == 'author_story': item['story']['words'] = stories[n.target_id].words item['story']['authors'] = [{ 'id': x.id, 'username': x.username } for x in stories[n.target_id].authors] elif n.type == 'story_chapter': c = chapters.get(n.target_id) if not c: item['broken'] = True result.append(item) continue item['story'] = {'id': c.story.id, 'title': c.story.title} item['chapter'] = { 'id': c.id, 'order': c.order, 'title': c.title, 'autotitle': c.autotitle, 'words': c.words } elif n.type in ('story_reply', 'story_comment', 'story_lreply', 'story_lcomment', 'news_reply', 'news_comment'): if n.type in ('story_reply', 'story_comment'): c = story_comments.get(n.target_id) elif n.type in ('story_lreply', 'story_lcomment'): c = local_comments.get(n.target_id) elif n.type in ('news_reply', 'news_comment'): c = news_comments.get(n.target_id) if not c: item['broken'] = True result.append(item) continue if c.deleted and not user.is_staff: item['comment'] = { 'id': c.id, 'local_id': c.local_id, 'permalink': c.bl.get_permalink(), 'can_vote': c.bl.can_vote, 'deleted': True, } else: item['comment'] = { 'id': c.id, 'local_id': c.local_id, 'permalink': c.bl.get_permalink(), 'date': c.date, 'brief_text_as_html': str(c.brief_text_as_html), 'can_vote': c.bl.can_vote, 'deleted': c.deleted, 'author': { 'id': c.author.id if c.author else None, 'username': c.author.username if c.author else c.author_username, } } if hasattr(c, 'vote_total'): item['comment']['vote_total'] = c.vote_total if n.type in ('story_reply', 'story_comment'): item['story'] = {'id': c.story.id, 'title': c.story.title} elif n.type in ('story_lreply', 'story_lcomment'): item['story'] = { 'id': c.local.story.id, 'title': c.local.story.title } elif n.type in ('news_reply', 'news_comment'): item['newsitem'] = { 'id': c.newsitem.id, 'name': c.newsitem.name, 'title': c.newsitem.title } result.append(item) if older is None and offset == 0 and count >= 101: current_app.cache.set('bell_content_{}'.format(user.id), result[:101], 600) return result
def abuse_storycomment(story_id, local_id): story = get_story(story_id) # Здесь проверка доступа return abuse_common('storycomment', StoryComment.get(story=story.id, local_id=local_id, deleted=False))
def abuse_storycomment(story_id, local_id): story = get_story(story_id) # Здесь проверка доступа return abuse_common( 'storycomment', StoryComment.get(story=story.id, local_id=local_id, deleted=False))
def vote(story_id, local_id): comment = StoryComment.get(story=story_id, local_id=local_id, deleted=False) if not comment: abort(404) return common_comment.vote('story', comment)
def info(user_id=None, comments_page=1): if user_id is not None: try: user_id = int(user_id) except ValueError: abort(404) data = {} if user_id is None: if not current_user.is_authenticated: abort(403) author = current_user._get_current_object() comments_list = StoryComment.bl.select_by_story_author(author) comments_list = comments_list.order_by(StoryComment.id.desc()) stories = list(author.stories) stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True) contributing_stories = list(author.contributing_stories) contributing_stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True) data['all_views'] = Story.bl.get_all_views_for_author(author) data['page_title'] = gettext('My cabinet') template = 'author_dashboard.html' else: author = Author.get(id=user_id) if not author: abort(404) author_id = author.id # обход утечки памяти comments_list = StoryComment.select(lambda x: x.author.id == author_id and not x.deleted and x.story_published) comments_list = comments_list.order_by(StoryComment.id.desc()) data['page_title'] = gettext('Author: {author}').format(author=author.username) stories = list(Story.bl.select_by_author(author, for_user=current_user)) stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True) contributing_stories = None template = 'author_overview.html' comments_count = comments_list.count() series = list(author.series) paged = Paginator( number=comments_page, total=comments_count, per_page=current_app.config['COMMENTS_COUNT']['author_page'], page_arg_name='comments_page', ) # TODO: restore orphans? comments = paged.slice(comments_list) if not comments and comments_page != 1: abort(404) data.update({ 'author': author, 'is_system_user': author.id == current_app.config['SYSTEM_USER_ID'], 'sub': author.bl.get_stories_subscription(current_user._get_current_object()), 'stories': stories, 'contributing_stories': contributing_stories, 'series': series, 'comments': comments, 'comments_count': comments_count, 'comments_short': True, 'page_obj': paged, }) story_ids = set(x.id for x in stories) if contributing_stories: story_ids |= set(x.id for x in contributing_stories) story_ids |= set(x.story.id for x in comments) data.update(cached_lists(story_ids)) return render_template(template, **data)
def info(user_id=None, comments_page=1): if user_id is not None: try: user_id = int(user_id) except ValueError: abort(404) data = {} if user_id is None: if not current_user.is_authenticated: abort(403) author = current_user._get_current_object() comments_list = StoryComment.bl.select_by_story_author(author) comments_list = comments_list.order_by(StoryComment.id.desc()) stories = list(author.stories) stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True) contributing_stories = list(author.contributing_stories) contributing_stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True) data['all_views'] = Story.bl.get_all_views_for_author(author) data['page_title'] = gettext('My cabinet') template = 'author_dashboard.html' else: author = Author.get(id=user_id) if not author: abort(404) author_id = author.id # обход утечки памяти comments_list = StoryComment.select( lambda x: x.author.id == author_id and not x.deleted and x. story_published) comments_list = comments_list.order_by(StoryComment.id.desc()) data['page_title'] = gettext('Author: {author}').format( author=author.username) stories = list(Story.bl.select_by_author(author, for_user=current_user)) stories.sort(key=lambda x: x.first_published_at or x.date, reverse=True) contributing_stories = None template = 'author_overview.html' comments_count = comments_list.count() series = list(author.series) paged = Paginator( number=comments_page, total=comments_count, per_page=current_app.config['COMMENTS_COUNT']['author_page'], page_arg_name='comments_page', ) # TODO: restore orphans? comments = paged.slice(comments_list) if not comments and comments_page != 1: abort(404) data.update({ 'author': author, 'is_system_user': author.id == current_app.config['SYSTEM_USER_ID'], 'sub': author.bl.get_stories_subscription(current_user._get_current_object()), 'stories': stories, 'contributing_stories': contributing_stories, 'series': series, 'comments': comments, 'comments_count': comments_count, 'comments_short': True, 'page_obj': paged, }) story_ids = set(x.id for x in stories) if contributing_stories: story_ids |= set(x.id for x in contributing_stories) story_ids |= set(x.story.id for x in comments) data.update(cached_lists(story_ids)) return render_template(template, **data)