bbcode parser

This commit is contained in:
flash 2016-08-04 23:24:08 +02:00
parent 4b39806756
commit 5286eff072
27 changed files with 239 additions and 148 deletions

4
.gitignore vendored
View file

@ -19,3 +19,7 @@ $RECYCLE.BIN/
# Compiled/copied assets
/public/js
/public/css
# User assets
/uploads/*
!/uploads/.gitkeep

View file

@ -16,25 +16,133 @@ namespace Sakura;
class BBcode
{
/**
* BBcodes, also for backwards compatibility.
* Holds the bbcode parsers
*
* @var array
*/
protected static $bbcodes = [];
/**
* Initialiser.
*/
public static function init()
{
}
public static $parsers = [
'bold' => [
'pattern' => '/\[b\](.*?)\[\/b\]/s',
'replace' => '<b>$1</b>',
'content' => '$1',
],
'italic' => [
'pattern' => '/\[i\](.*?)\[\/i\]/s',
'replace' => '<i>$1</i>',
'content' => '$1',
],
'underline' => [
'pattern' => '/\[u\](.*?)\[\/u\]/s',
'replace' => '<u>$1</u>',
'content' => '$1',
],
'linethrough' => [
'pattern' => '/\[s\](.*?)\[\/s\]/s',
'replace' => '<del>$1</del>',
'content' => '$1',
],
'header' => [
'pattern' => '/\[header\](.*?)\[\/header\]/s',
'replace' => '<h1>$1</h1>',
'content' => '$1',
],
'size' => [
'pattern' => '/\[size\=([1-7])\](.*?)\[\/size\]/s',
'replace' => '<font size="$1">$2</font>',
'content' => '$2',
],
'color' => [
'pattern' => '/\[color\=(#[A-f0-9]{6}|#[A-f0-9]{3})\](.*?)\[\/color\]/s',
'replace' => '<span style="color: $1">$2</span>',
'content' => '$2',
],
'center' => [
'pattern' => '/\[center\](.*?)\[\/center\]/s',
'replace' => '<div style="text-align: center;">$1</div>',
'content' => '$1',
],
'left' => [
'pattern' => '/\[left\](.*?)\[\/left\]/s',
'replace' => '<div style="text-align: left;">$1</div>',
'content' => '$1',
],
'right' => [
'pattern' => '/\[right\](.*?)\[\/right\]/s',
'replace' => '<div style="text-align: right;">$1</div>',
'content' => '$1',
],
'align' => [
'pattern' => '/\[align\=(left|center|right)\](.*?)\[\/align\]/s',
'replace' => '<div style="text-align: $1;">$2</div>',
'content' => '$2',
],
'quote' => [
'pattern' => '/\[quote\](.*?)\[\/quote\]/s',
'replace' => '<blockquote>$1</blockquote>',
'content' => '$1',
],
'namedquote' => [
'pattern' => '/\[quote\=(.*?)\](.*)\[\/quote\]/s',
'replace' => '<blockquote><small>$1</small>$2</blockquote>',
'content' => '$2',
],
'link' => [
'pattern' => '/\[url\](.*?)\[\/url\]/s',
'replace' => '<a href="$1">$1</a>',
'content' => '$1',
],
'namedlink' => [
'pattern' => '/\[url\=(.*?)\](.*?)\[\/url\]/s',
'replace' => '<a href="$1">$2</a>',
'content' => '$2',
],
'image' => [
'pattern' => '/\[img\](.*?)\[\/img\]/s',
'replace' => '<img src="$1" alt="$1">',
'content' => '$1',
],
'orderedlistnumerical' => [
'pattern' => '/\[list=1\](.*?)\[\/list\]/s',
'replace' => '<ol>$1</ol>',
'content' => '$1',
],
'orderedlistalpha' => [
'pattern' => '/\[list=a\](.*?)\[\/list\]/s',
'replace' => '<ol type="a">$1</ol>',
'content' => '$1',
],
'unorderedlist' => [
'pattern' => '/\[list\](.*?)\[\/list\]/s',
'replace' => '<ul>$1</ul>',
'content' => '$1',
],
'listitem' => [
'pattern' => '/\[\*\](.*)/',
'replace' => '<li>$1</li>',
'content' => '$1',
],
'code' => [
'pattern' => '/\[code\](.*?)\[\/code\]/s',
'replace' => '<pre><code>$1</code></pre>',
'content' => '$1',
],
'youtube' => [
'pattern' => '/\[youtube\](.*?)\[\/youtube\]/s',
'replace' => '<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/$1" frameborder="0" allowfullscreen></iframe>',
'content' => '$1',
],
'linebreak' => [
'pattern' => '/\r\n|\r|\n/',
'replace' => '<br>',
'content' => '',
],
];
/**
* Parse the emoticons.
*
* @param string $text String to parse emoticons from.
*
* @return string Parsed text.
* @param string $text
* @return string
*/
public static function parseEmoticons($text)
{
@ -46,115 +154,27 @@ class BBcode
foreach ($emotes as $emote) {
$image = "<img src='{$emote->emote_path}' alt='{$emote->emote_string}' class='emoticon'>";
$icon = preg_quote($emote->emote_string, '#');
$text = preg_replace("#$icon#", $image, $text);
$text = preg_replace("#{$icon}#", $image, $text);
}
// Return the parsed text
return $text;
}
/**
* Set the text to parse.
*
* @param string $text The text that should be parsed.
*/
public static function text($text)
{
return $text;
}
/**
* Convert the parsed text to HTML.
*
* @param string $text The text that should be parsed.
*
* @return string The parsed HTML.
* @param string $text
* @return string
*/
public static function toHTML($text = null)
public static function toHTML($text)
{
// // Check if text isn't null
// if ($text !== null) {
// self::text($text);
// }
$text = self::parseEmoticons($text);
// $parsed = nl2br(self::$bbcode->getAsHtml());
// $parsed = self::fixCodeTags($parsed);
// $parsed = self::parseEmoticons($parsed);
// return $parsed;
return $text;
}
/**
* Convert the parsed text to BBCode.
*
* @param string $text The text that should be parsed.
*
* @return string The converted bbcode.
*/
public static function toEditor($text = null)
{
// // Check if text isn't null
// if ($text !== null) {
// self::text($text);
// }
// return self::$bbcode->getAsBBCode();
return $text;
}
/**
* Convert the parsed text to plain.
*
* @param string $text The text that should be parsed.
*
* @return string The converted plaintext.
*/
public static function toPlain($text = null)
{
// // Check if text isn't null
// if ($text !== null) {
// self::text($text);
// }
// return self::$bbcode->getAsText();
return $text;
}
/**
* Clean up the contents of <code> tags.
* See if this can be deprecated with a custom implementation!
*
* @param string $text Dirty
*
* @return string Clean
*/
public static function fixCodeTags($text)
{
$parts = explode('<code>', $text);
$newStr = '';
if (count($parts) > 1) {
foreach ($parts as $p) {
$parts2 = explode('</code>', $p);
if (count($parts2) > 1) {
$code = str_replace('<br />', '', $parts2[0]);
$code = str_replace('<br/>', '', $code);
$code = str_replace('<br>', '', $code);
$code = str_replace('<', '&lt;', $code);
$newStr .= '<code>' . $code . '</code>';
$newStr .= $parts2[1];
} else {
$newStr .= $p;
}
}
} else {
$newStr = $text;
foreach (self::$parsers as $parser) {
$text = preg_replace($parser['pattern'], $parser['replace'], $text);
}
return $newStr;
return $text;
}
}

View file

@ -84,7 +84,7 @@ class AppearanceController extends Controller
$userId = ActiveUser::$user->id;
$ext = image_type_to_extension($meta[2]);
$filename = "{$mode}_{$userId}.{$ext}";
$filename = "{$mode}_{$userId}{$ext}";
// Create the file
$file = File::create(file_get_contents($tmpName), $filename, ActiveUser::$user);
@ -106,7 +106,11 @@ class AppearanceController extends Controller
public function deleteFile($mode)
{
(new File(ActiveUser::$user->{$mode}))->delete();
$fileId = ActiveUser::$user->{$mode};
if ($fileId) {
(new File($fileId))->delete();
}
}
public function avatar()

View file

@ -84,13 +84,15 @@ class File
$id = DB::table('uploads')
->insertGetId([
'user_id' => $user->id,
'file_data' => $data,
'file_name' => $name,
'file_mime' => $mime,
'file_time' => time(),
'file_expire' => $expire,
]);
// Save the file data
file_put_contents(config('file.uploads_dir') . $id . ".bin", $data);
// Return a new File object
return new File($id);
}
@ -112,7 +114,7 @@ class File
$fileRow = $fileRow[0];
$this->id = $fileRow->file_id;
$this->user = User::construct($fileRow->user_id);
$this->data = $fileRow->file_data;
$this->data = file_get_contents(config('file.uploads_dir') . $fileRow->file_id . ".bin");
$this->name = $fileRow->file_name;
$this->mime = $fileRow->file_mime;
$this->time = $fileRow->file_time;
@ -125,6 +127,8 @@ class File
*/
public function delete()
{
unlink(config('file.uploads_dir') . $this->id . ".bin");
DB::table('uploads')
->where('file_id', $this->id)
->delete();

View file

@ -7,6 +7,7 @@
namespace Sakura;
use Carbon\Carbon;
use Sakura\Perms;
use Sakura\Perms\Site;
use stdClass;
@ -428,6 +429,26 @@ class User
$this->permissions = new Perms(Perms::SITE);
}
/**
* Get a Carbon object of the registration date
*
* @return Carbon
*/
public function registerDate()
{
return Carbon::createFromTimestamp($this->registered);
}
/**
* Get a Carbon object of the last online date
*
* @return Carbon
*/
public function lastDate()
{
return Carbon::createFromTimestamp($this->lastOnline);
}
/**
* Get the user's birthday.
*

View file

@ -15,7 +15,8 @@
; ; sqlite
; driver = sqlite
; database = sakura.sq3
; prefix = sakura_
; ; Although the option exists, setting a table prefix for sqlite breaks some migration related things.
; prefix =
; ; postgres
; driver = pgsql
@ -54,6 +55,9 @@ maintenance = false
; URL of the sakurako chat (full path) without trailing slash
chat = http://chat.localghost
; Date formatting string
date_format = D Y-m-d H:i:s T
; Cookie settings
[cookie]
prefix = sakura_
@ -103,7 +107,7 @@ secure = tls
; File settings
[file]
upload_dir = uploads/
uploads_dir = uploads/
; Avatar requirements
[file.avatar]

View file

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Sakura\DB;
class FilesBelongOnTheFilesystem extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$schema = DB::getSchemaBuilder();
$schema->table('uploads', function (Blueprint $table) {
$table->dropColumn('file_data');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$schema = DB::getSchemaBuilder();
$schema->table('uploads', function (Blueprint $table) {
$table->binary('file_data');
});
}
}

View file

@ -28,7 +28,7 @@ namespace Sakura
title.style.marginBottom = '1px';
link.innerText = 'Changelog';
link.href = Config.ChangelogUrl + '#r' + Config.Revision;
link.href = Config.ChangelogUrl;
link.target = '_blank';
DOM.Append(title, link);

View file

@ -2,7 +2,6 @@ namespace Sakura
{
export class Config
{
public static Revision: number = 0;
public static UserId: number = 0;
public static SessionId: string = "";
public static LoggedIn: boolean = false;

View file

@ -106,8 +106,8 @@
<div class="profile__username" style="color: {{ profile.colour }}">{{ profile.username }}</div>
</div>
<div class="profile__header-sub profile__dates">
<div class="profile__date--joined">Joined {# $user->joined()->format('r') #}</div>
<div class="profile__date--last">Last seen {# $user->lastSeen()->format('r') #}</div>
<div class="profile__date--joined">Joined {{ profile.registerDate.format('r') }}</div>
<div class="profile__date--last">Last seen {{ profile.lastDate.format('r') }}</div>
</div>
</div>
{% endblock %}

View file

@ -20,7 +20,7 @@
All active users in the past 2 minutes
<table class="panelTable">
{% for amount,onlineUser in stats.onlineUsers %}
<tr><td style="text-align: left;"><a href="{{ route('user.profile', onlineUser.id) }}" style="font-weight: bold; color: {{ onlineUser.colour }};" class="default">{{ onlineUser.username }}</a></td><td style="text-align: right;"><time class="time-ago" datetime="{{ onlineUser.lastOnline|date('r') }}">{{ onlineUser.lastOnline|date('D Y-m-d H:i:s T') }}</time></td></tr>
<tr><td style="text-align: left;"><a href="{{ route('user.profile', onlineUser.id) }}" style="font-weight: bold; color: {{ onlineUser.colour }};" class="default">{{ onlineUser.username }}</a></td><td style="text-align: right;"><time class="time-ago" datetime="{{ onlineUser.lastOnline|date('r') }}">{{ onlineUser.lastOnline|date(config('general.date_format')) }}</time></td></tr>
{% endfor %}
</table>
{% else %}

View file

@ -12,6 +12,6 @@
</div>
<div class="clear"></div>
<div class="news-post-time">
Posted <time class="time-ago" datetime="{{ post.time|date('r') }}">{{ post.time|date('D Y-m-d H:i:s T') }}</time>
Posted <time class="time-ago" datetime="{{ post.time|date('r') }}">{{ post.time|date(config('general.date_format')) }}</time>
{% if newsHideCommentCount is not defined %}<a class="default" href="{{ route('news.post', post.id) }}#comments">{{ post.commentCount }} comment{% if post.commentCount != 1 %}s{% endif %}</a>{% endif %}
</div>

View file

@ -24,7 +24,7 @@
<div>
{% if forum.lastPost.id %}
<a href="{{ route('forums.topic', forum.lastPost.topic) }}" class="default">{{ forum.lastPost.subject|slice(0, 30) }}{% if forum.lastPost.subject|length > 30 %}...{% endif %}</a><br>
<time class="time-ago" datetime="{{ forum.lastPost.time|date('r') }}">{{ forum.lastPost.time|date('D Y-m-d H:i:s T') }}</time> by {% if forum.lastPost.poster.id %}<a href="{{ route('user.profile', forum.lastPost.poster.id) }}" class="default" style="color: {{ forum.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if forumlastPost.poster.colour != 'inherit' %}{{ forum.lastPost.poster.colour }}{% else %}#222{% endif %};">{{ forum.lastPost.poster.username }}</a>{% else %}[deleted user]{% endif %} <a href="{{ route('forums.post', forum.lastPost.id) }}" class="default fa fa-tag"></a>
<time class="time-ago" datetime="{{ forum.lastPost.time|date('r') }}">{{ forum.lastPost.time|date(config('general.date_format')) }}</time> by {% if forum.lastPost.poster.id %}<a href="{{ route('user.profile', forum.lastPost.poster.id) }}" class="default" style="color: {{ forum.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if forumlastPost.poster.colour != 'inherit' %}{{ forum.lastPost.poster.colour }}{% else %}#222{% endif %};">{{ forum.lastPost.poster.username }}</a>{% else %}[deleted user]{% endif %} <a href="{{ route('forums.post', forum.lastPost.id) }}" class="default fa fa-tag"></a>
{% else %}
There are no posts in this forum.<br>&nbsp;
{% endif %}

View file

@ -22,6 +22,6 @@
{% else %}
[deleted user]
{% endif %} <a href="{{ route('forums.post', topic.lastPost.id) }}" class="default fa fa-tag"></a><br>
<time class="time-ago" datetime="{{ topic.lastPost.time|date('r') }}">{{ topic.lastPost.time|date('D Y-m-d H:i:s T') }}</time>
<time class="time-ago" datetime="{{ topic.lastPost.time|date('r') }}">{{ topic.lastPost.time|date(config('general.date_format')) }}</time>
</td>
</tr>

View file

@ -17,7 +17,7 @@
<td style="text-align: left; border-bottom: 1px solid #9475b2;">
<a href="{{ route('forums.topic', _t.id) }}" class="default">{{ _t.title }}</a>
</td>
<td class="rightAlign" style="border-bottom: 1px solid #9475b2;"><time class="time-ago" datetime="{{ _t.lastPost.time|date('r') }}">{{ _t.lastPost.time|date('D Y-m-d H:i:s T') }}</time></td>
<td class="rightAlign" style="border-bottom: 1px solid #9475b2;"><time class="time-ago" datetime="{{ _t.lastPost.time|date('r') }}">{{ _t.lastPost.time|date(config('general.date_format')) }}</time></td>
</tr>
{% endfor %}
</table>
@ -36,7 +36,7 @@
by
<a href="{{ route('user.profile', _p.poster.id) }}" class="default"><span style="color: {{ _p.poster.colour }};">{{ _p.poster.username }}</span></a>
</td>
<td class="rightAlign" style="border-bottom: 1px solid #9475b2;"><time class="time-ago" datetime="{{ _p.time|date('r') }}">{{ _p.time|date('D Y-m-d H:i:s T') }}</time></td>
<td class="rightAlign" style="border-bottom: 1px solid #9475b2;"><time class="time-ago" datetime="{{ _p.time|date('r') }}">{{ _p.time|date(config('general.date_format')) }}</time></td>
</tr>
{% endfor %}
</table>
@ -48,7 +48,7 @@
<div class="user-container" style="background-image: url({{ route('user.header', activePoster.id) }});">
<div class="default-avatar-setting user-container-avatar" style="background-image: url({{ route('file.avatar', activePoster.id) }}); box-shadow: 0 0 5px #{% if activePoster.isOnline %}484{% else %}844{% endif %};"></div>
<div class="user-container-info">
<h1 style="color: {{ activePoster.colour }}; text-shadow: 0 0 7px {% if activePoster.colour != 'inherit' %}{{ activePoster.colour }}{% else %}#222{% endif %}; padding: 0 0 2px;" {% if activePoster.getUsernameHistory %} title="Known as {{ activePoster.getUsernameHistory[0].username_old }} before {{ activePoster.getUsernameHistory[0].change_time|date('D Y-m-d H:i:s T') }}." {% endif %}>{{ activePoster.username }}</h1>
<h1 style="color: {{ activePoster.colour }}; text-shadow: 0 0 7px {% if activePoster.colour != 'inherit' %}{{ activePoster.colour }}{% else %}#222{% endif %}; padding: 0 0 2px;" {% if activePoster.getUsernameHistory %} title="Known as {{ activePoster.getUsernameHistory[0].username_old }} before {{ activePoster.getUsernameHistory[0].change_time|date(config('general.date_format')) }}." {% endif %}>{{ activePoster.username }}</h1>
{% if activePoster.isPremium %}<img src="/images/tenshi.png" alt="Tenshi" style="vertical-align: middle;"> {% endif %}<img src="/images/flags/{{ activePoster.country|lower }}.png" alt="{{ activePoster.country }}" style="vertical-align: middle;" title="{{ activePoster.country(true) }}"> <span style="font-size: .8em;">{{ activePoster.title }}</span>
</div>
</div>

View file

@ -111,7 +111,7 @@
<a href="#p{{ post.id }}" class="clean">{{ post.subject|slice(0, 50) }}{% if post.subject|length > 50 %}...{% endif %}</a>
</div>
<div class="date">
<a href="{{ route('forums.post', post.id) }}" class="clean">#{{ post.id }} - <time class="time-ago" datetime="{{ post.time|date('r') }}">{{ post.time|date('D Y-m-d H:i:s T') }}</time></a>
<a href="{{ route('forums.post', post.id) }}" class="clean">#{{ post.id }} - <time class="time-ago" datetime="{{ post.time|date('r') }}">{{ post.time|date(config('general.date_format')) }}</time></a>
</div>
<div class="clear"></div>
</div>

View file

@ -112,23 +112,23 @@
</div>
<div class="footer">
<div class="ftsections">
<div class="copycentre">Powered by <a href="https://github.com/flashwave/sakura/" target="_blank">Sakura</a>{% if config('dev.show_changelog', true) %} <a href="https://sakura.flash.moe/#r{{ constant('SAKURA_VERSION') }}" target="_blank">r{{ constant('SAKURA_VERSION') }}</a>{% endif %} &copy; 2013-2016 <a href="http://flash.moe/" target="_blank">Flashwave</a></div>
<div class="copycentre">Powered by <a href="https://github.com/flashwave/sakura/">Sakura</a> &copy; 2013-2016 <a href="http://flash.moe/">Flashwave</a></div>
<ul class="ftsection">
<li class="fthead">General</li>
<li><a href="{{ route('main.index') }}">Home</a></li>
<li><a href="{{ route('news.category') }}">News</a></li>
<li><a href="{{ route('main.search') }}">Search</a></li>
<li><a href="{{ route('info.contact') }}">Contact</a></li>
<li><a href="https://sakura.flash.moe" target="_blank">Changelog</a></li>
<li><a href="https://sakura.flash.moe">Changelog</a></li>
<li><a href="{{ route('premium.index') }}">Support us</a></li>
</ul>
<ul class="ftsection">
<li class="fthead">Community</li>
<li><a href="{{ route('forums.index') }}">Forums</a></li>
<li><a href="https://twitter.com/_flashii" target="_blank">Twitter</a></li>
<li><a href="https://youtube.com/user/flashiinet" target="_blank">YouTube</a></li>
<li><a href="https://steamcommunity.com/groups/flashiinet" target="_blank">Steam</a></li>
<li><a href="https://github.com/flashii" target="_blank">GitHub</a></li>
<li><a href="https://twitter.com/_flashii">Twitter</a></li>
<li><a href="https://youtube.com/user/flashiinet">YouTube</a></li>
<li><a href="https://steamcommunity.com/groups/flashiinet">Steam</a></li>
<li><a href="https://github.com/flashii">GitHub</a></li>
</ul>
<ul class="ftsection">
<li class="fthead">Information</li>
@ -142,7 +142,6 @@
</div>
<script type="text/javascript">
Sakura.Config.Set({
Revision: {{ constant('SAKURA_VERSION') }},
LoggedIn: {{ user.isActive ? 'true' : 'false' }},
UserId: {{ user.id }},
SessionId: "{{ session_id() }}",

View file

@ -18,8 +18,8 @@
<br>
<h2>Additional information</h2>
<ul style="margin-left: 30px;">
<li>You were banned on {{ ban.issued|date('D Y-m-d H:i:s T') }}.</li>
<li>{% if ban.expires %}This ban expires on {{ ban.expires|date('D Y-m-d H:i:s T') }}.{% else %}<b>You are permanently banned.</b>{% endif %}</li>
<li>You were banned on {{ ban.issued|date(config('general.date_format')) }}.</li>
<li>{% if ban.expires %}This ban expires on {{ ban.expires|date(config('general.date_format')) }}.{% else %}<b>You are permanently banned.</b>{% endif %}</li>
{% if ban.expires %}
<li>You were banned by <a href="{{ route('user.profile', ban.issuer.id) }}" class="default">{{ ban.issuer.username }}</a>.</li>
{% endif %}

View file

@ -6,6 +6,6 @@
<div class="content standalone" style="text-align: center;">
<h1 class="stylised" style="margin: 1em auto;">Thank you for your contribution!</h1>
<h1 class="fa fa-heart stylised" style="font-size: 20em;"></h1>
<h3>Your Tenshi will expire on {{ user.isPremium|date('D Y-m-d H:i:s T') }}.</h3>
<h3>Your Tenshi will expire on {{ user.isPremium|date(config('general.date_format')) }}.</h3>
</div>
{% endblock %}

View file

@ -30,7 +30,7 @@
Your current Tenshi tag
</div>
<div style="margin-bottom: 10px;">
<h3>{% if persistentPremium %}Your rank has persistent Tenshi.{% else %}Your Tenshi tag is valid till {{ user.premiumInfo.expire|date('D Y-m-d H:i:s T') }}.{% endif %}</h3>
<h3>{% if persistentPremium %}Your rank has persistent Tenshi.{% else %}Your Tenshi tag is valid till {{ user.premiumInfo.expire|date(config('general.date_format')) }}.{% endif %}</h3>
<progress value="{{ persistentPremium ? 100 : (100 - (((date().timestamp - user.premiumInfo.start) / (user.premiumInfo.expire - user.premiumInfo.start)) * 100)) }}" max="100" style="width: 100%"></progress>
</div>
{% endif %}

View file

@ -12,7 +12,7 @@
{% block settingsContent %}
<form enctype="multipart/form-data" method="post" action="{{ route('settings.account.username') }}">
<h1 class="stylised" style="text-align: center; margin-top: 10px;{% if not eligible %} color: #c44;{% endif %}">You are {% if not eligible %}not {% endif %}eligible for a name change.</h1>
<h3 style="text-align: center;">{% if user.getUsernameHistory %}Your last name change was <time class="time-ago" datetime="{{ user.getUsernameHistory[0]['change_time']|date('r') }}">{{ user.getUsernameHistory[0]['change_time']|date('D Y-m-d H:i:s T') }}</time>.{% else %}This is your first username change.{% endif %}</h3>
<h3 style="text-align: center;">{% if user.getUsernameHistory %}Your last name change was <time class="time-ago" datetime="{{ user.getUsernameHistory[0]['change_time']|date('r') }}">{{ user.getUsernameHistory[0]['change_time']|date(config('general.date_format')) }}</time>.{% else %}This is your first username change.{% endif %}</h3>
{% if eligible %}
<div class="profile-field">
<div><h2>Username</h2></div>

View file

@ -26,7 +26,7 @@
{{ s.user_agent }}
</td>
<td>
<time class="time-ago" datetime="{{ s.session_start|date('r') }}">{{ s.session_start|date('D Y-m-d H:i:s T') }}</time>
<time class="time-ago" datetime="{{ s.session_start|date('r') }}">{{ s.session_start|date(config('general.date_format')) }}</time>
</td>
<td style="width: 90px;">
<form method="post" action="{{ route('settings.advanced.sessions') }}">

View file

@ -41,7 +41,7 @@
</div>
</div>
<div class="notif-hist-time">
<time class="time-ago" datetime="{{ alert.time|date('r') }}">{{ alert.time|date('D Y-m-d H:i:s T') }}</time>
<time class="time-ago" datetime="{{ alert.time|date('r') }}">{{ alert.time|date(config('general.date_format')) }}</time>
</div>
</div>
<div class="clear"></div>

View file

@ -80,10 +80,10 @@
<a href="{{ route('user.profile', user.id) }}" class="default" style="font-weight: bold; color: {{ user.colour }}; text-shadow: 0 0 5px {{ user.colour }};">{{ user.username }}</a>
</td>
<td>
<time class="time-ago" datetime="{{ user.registered|date('r') }}">{{ user.registered|date('D Y-m-d H:i:s T') }}</time>
<time class="time-ago" datetime="{{ user.registered|date('r') }}">{{ user.registered|date(config('general.date_format')) }}</time>
</td>
<td>
{% if user.lastOnline == 0 %}<i>Never logged in.</i>{% else %}<time class="time-ago" datetime="{{ user.lastOnline|date('r') }}">{{ user.lastOnline|date('D Y-m-d H:i:s T') }}</time>{% endif %}
{% if user.lastOnline == 0 %}<i>Never logged in.</i>{% else %}<time class="time-ago" datetime="{{ user.lastOnline|date('r') }}">{{ user.lastOnline|date(config('general.date_format')) }}</time>{% endif %}
</td>
<td>
{{ user.title }}

View file

@ -144,16 +144,16 @@
<div class="new-profile-info">
<div class="default-avatar-setting new-profile-avatar" style="background-image: url({{ route('file.avatar', profile.id) }}); box-shadow: 0 0 5px #{% if profile.isOnline %}484{% else %}844{% endif %};"></div>
<div class="new-profile-username">
<h1 style="color: {{ profile.colour }}; text-shadow: 0 0 7px {% if profile.colour != 'inherit' %}{{ profile.colour }}{% else %}#222{% endif %}; padding: 0 0 2px;" {% if profile.getUsernameHistory %} title="Known as {{ profile.getUsernameHistory[0].username_old }} before {{ profile.getUsernameHistory[0].change_time|date('D Y-m-d H:i:s T') }}." {% endif %}>{{ profile.username }}</h1>
<h1 style="color: {{ profile.colour }}; text-shadow: 0 0 7px {% if profile.colour != 'inherit' %}{{ profile.colour }}{% else %}#222{% endif %}; padding: 0 0 2px;" {% if profile.getUsernameHistory %} title="Known as {{ profile.getUsernameHistory[0].username_old }} before {{ profile.getUsernameHistory[0].change_time|date(config('general.date_format')) }}." {% endif %}>{{ profile.username }}</h1>
{% if profile.isPremium %}<img src="/images/tenshi.png" alt="Tenshi" style="vertical-align: middle;"> {% endif %}<img src="/images/flags/{{ profile.country|lower }}.png" alt="{{ profile.country }}" style="vertical-align: middle;" title="{{ profile.country(true) }}"> <span style="font-size: .8em;">{{ profile.title }}</span>
</div>
<div class="new-profile-dates">
<b>Joined</b> <time class="time-ago" datetime="{{ profile.registered|date('r') }}">{{ profile.registered|date('D Y-m-d H:i:s T') }}</time>
<b>Joined</b> <time class="time-ago" datetime="{{ profile.registered|date('r') }}">{{ profile.registered|date(config('general.date_format')) }}</time>
<br>
{% if profile.lastOnline < 1 %}
<b>{{ profile.username }} hasn't logged in yet.</b>
{% else %}
<b>Last online</b> <time class="time-ago" datetime="{{ profile.lastOnline|date('r') }}">{{ profile.lastOnline|date('D Y-m-d H:i:s T') }}</time>
<b>Last online</b> <time class="time-ago" datetime="{{ profile.lastOnline|date('r') }}">{{ profile.lastOnline|date(config('general.date_format')) }}</time>
{% endif %}
{% if profile.birthday != '0000-00-00' and profile.birthday|split('-')[0] > 0 %}
<br><b>Age</b> <span title="{{ profile.birthday }}">{{ profile.birthday(true) }} years old</span>&nbsp;
@ -164,7 +164,7 @@
<div class="new-profile-interactions">
<div class="new-profile-navigation">
{% if not noUserpage %}
<a class="fa fa-file-text-o" title="View {{ profile.username }}'s user page" href="#_userpage" onclick="profileMode('userpage');"></a>
<a class="fa fa-file-text-o" title="View {{ profile.username }}'s user page" href="#_userpage" onclick="profileMode('userpage');"></a>
{% endif %}
<a class="fa fa-list" title="View {{ profile.username }}'s topics" href="#_topics" onclick="profileMode('topics');"></a>
<a class="fa fa-reply" title="View {{ profile.username }}'s posts" href="#_posts" onclick="profileMode('posts');"></a>

View file

@ -24,12 +24,12 @@ mb_internal_encoding('utf-8');
// Check the PHP version
if (version_compare(phpversion(), '7.0.0', '<')) {
throw new Exception('Sakura requires at least PHP 7.0.0, please upgrade to a newer PHP version.');
die('Sakura requires at least PHP 7.0.0, please upgrade to a newer PHP version.');
}
// Check if the composer autoloader exists
if (!file_exists(ROOT . 'vendor/autoload.php')) {
throw new Exception('Autoloader not found, did you run composer install?');
die('Autoloader not found, did you run composer install?');
}
// Include the autoloader

1
uploads/.gitkeep Normal file
View file

@ -0,0 +1 @@
#