News, part 1 at least.

This commit is contained in:
flash 2018-04-14 04:58:53 +02:00
parent 9cf45fe036
commit aea66a62fb
14 changed files with 330 additions and 17 deletions

View file

@ -0,0 +1,59 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Misuzu\Database;
// phpcs:disable
class CreateNewsTables extends Migration
{
/**
* @SuppressWarnings(PHPMD)
*/
public function up()
{
$schema = Database::connection()->getSchemaBuilder();
$schema->create('news_categories', function (Blueprint $table) {
$table->increments('category_id');
$table->string('category_name');
$table->text('category_description');
$table->boolean('is_hidden')->default(false);
$table->timestamps();
});
$schema->create('news_posts', function (Blueprint $table) {
$table->increments('post_id');
$table->integer('category_id')->unsigned();
$table->boolean('is_featured')->default(false);
$table->integer('user_id')->unsigned()->nullable();
$table->string('post_title');
$table->text('post_text');
$table->timestamp('scheduled_for')->useCurrent();
$table->timestamps();
$table->softDeletes();
$table->foreign('category_id')
->references('category_id')
->on('news_categories')
->onUpdate('cascade')
->onDelete('cascade');
$table->foreign('user_id')
->references('user_id')
->on('users')
->onUpdate('cascade')
->onDelete('set null');
});
}
/**
* @SuppressWarnings(PHPMD)
*/
public function down()
{
$schema = Database::connection()->getSchemaBuilder();
$schema->drop('news_posts');
$schema->drop('news_categories');
}
}

41
public/news.php Normal file
View file

@ -0,0 +1,41 @@
<?php
use Misuzu\News\NewsCategory;
use Misuzu\News\NewsPost;
require_once __DIR__ . '/../misuzu.php';
$category_id = empty($_GET['c']) ? null : (int)$_GET['c'];
$post_id = empty($_GET['n']) ? null : (int)$_GET['n'];
if ($post_id !== null) {
$post = NewsPost::find($post_id);
if ($post === null) {
http_response_code(404);
echo $app->templating->render('errors.404');
return;
}
echo $app->templating->render('news.post', compact('post'));
return;
}
if ($category_id !== null) {
$category = NewsCategory::find($category_id);
if ($category === null) {
http_response_code(404);
echo $app->templating->render('errors.404');
return;
}
$posts = $category->posts()->orderBy('created_at', 'desc')->paginate(5);
$featured = $category->where('is_featured', 1)->orderBy('created_at', 'desc')->take(10);
echo $app->templating->render('news.category', compact('category', 'posts', 'featured'));
return;
}
$categories = NewsCategory::where('is_hidden', false)->get();
$posts = NewsPost::where('is_featured', true)->paginate(5);
echo $app->templating->render('news.index', compact('categories', 'posts'));

View file

@ -160,15 +160,19 @@ class Application extends ApplicationBase
$this->addModule('templating', $twig = new TemplateEngine);
$twig->debug($this->debugMode);
$twig->var('globals', [
'site_name' => $this->config->get('Site', 'name', 'string', 'Flashii'),
'site_description' => $this->config->get('Site', 'description'),
'site_twitter' => $this->config->get('Site', 'twitter'),
'site_url' => $this->config->get('Site', 'url'),
]);
$twig->addFilter('json_decode');
$twig->addFilter('byte_symbol');
$twig->addFilter('country_name', 'get_country_name');
$twig->addFilter('flip', 'array_flip');
$twig->addFilter('create_pagination');
// avoid using config() in templates whenever possible
// in all honesty this shouldn't even be a thing
$twig->addFunction('config', [$this->config, 'get']);
$twig->addFilter('first_paragraph');
$twig->addFunction('git_hash', [Application::class, 'gitCommitHash']);
$twig->addFunction('git_branch', [Application::class, 'gitBranch']);

15
src/News/NewsCategory.php Normal file
View file

@ -0,0 +1,15 @@
<?php
namespace Misuzu\News;
use Misuzu\Model;
final class NewsCategory extends Model
{
protected $table = 'news_categories';
protected $primaryKey = 'category_id';
public function posts()
{
return $this->hasMany(NewsPost::class, 'category_id');
}
}

24
src/News/NewsPost.php Normal file
View file

@ -0,0 +1,24 @@
<?php
namespace Misuzu\News;
use Illuminate\Database\Eloquent\SoftDeletes;
use Misuzu\Users\User;
use Misuzu\Model;
final class NewsPost extends Model
{
use SoftDeletes;
protected $table = 'news_posts';
protected $primaryKey = 'post_id';
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function category()
{
return $this->belongsTo(NewsCategory::class, 'category_id');
}
}

View file

@ -206,3 +206,9 @@ function running_on_windows(): bool
{
return starts_with(strtolower(PHP_OS), 'win');
}
function first_paragraph(string $text, string $delimiter = "\n"): string
{
$index = mb_strpos($text, $delimiter);
return $index === false ? $text : mb_substr($text, 0, $index);
}

View file

@ -1,21 +1,59 @@
{% set title = title|default('Flashii') %}
{% set description = description|default("Where the floor doesn't fall far from the carrot.") %}
{% spaceless %}
{% set description = description|default(globals.site_description) %}
{% set site_twitter = site_twitter|default(globals.site_twitter) %}
{% if title is defined %}
{% set title = title ~ ' :: ' ~ globals.site_name %}
{% else %}
{% set title = globals.site_name %}
{% endif %}
<title>{{ title }}</title>
<meta name="twitter:title" content="{{ title }}">
<meta name="twitter:title" content="{{ title|slice(0, 70) }}">
<meta property="og:title" content="{{ title }}">
<meta property="og:site_name" content="{{ globals.site_name }}">
{% if description|length > 0 %}
<meta name="description" content="{{ description }}">
<meta name="twitter:description" content="{{ description }}">
<meta property="og:description" content="{{ description }}">
{% endif %}
<meta name="twitter:card" content="summary">
{% if site_twitter|length > 0 %}
<meta name="twitter:site" content="{{ site_twitter }}">
{% endif %}
<meta property="og:type" content="object">
<meta property="og:site_name" content="Flashii">
<meta name="twitter:card" content="summary">
{% if icon is defined %}
<meta name="twitter:image:src" content="{{ icon }}">
<meta property="og:image" content="{{ icon }}">
{% if image is defined %}
{% if image|slice(0, 1) == '/' %}
{% if globals.site_url is not defined or globals.site_url|length < 1 %}
{% set image = '' %}
{% else %}
{% set image = globals.site_url|trim('/') ~ image %}
{% endif %}
{% endif %}
{% if image|length > 0 %}
<meta name="twitter:image:src" content="{{ image }}">
<meta property="og:image" content="{{ image }}">
{% endif %}
{% endif %}
{% if canonical_url is defined %}
{% if canonical_url|slice(0, 1) == '/' %}
{% if globals.site_url is not defined or globals.site_url|length < 1 %}
{% set canonical_url = '' %}
{% else %}
{% set canonical_url = globals.site_url|trim('/') ~ canonical_url %}
{% endif %}
{% endif %}
{% if canonical_url|length > 0 %}
<link rel="canonical" href="{{ canonical_url }}">
<link rel="og:url" href="{{ canonical_url }}">
{% endif %}
{% endif %}
{% endspaceless %}

View file

@ -1,6 +1,8 @@
{% extends '@mio/home/master.twig' %}
{% from '@mio/macros.twig' import navigation, link %}
{% set canonical_url = '/' %}
{% block content %}
<div class="mio__container">
<div class="mio__container__title">Welcome!</div>

View file

@ -2,6 +2,7 @@
{% set mio_navigation = {
'Home': '/',
'News': '/news.php',
'Chat': 'https://chat.flashii.net',
} %}

View file

@ -0,0 +1,39 @@
{% extends '@mio/news/master.twig' %}
{% set title = category.category_name ~ ' :: News' %}
{% set canonical_url = '/news.php?c=' ~ category.category_id %}
{% block news_content %}
<div class="mio__container">
<div class="mio__container__title">News » {{ category.category_name }}</div>
<div class="mio__container__content">
<div class="mio__news__category__posts">
{% for post in posts %}
<div class="mio__container mio__news__preview">
<div class="mio__container__title mio__news__preview__title">
{{ post.post_title }}
</div>
<div class="mio__container__content mio__news__preview__content">
<div class="mio__news__preview__text">
{{ post.post_text|first_paragraph }}
</div>
<div class="mio__news__preview__info">
Posted on {{ post.created_at }} by {{ post.user.username }}
</div>
</div>
</div>
{% endfor %}
</div>
<div class="mio__news__category__menu">
<div class="mio__news__category__listing">
{% for featured_post in featured %}
<a href="/news.php?n={{ featured_post.post_id }}">{{ featured_post.post_title }}</a>
{% endfor %}
</div>
<div class="mio__news__category__pagination">
pagination here
</div>
</div>
</div>
</div>
{% endblock %}

39
views/mio/news/index.twig Normal file
View file

@ -0,0 +1,39 @@
{% extends '@mio/news/master.twig' %}
{% set title = 'News' %}
{% set canonical_url = '/news.php' %}
{% block news_content %}
<div class="mio__container">
<div class="mio__container__title">News</div>
<div class="mio__container__content">
<div class="mio__news__category__posts">
{% for post in posts %}
<div class="mio__container mio__news__preview">
<div class="mio__container__title mio__news__preview__title">
{{ post.post_title }}
</div>
<div class="mio__container__content mio__news__preview__content">
<div class="mio__news__preview__text">
{{ post.post_text|first_paragraph }}
</div>
<div class="mio__news__preview__info">
Posted on {{ post.created_at }} by {{ post.user.username }}
</div>
</div>
</div>
{% endfor %}
</div>
<div class="mio__news__category__menu">
<div class="mio__news__category__listing">
{% for category in categories %}
<a href="/news.php?c={{ category.category_id }}">{{ category.category_name }}</a>
{% endfor %}
</div>
<div class="mio__news__category__pagination">
pagination here
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,15 @@
{% extends '@mio/master.twig' %}
{% from '@mio/macros.twig' import navigation %}
{% block content %}
{% block news_content %}
<div class="mio__container">
<div class="mio__container__title">News!</div>
<div class="mio__container__content">
<p>Welcome to News, the news is still heavily in development. You can follow us on News where we'll post news every so often, we'll also announce when the news is ready for public use there!</p>
</div>
</div>
{% endblock %}
{{ navigation(mio_navigation, '/news.php') }}
{% endblock %}

29
views/mio/news/post.twig Normal file
View file

@ -0,0 +1,29 @@
{% extends '@mio/news/master.twig' %}
{% set title = post.post_title ~ ' :: News' %}
{% set canonical_url = '/news.php?n=' ~ post.post_id %}
{% block news_content %}
<div class="mio__container">
<div class="mio__container__title">{{ post.category.category_name }} » {{ post.post_title }}</div>
<div class="mio__container__content">
<div class="mio__news__post__text">
{{ post.post_text|raw }}
</div>
<div class="mio__news__post__info">
<div class="mio__news__post__user">
<div class="mio__news__post__username">
{{ post.user.username }}
</div>
<div class="mio__news__post__avatar" style="background-image:url('/profile.php?u={{ post.user.user_id }}&amp;m=avatar');"></div>
</div>
<div class="mio__news__post__info">
Category: <a href="/news.php?c={{ post.category.category_id }}">{{ post.category.category_name }}</a>
</div>
<div class="mio__news__post__info">
Posted: {{ post.created_at }}
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -1,7 +1,8 @@
{% extends '@mio/user/master.twig' %}
{% from '@mio/macros.twig' import navigation, link %}
{% set icon = '/profile.php?u=' ~ profile.user_id ~ '&m=avatar' %}
{% set image = '/profile.php?u=' ~ profile.user_id ~ '&m=avatar' %}
{% set canonical_url = '/profile.php?u=' ~ profile.user_id %}
{% set title = 'Profile of ' ~ profile.username %}
{% set youtube_is_channel_id = profile.user_youtube|slice(0, 2) == 'UC' and profile.user_youtube|length == 24 %}
@ -118,7 +119,7 @@
{% endspaceless %}
{% endif %}
</div>
<div class="mio__avatar mio__profile__avatar" style="background-image:url('{{ icon }}');"></div>
<div class="mio__avatar mio__profile__avatar" style="background-image:url('{{ image }}');"></div>
</div>
</div>
</div>