Public feed implemented.

This commit is contained in:
Alexey Skobkin 2017-11-05 00:30:32 +03:00
parent 988ac34752
commit c0ea97e8f9
12 changed files with 157 additions and 64 deletions

View file

@ -25,6 +25,7 @@
{% block header_navbar_menus %}
<ul class="nav navbar-nav">
<li><a href="{{ path('index') }}"><span class="glyphicon glyphicon-home"></span> {{ 'Main'|trans }}</a></li>
<li><a href="{{ path('feed_public') }}"><span class="glyphicon glyphicon-bullhorn"></span> {{ 'Public feed'|trans }}</a></li>
<li><a href="{{ path('statistics') }}"><span class="glyphicon glyphicon-stats"></span> {{ 'Statistics'|trans }}</a></li>
<li><a href="{{ path('events_last') }}"><span class="glyphicon glyphicon-th-list"></span> {{ 'Last'|trans }}</a></li>
</ul>

View file

@ -0,0 +1,37 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Controller;
use Skobkin\Bundle\PointToolsBundle\Entity\Blogs\Post;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class PublicFeedController extends Controller
{
private const POSTS_PER_PAGE = 20;
public function indexAction(Request $request)
{
// @todo autowire
$postRepository = $this->getDoctrine()->getRepository(Post::class);
$paginator = $this->get('knp_paginator');
$postsPagination = $paginator->paginate(
$postRepository->createPublicFeedPostsQuery(),
$request->query->getInt('page', 1),
self::POSTS_PER_PAGE
);
return $this->render(
'SkobkinPointToolsBundle:Post:feed.html.twig',
[
// @todo Move to translation
'feed_title' => 'All',
'posts' => $postsPagination,
// Special feed mark (to not show comments and other)
'is_feed' => true,
]
);
}
}

View file

@ -3,13 +3,11 @@
namespace Skobkin\Bundle\PointToolsBundle\Controller;
use Doctrine\ORM\EntityManager;
use Skobkin\Bundle\PointToolsBundle\DTO\DailyEvents;
use Skobkin\Bundle\PointToolsBundle\DTO\TopUserDTO;
use Skobkin\Bundle\PointToolsBundle\DTO\{DailyEvents, TopUserDTO};
use Skobkin\Bundle\PointToolsBundle\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Ob\HighchartsBundle\Highcharts\Highchart;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\{Request, Response};
class UserController extends Controller
{

View file

@ -89,7 +89,7 @@ class Post
private $files;
/**
* @var Tag[]|ArrayCollection
* @var PostTag[]|ArrayCollection
*
* @ORM\OneToMany(targetEntity="Skobkin\Bundle\PointToolsBundle\Entity\Blogs\PostTag", mappedBy="post", fetch="EXTRA_LAZY", cascade={"persist"}, orphanRemoval=true)
*/

View file

@ -17,6 +17,7 @@ class PostRepository extends EntityRepository
{
/** @var QueryBuilder $qb */
$qb = $this->createQueryBuilder('p');
return $qb
->select(['p', 'c', 'a'])
->leftJoin('p.comments', 'c')
@ -28,4 +29,19 @@ class PostRepository extends EntityRepository
->getQuery()->getOneOrNullResult()
;
}
public function createPublicFeedPostsQuery(): QueryBuilder
{
$qb = $this->createQueryBuilder('p');
return $qb
// @todo optimize hydration
->select(['p', 'pa', 'pt', 'pf'])
->innerJoin('p.author', 'pa')
->leftJoin('p.postTags', 'pt')
->leftJoin('p.files', 'pf')
->where('p.private = FALSE')
->andWhere('pa.public = TRUE')
;
}
}

View file

@ -36,6 +36,11 @@ events_last:
defaults: { _controller: SkobkinPointToolsBundle:Events:last }
methods: [GET]
feed_public:
path: /posts/all
defaults: { _controller: SkobkinPointToolsBundle:PublicFeed:index }
methods: [GET]
post_show:
path: /{id}
defaults: { _controller: SkobkinPointToolsBundle:Post:show }

View file

@ -3,6 +3,7 @@
# Header
Toggle navigation: Переключить навигацию
Main: Главная
Public feed: Публичная лента
Statistics: Статистика
Report a bug: Сообщить об ошибке
Telegram Bot: Бот в Telegram

View file

@ -0,0 +1,11 @@
{% extends "::base.html.twig" %}
{% block css %}
{{ parent() }}
<link href="{{ asset('css/lib/magnific-popup.css') }}" rel="stylesheet">
{% endblock %}
{% block footer_js %}
{{ parent() }}
<script src="{{ asset('js/lib/jquery.magnific-popup.min.js') }}"></script>
<script src="{{ asset('js/popups.js') }}"></script>
{% endblock %}

View file

@ -0,0 +1,26 @@
{% extends 'SkobkinPointToolsBundle:Post:base_feed.html.twig' %}
{% block header_title %}{{ feed_title }} @ Point Tools{% endblock %}
{% block content %}
{% if is_feed is defined %}
<div class="navigation">
{{ knp_pagination_render(posts) }}
</div>
{% endif %}
{% for post in posts %}
<div class="feed-post panel panel-default">
{% include 'SkobkinPointToolsBundle:Post:post.html.twig' with {
'post': post,
'is_feed': is_feed
} %}
</div>
{% endfor %}
{% if is_feed is defined %}
<div class="navigation">
{{ knp_pagination_render(posts) }}
</div>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,47 @@
<div class="container post-block">
<div class="row">
<div class="col-xs-1">
<img src="{{ point_avatar_large(post.author.login) }}" alt="Avatar">
</div>
<div class="col-xs-11">
<div><a href="{{ path('user_show', {'login': post.author.login}) }}">@{{ post.author.login }}</a></div>
<div class="post-date">{{ post.createdAt|date('j M Y G:i') }}</div>
<div>
{% for pt in post.postTags %}
<span class="tag">{{ pt.text }}</span>
{% endfor %}
</div>
</div>
</div>
<div class="row post-text">
<div class="col-xs-12">
{{ post.text|markdown('app.point.markdown_parser') }}
</div>
</div>
<div class="row post-files">
<div class="col-xs-2">
{% for file in post.files %}
<div class="post-attachment">
<a href="{{ file.remoteUrl }}" class="post-image"><img src="{{ file.remoteUrl }}" class="img-thumbnail" /></a>
</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col-xs-12"><a href="{{ post.id|point_post_url }}" class="post">#{{ post.id }}</a></div>
</div>
{% if is_feed is defined and post.comments|length > 0 %}
<div class="row comments">
{#
{% include '@SkobkinPointTools/Post/comments_tree.html.twig' with {
'comments': post.firstLevelComments
} only %}
#}
{% include 'SkobkinPointToolsBundle:Post:comments_list.html.twig' with {
'comments': post.comments
} %}
</div>
{% endif %}
</div>

View file

@ -1,63 +1,7 @@
{% extends "::base.html.twig" %}
{% block css %}
{{ parent() }}
<link href="{{ asset('css/lib/magnific-popup.css') }}" rel="stylesheet">
{% endblock %}
{% block footer_js %}
{{ parent() }}
<script src="{{ asset('js/lib/jquery.magnific-popup.min.js') }}"></script>
<script src="{{ asset('js/popups.js') }}"></script>
{% endblock %}
{% extends 'SkobkinPointToolsBundle:Post:base_feed.html.twig' %}
{% block header_title %}#{{ post.id }} @ Point Tools{% endblock %}
{% block content %}
<div class="container post-block">
<div class="row">
<div class="col-xs-1">
<img src="{{ point_avatar_large(post.author.login) }}" alt="Avatar">
</div>
<div class="col-xs-11">
<div><a href="{{ path('user_show', {'login': post.author.login}) }}">@{{ post.author.login }}</a></div>
<div class="post-date">{{ post.createdAt|date('j M Y G:i') }}</div>
<div>
{% for pt in post.postTags %}
<a href="#" class="tag">{{ pt.text }}</a>
{% endfor %}
</div>
</div>
</div>
<div class="row post-text">
<div class="col-xs-12">
{{ post.text|markdown('app.point.markdown_parser') }}
</div>
</div>
<div class="row post-files">
<div class="col-xs-2">
{% for file in post.files %}
<div class="post-attachment">
<a href="{{ file.remoteUrl }}" class="post-image"><img src="{{ file.remoteUrl }}" class="img-thumbnail" /></a>
</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col-xs-12"><a href="{{ post.id|point_post_url }}" class="post">#{{ post.id }}</a></div>
</div>
{% if post.comments|length > 0 %}
<div class="row comments">
{#
{% include '@SkobkinPointTools/Post/comments_tree.html.twig' with {
'comments': post.firstLevelComments
} only %}
#}
{% include '@SkobkinPointTools/Post/comments_list.html.twig' with {
'comments': post.comments
} %}
</div>
{% endif %}
</div>
{% include 'SkobkinPointToolsBundle:Post:post.html.twig' with {'post': post} %}
{% endblock %}

View file

@ -106,7 +106,8 @@ ul.users.mosaic li:nth-child(odd) {
color: red;
}
a.tag {
a.tag,
span.tag {
position: relative;
display: inline-block;
margin: .8em .8em 0 0;
@ -117,6 +118,12 @@ a.tag {
text-decoration: none;
}
/* Posts */
.feed-post {
padding: 10px 0;
}
.post-block .post-date {
margin-top: 5px;
color: #a0a0a0;