diff --git a/.gitignore b/.gitignore index 512069a..eefe962 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ $RECYCLE.BIN/ # Compiled/copied assets /public/js /public/css + +# User assets +/uploads/* +!/uploads/.gitkeep diff --git a/app/BBcode.php b/app/BBcode.php index 7b7747f..b5b5235 100644 --- a/app/BBcode.php +++ b/app/BBcode.php @@ -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' => '$1', + 'content' => '$1', + ], + 'italic' => [ + 'pattern' => '/\[i\](.*?)\[\/i\]/s', + 'replace' => '$1', + 'content' => '$1', + ], + 'underline' => [ + 'pattern' => '/\[u\](.*?)\[\/u\]/s', + 'replace' => '$1', + 'content' => '$1', + ], + 'linethrough' => [ + 'pattern' => '/\[s\](.*?)\[\/s\]/s', + 'replace' => '$1', + 'content' => '$1', + ], + 'header' => [ + 'pattern' => '/\[header\](.*?)\[\/header\]/s', + 'replace' => '

$1

', + 'content' => '$1', + ], + 'size' => [ + 'pattern' => '/\[size\=([1-7])\](.*?)\[\/size\]/s', + 'replace' => '$2', + 'content' => '$2', + ], + 'color' => [ + 'pattern' => '/\[color\=(#[A-f0-9]{6}|#[A-f0-9]{3})\](.*?)\[\/color\]/s', + 'replace' => '$2', + 'content' => '$2', + ], + 'center' => [ + 'pattern' => '/\[center\](.*?)\[\/center\]/s', + 'replace' => '
$1
', + 'content' => '$1', + ], + 'left' => [ + 'pattern' => '/\[left\](.*?)\[\/left\]/s', + 'replace' => '
$1
', + 'content' => '$1', + ], + 'right' => [ + 'pattern' => '/\[right\](.*?)\[\/right\]/s', + 'replace' => '
$1
', + 'content' => '$1', + ], + 'align' => [ + 'pattern' => '/\[align\=(left|center|right)\](.*?)\[\/align\]/s', + 'replace' => '
$2
', + 'content' => '$2', + ], + 'quote' => [ + 'pattern' => '/\[quote\](.*?)\[\/quote\]/s', + 'replace' => '
$1
', + 'content' => '$1', + ], + 'namedquote' => [ + 'pattern' => '/\[quote\=(.*?)\](.*)\[\/quote\]/s', + 'replace' => '
$1$2
', + 'content' => '$2', + ], + 'link' => [ + 'pattern' => '/\[url\](.*?)\[\/url\]/s', + 'replace' => '$1', + 'content' => '$1', + ], + 'namedlink' => [ + 'pattern' => '/\[url\=(.*?)\](.*?)\[\/url\]/s', + 'replace' => '$2', + 'content' => '$2', + ], + 'image' => [ + 'pattern' => '/\[img\](.*?)\[\/img\]/s', + 'replace' => '$1', + 'content' => '$1', + ], + 'orderedlistnumerical' => [ + 'pattern' => '/\[list=1\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1', + ], + 'orderedlistalpha' => [ + 'pattern' => '/\[list=a\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1', + ], + 'unorderedlist' => [ + 'pattern' => '/\[list\](.*?)\[\/list\]/s', + 'replace' => '', + 'content' => '$1', + ], + 'listitem' => [ + 'pattern' => '/\[\*\](.*)/', + 'replace' => '
  • $1
  • ', + 'content' => '$1', + ], + 'code' => [ + 'pattern' => '/\[code\](.*?)\[\/code\]/s', + 'replace' => '
    $1
    ', + 'content' => '$1', + ], + 'youtube' => [ + 'pattern' => '/\[youtube\](.*?)\[\/youtube\]/s', + 'replace' => '', + 'content' => '$1', + ], + 'linebreak' => [ + 'pattern' => '/\r\n|\r|\n/', + 'replace' => '
    ', + '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 = "{$emote->emote_string}"; $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 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('', $text); - $newStr = ''; - - if (count($parts) > 1) { - foreach ($parts as $p) { - $parts2 = explode('', $p); - if (count($parts2) > 1) { - $code = str_replace('
    ', '', $parts2[0]); - $code = str_replace('
    ', '', $code); - $code = str_replace('
    ', '', $code); - $code = str_replace('<', '<', $code); - $newStr .= '' . $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; } } diff --git a/app/Controllers/Settings/AppearanceController.php b/app/Controllers/Settings/AppearanceController.php index f81827a..4131518 100644 --- a/app/Controllers/Settings/AppearanceController.php +++ b/app/Controllers/Settings/AppearanceController.php @@ -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() diff --git a/app/File.php b/app/File.php index f688837..aeaf855 100644 --- a/app/File.php +++ b/app/File.php @@ -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(); diff --git a/app/User.php b/app/User.php index 8b76ea7..ba01ed0 100644 --- a/app/User.php +++ b/app/User.php @@ -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. * diff --git a/config/config.example.ini b/config/config.example.ini index 6f77bea..9dbb697 100644 --- a/config/config.example.ini +++ b/config/config.example.ini @@ -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] diff --git a/database/2016_08_04_175711_files_belong_on_the_filesystem.php b/database/2016_08_04_175711_files_belong_on_the_filesystem.php new file mode 100644 index 0000000..f552a3d --- /dev/null +++ b/database/2016_08_04_175711_files_belong_on_the_filesystem.php @@ -0,0 +1,35 @@ +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'); + }); + } +} diff --git a/resources/assets/typescript/Sakura/Changelog.ts b/resources/assets/typescript/Sakura/Changelog.ts index c8a90ee..8ac8749 100644 --- a/resources/assets/typescript/Sakura/Changelog.ts +++ b/resources/assets/typescript/Sakura/Changelog.ts @@ -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); diff --git a/resources/assets/typescript/Sakura/Config.ts b/resources/assets/typescript/Sakura/Config.ts index 93396fe..f095bae 100644 --- a/resources/assets/typescript/Sakura/Config.ts +++ b/resources/assets/typescript/Sakura/Config.ts @@ -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; diff --git a/resources/views/aitemu/user/profile.twig b/resources/views/aitemu/user/profile.twig index 9fbf395..21fb018 100644 --- a/resources/views/aitemu/user/profile.twig +++ b/resources/views/aitemu/user/profile.twig @@ -106,8 +106,8 @@
    {{ profile.username }}
    -
    Joined {# $user->joined()->format('r') #}
    -
    Last seen {# $user->lastSeen()->format('r') #}
    +
    Joined {{ profile.registerDate.format('r') }}
    +
    Last seen {{ profile.lastDate.format('r') }}
    {% endblock %} diff --git a/resources/views/yuuno/elements/indexPanel.twig b/resources/views/yuuno/elements/indexPanel.twig index 4c69eda..62cbc8d 100644 --- a/resources/views/yuuno/elements/indexPanel.twig +++ b/resources/views/yuuno/elements/indexPanel.twig @@ -20,7 +20,7 @@ All active users in the past 2 minutes {% for amount,onlineUser in stats.onlineUsers %} - + {% endfor %}
    {{ onlineUser.username }}
    {{ onlineUser.username }}
    {% else %} diff --git a/resources/views/yuuno/elements/newsPost.twig b/resources/views/yuuno/elements/newsPost.twig index bb09206..4669642 100644 --- a/resources/views/yuuno/elements/newsPost.twig +++ b/resources/views/yuuno/elements/newsPost.twig @@ -12,6 +12,6 @@
    - Posted + Posted {% if newsHideCommentCount is not defined %}{{ post.commentCount }} comment{% if post.commentCount != 1 %}s{% endif %}{% endif %}
    diff --git a/resources/views/yuuno/forum/elements/forumEntry.twig b/resources/views/yuuno/forum/elements/forumEntry.twig index e80b7c3..b406bac 100644 --- a/resources/views/yuuno/forum/elements/forumEntry.twig +++ b/resources/views/yuuno/forum/elements/forumEntry.twig @@ -24,7 +24,7 @@
    {% if forum.lastPost.id %} {{ forum.lastPost.subject|slice(0, 30) }}{% if forum.lastPost.subject|length > 30 %}...{% endif %}
    - by {% if forum.lastPost.poster.id %}{{ forum.lastPost.poster.username }}{% else %}[deleted user]{% endif %} + by {% if forum.lastPost.poster.id %}{{ forum.lastPost.poster.username }}{% else %}[deleted user]{% endif %} {% else %} There are no posts in this forum.
      {% endif %} diff --git a/resources/views/yuuno/forum/elements/topicEntry.twig b/resources/views/yuuno/forum/elements/topicEntry.twig index dbe87ec..cf8b979 100644 --- a/resources/views/yuuno/forum/elements/topicEntry.twig +++ b/resources/views/yuuno/forum/elements/topicEntry.twig @@ -22,6 +22,6 @@ {% else %} [deleted user] {% endif %}
    - + diff --git a/resources/views/yuuno/forum/index.twig b/resources/views/yuuno/forum/index.twig index 05c4734..c1d6ee5 100644 --- a/resources/views/yuuno/forum/index.twig +++ b/resources/views/yuuno/forum/index.twig @@ -17,7 +17,7 @@ {{ _t.title }} - + {% endfor %} @@ -36,7 +36,7 @@ by {{ _p.poster.username }} - + {% endfor %} @@ -48,7 +48,7 @@
    -

    {{ activePoster.username }}

    +

    {{ activePoster.username }}

    {% if activePoster.isPremium %}Tenshi {% endif %}{{ activePoster.country }} {{ activePoster.title }}
    diff --git a/resources/views/yuuno/forum/topic.twig b/resources/views/yuuno/forum/topic.twig index f44120d..4da5e3e 100644 --- a/resources/views/yuuno/forum/topic.twig +++ b/resources/views/yuuno/forum/topic.twig @@ -111,7 +111,7 @@ {{ post.subject|slice(0, 50) }}{% if post.subject|length > 50 %}...{% endif %}
    - #{{ post.id }} - + #{{ post.id }} -
    diff --git a/resources/views/yuuno/master.twig b/resources/views/yuuno/master.twig index b95c897..b3376a8 100644 --- a/resources/views/yuuno/master.twig +++ b/resources/views/yuuno/master.twig @@ -112,23 +112,23 @@