The beginning of TypeScript
This commit is contained in:
parent
5d665bce51
commit
97593040e0
72 changed files with 1450 additions and 1285 deletions
161
app/Controllers/Forum/ForumController.php
Normal file
161
app/Controllers/Forum/ForumController.php
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Holds the forum pages controllers.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\Controllers\Forum;
|
||||||
|
|
||||||
|
use Sakura\ActiveUser;
|
||||||
|
use Sakura\Config;
|
||||||
|
use Sakura\DB;
|
||||||
|
use Sakura\Forum\Forum;
|
||||||
|
use Sakura\Forum\Post;
|
||||||
|
use Sakura\Forum\Topic;
|
||||||
|
use Sakura\Perms\Forum as ForumPerms;
|
||||||
|
use Sakura\User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forum page controllers.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
* @author Julian van de Groep <me@flash.moe>
|
||||||
|
*/
|
||||||
|
class ForumController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
// Get the most active topics
|
||||||
|
$activeTopicsIds = DB::table('posts')
|
||||||
|
->where('forum_id', '!=', config('forum.trash'))
|
||||||
|
->groupBy('topic_id')
|
||||||
|
->orderByRaw('COUNT(*) DESC')
|
||||||
|
->limit(10)
|
||||||
|
->get(['topic_id']);
|
||||||
|
$activeTopics = [];
|
||||||
|
|
||||||
|
// make this not disgusting
|
||||||
|
while (list($_n, $_t) = each($activeTopicsIds)) {
|
||||||
|
$topic = new Topic($_t->topic_id);
|
||||||
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
|
// Check if we have permission to view it
|
||||||
|
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
|
$fetch = DB::table('posts')
|
||||||
|
->groupBy('topic_id')
|
||||||
|
->orderByRaw('COUNT(*) DESC')
|
||||||
|
->skip(11 + $_n)
|
||||||
|
->take(1)
|
||||||
|
->get(['topic_id']);
|
||||||
|
|
||||||
|
if ($fetch) {
|
||||||
|
$activeTopicsIds[] = $fetch[0];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$activeTopics[$topic->id] = $topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the latest posts
|
||||||
|
$latestPostsIds = DB::table('posts')
|
||||||
|
->where('forum_id', '!=', config('forum.trash'))
|
||||||
|
->orderBy('post_id', 'desc')
|
||||||
|
->limit(10)
|
||||||
|
->get(['post_id']);
|
||||||
|
$latestPosts = [];
|
||||||
|
|
||||||
|
while (list($_n, $_p) = each($latestPostsIds)) {
|
||||||
|
$post = new Post($_p->post_id);
|
||||||
|
$forum = new Forum($post->forum);
|
||||||
|
|
||||||
|
// Check if we have permission to view it
|
||||||
|
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
|
$fetch = DB::table('posts')
|
||||||
|
->orderBy('post_id', 'desc')
|
||||||
|
->skip(11 + $_n)
|
||||||
|
->take(1)
|
||||||
|
->get(['post_id']);
|
||||||
|
|
||||||
|
if ($fetch) {
|
||||||
|
$latestPostsIds[] = $fetch[0];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestPosts[$post->id] = $post;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the most active poster
|
||||||
|
$activePosterId = DB::table('posts')
|
||||||
|
->where('forum_id', '!=', config('forum.trash'))
|
||||||
|
->where('post_time', '>', time() - (24 * 60 * 60))
|
||||||
|
->groupBy('poster_id')
|
||||||
|
->orderByRaw('COUNT(*) DESC')
|
||||||
|
->limit(1)
|
||||||
|
->get(['poster_id']);
|
||||||
|
$activePoster = User::construct(
|
||||||
|
$activePosterId ? $activePosterId[0]->poster_id : 0
|
||||||
|
);
|
||||||
|
|
||||||
|
$forum = new Forum;
|
||||||
|
|
||||||
|
return view('forum/index', compact('forum', 'activeTopics', 'latestPosts', 'activePoster'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function forum($id = 0)
|
||||||
|
{
|
||||||
|
$forum = new Forum($id);
|
||||||
|
|
||||||
|
$redirect = route('forums.index');
|
||||||
|
$message = "The forum you tried to access does not exist!";
|
||||||
|
|
||||||
|
// Redirect forum id 0 to the main page
|
||||||
|
if ($forum->id === 0) {
|
||||||
|
return header("Location: {$redirect}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($forum->id < 0
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the forum isn't a link
|
||||||
|
if ($forum->type === 2) {
|
||||||
|
$message = "The forum you tried to access is a link. You're being redirected.";
|
||||||
|
$redirect = $forum->link;
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('forum/forum', compact('forum'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function markRead($id = 0)
|
||||||
|
{
|
||||||
|
$redirect = route('forums.index');
|
||||||
|
|
||||||
|
if (!session_check('s')) {
|
||||||
|
$message = "Your session expired! Go back and try again.";
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$forum = new Forum($id);
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($forum->id < 1
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
|
$message = "The forum you tried to access does not exist.";
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$forum->trackUpdateAll(ActiveUser::$user->id);
|
||||||
|
|
||||||
|
$message = 'All topics have been marked as read!';
|
||||||
|
$redirect = route('forums.forum', $forum->id);
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
}
|
243
app/Controllers/Forum/PostController.php
Normal file
243
app/Controllers/Forum/PostController.php
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Holds the controller for posts.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\Controllers\Forum;
|
||||||
|
|
||||||
|
use Sakura\ActiveUser;
|
||||||
|
use Sakura\DB;
|
||||||
|
use Sakura\Forum\Forum;
|
||||||
|
use Sakura\Forum\Post;
|
||||||
|
use Sakura\Forum\Topic;
|
||||||
|
use Sakura\Perms\Forum as ForumPerms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Topic controller.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
* @author Julian van de Groep <me@flash.moe>
|
||||||
|
*/
|
||||||
|
class PostController extends Controller
|
||||||
|
{
|
||||||
|
public function find($id = 0)
|
||||||
|
{
|
||||||
|
$post = new Post($id);
|
||||||
|
$topic = new Topic($post->topic);
|
||||||
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($post->id === 0
|
||||||
|
|| $topic->id === 0
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
|
$message = "This post doesn't exist or you don't have access to it!";
|
||||||
|
$redirect = route('forums.index');
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$topicLink = route('forums.topic', $topic->id);
|
||||||
|
|
||||||
|
// Get all post ids from the database
|
||||||
|
$postIds = DB::table('posts')
|
||||||
|
->where('topic_id', $topic->id)
|
||||||
|
->get(['post_id']);
|
||||||
|
$postIds = array_column($postIds, 'post_id');
|
||||||
|
|
||||||
|
// Find in array
|
||||||
|
$postAt = ceil(array_search($post->id, $postIds) / 10);
|
||||||
|
|
||||||
|
// Only append the page variable if it's more than 1
|
||||||
|
if ($postAt > 1) {
|
||||||
|
$topicLink .= "?page={$postAt}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return header("Location: {$topicLink}#p{$post->id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function raw($id = 0)
|
||||||
|
{
|
||||||
|
$post = new Post($id);
|
||||||
|
$topic = new Topic($post->topic);
|
||||||
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($post->id === 0
|
||||||
|
|| $topic->id === 0
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $post->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($id = 0)
|
||||||
|
{
|
||||||
|
$title = $_POST['title'] ?? null;
|
||||||
|
$text = $_POST['text'] ?? null;
|
||||||
|
|
||||||
|
$post = new Post($id);
|
||||||
|
$topic = new Topic($post->topic);
|
||||||
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
|
// Check permissions
|
||||||
|
$noAccess = $post->id === 0
|
||||||
|
|| $topic->id === 0
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id);
|
||||||
|
|
||||||
|
$noEdit = (
|
||||||
|
$post->poster->id === ActiveUser::$user->id
|
||||||
|
? !ActiveUser::$user->permission(ForumPerms::EDIT_OWN, Perms::FORUM)
|
||||||
|
: !$forum->permission(ForumPerms::EDIT_ANY, ActiveUser::$user->id)
|
||||||
|
) || (
|
||||||
|
$topic->status === 1
|
||||||
|
&& !$forum->permission(ForumPerms::LOCK, ActiveUser::$user->id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($noAccess || $noEdit) {
|
||||||
|
if ($noDelete) {
|
||||||
|
$message = "You aren't allowed to edit posts in this topic!";
|
||||||
|
$redirect = route('forums.post', $post->id);
|
||||||
|
} else {
|
||||||
|
$message = "This post doesn't exist or you don't have access to it!";
|
||||||
|
$redirect = route('forums.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$titleLength = strlen($title);
|
||||||
|
$textLength = strlen($text);
|
||||||
|
$titleMin = config('forum.min_title_length');
|
||||||
|
$titleMax = config('forum.max_title_length');
|
||||||
|
$textMin = config('forum.min_post_length');
|
||||||
|
$textMax = config('forum.max_post_length');
|
||||||
|
|
||||||
|
// Checks
|
||||||
|
$titleTooShort = $title !== null
|
||||||
|
&& $post->id === $topic->firstPost()->id
|
||||||
|
&& $titleLength < $titleMin;
|
||||||
|
$titleTooLong = $title !== null
|
||||||
|
&& $post->id === $topic->firstPost()->id
|
||||||
|
&& $titleLength > $titleMax;
|
||||||
|
$textTooShort = $textLength < $textMin;
|
||||||
|
$textTooLong = $textLength > $textMax;
|
||||||
|
|
||||||
|
// Check requirments
|
||||||
|
if ($titleTooShort
|
||||||
|
|| $titleTooLong
|
||||||
|
|| $textTooShort
|
||||||
|
|| $textTooLong) {
|
||||||
|
$message = "";
|
||||||
|
|
||||||
|
if ($titleTooShort) {
|
||||||
|
$message = "This title is too short!";
|
||||||
|
} elseif ($titleTooLong) {
|
||||||
|
$message = "This title is too long!";
|
||||||
|
} elseif ($textTooShort) {
|
||||||
|
$message = "Please make your post a little bit longer!";
|
||||||
|
} elseif ($textTooLong) {
|
||||||
|
$message = "Your post is too long, you're gonna have to cut a little!";
|
||||||
|
}
|
||||||
|
|
||||||
|
$redirect = route('forums.post', $post->id);
|
||||||
|
|
||||||
|
if (!isset($_SESSION['replyText'])) {
|
||||||
|
$_SESSION['replyText'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['replyText']["t{$forum->id}"] = $text;
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($_SESSION['replyText']["t{$forum->id}"]);
|
||||||
|
|
||||||
|
if ($post->id !== $topic->firstPost()->id || $title === null) {
|
||||||
|
$title = "Re: {$topic->title}";
|
||||||
|
} else {
|
||||||
|
$topic->title = $title;
|
||||||
|
$topic->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the post
|
||||||
|
$post->subject = $title;
|
||||||
|
$post->text = $text;
|
||||||
|
$post->editTime = time();
|
||||||
|
$post->editReason = '';
|
||||||
|
$post->editUser = ActiveUser::$user;
|
||||||
|
$post = $post->update();
|
||||||
|
|
||||||
|
$postLink = route('forums.post', $post->id);
|
||||||
|
|
||||||
|
return header("Location: {$postLink}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($id = 0)
|
||||||
|
{
|
||||||
|
$action = isset($_POST['yes']) && session_check();
|
||||||
|
|
||||||
|
$post = new Post($id);
|
||||||
|
$topic = new Topic($post->topic);
|
||||||
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
|
// Check permissions
|
||||||
|
$noAccess = $post->id === 0
|
||||||
|
|| $topic->id === 0
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id);
|
||||||
|
|
||||||
|
$noDelete = (
|
||||||
|
$post->poster->id === ActiveUser::$user->id
|
||||||
|
? !ActiveUser::$user->permission(ForumPerms::DELETE_OWN, Perms::FORUM)
|
||||||
|
: !$forum->permission(ForumPerms::DELETE_ANY, ActiveUser::$user->id)
|
||||||
|
) || (
|
||||||
|
$topic->status === 1
|
||||||
|
&& !$forum->permission(ForumPerms::LOCK, ActiveUser::$user->id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($noAccess || $noDelete) {
|
||||||
|
if ($noDelete) {
|
||||||
|
$message = "You aren't allowed to delete posts in this topic!";
|
||||||
|
$redirect = Router::route('forums.post', $post->id);
|
||||||
|
} else {
|
||||||
|
$message = "This post doesn't exist or you don't have access to it!";
|
||||||
|
$redirect = Router::route('forums.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($action !== null) {
|
||||||
|
if ($action) {
|
||||||
|
// Set message
|
||||||
|
$message = "Deleted the post!";
|
||||||
|
|
||||||
|
// Check if the topic only has 1 post
|
||||||
|
if ($topic->replyCount() === 1) {
|
||||||
|
// Delete the entire topic
|
||||||
|
$topic->delete();
|
||||||
|
|
||||||
|
$redirect = route('forums.forum', $forum->id);
|
||||||
|
} else {
|
||||||
|
// Just delete the post
|
||||||
|
$post->delete();
|
||||||
|
|
||||||
|
$redirect = route('forums.topic', $topic->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$postLink = route('forums.post', $post->id);
|
||||||
|
return header("Location: {$postLink}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = "Are you sure?";
|
||||||
|
|
||||||
|
return view('global/confirm', compact('message'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Holds the controller for topic.
|
* Holds the controller for topics.
|
||||||
*
|
*
|
||||||
* @package Sakura
|
* @package Sakura
|
||||||
*/
|
*/
|
||||||
|
@ -9,9 +9,9 @@ namespace Sakura\Controllers\Forum;
|
||||||
|
|
||||||
use Sakura\ActiveUser;
|
use Sakura\ActiveUser;
|
||||||
use Sakura\Forum\Forum;
|
use Sakura\Forum\Forum;
|
||||||
|
use Sakura\Forum\Post;
|
||||||
use Sakura\Forum\Topic;
|
use Sakura\Forum\Topic;
|
||||||
use Sakura\Perms\Forum as ForumPerms;
|
use Sakura\Perms\Forum as ForumPerms;
|
||||||
use Sakura\Template;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Topic controller.
|
* Topic controller.
|
||||||
|
@ -23,35 +23,22 @@ class TopicController extends Controller
|
||||||
{
|
{
|
||||||
public function view($id = 0)
|
public function view($id = 0)
|
||||||
{
|
{
|
||||||
// Attempt to get the topic
|
|
||||||
$topic = new Topic($id);
|
$topic = new Topic($id);
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$forum = new Forum($topic->forum);
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
// Check if the forum exists
|
// Check if the forum exists
|
||||||
if ($topic->id === 0 || !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
if ($topic->id === 0
|
||||||
// Set render data
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
||||||
Template::vars([
|
$message = "This topic doesn't exist or you don't have access to it!";
|
||||||
'message' => "This topic doesn't exist or you don't have access to it!",
|
$redirect = route('forums.index');
|
||||||
'redirect' => route('forums.index'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
return view('global/information', compact('message', 'redirect'));
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the tracking status
|
|
||||||
$topic->trackUpdate(ActiveUser::$user->id);
|
$topic->trackUpdate(ActiveUser::$user->id);
|
||||||
|
|
||||||
// Update views
|
|
||||||
$topic->viewsUpdate();
|
$topic->viewsUpdate();
|
||||||
|
|
||||||
// Set parse variables
|
return view('forum/topic', compact('forum', 'topic'));
|
||||||
Template::vars(compact('forum', 'topic'));
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('forum/topic');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function modBase($id)
|
private function modBase($id)
|
||||||
|
@ -59,7 +46,9 @@ class TopicController extends Controller
|
||||||
$topic = new Topic($id);
|
$topic = new Topic($id);
|
||||||
$forum = new Forum($topic->forum);
|
$forum = new Forum($topic->forum);
|
||||||
|
|
||||||
if ($topic->id !== 0 || $forum->permission(ForumPerms::VIEW, ActiveUser::$user->id) || session_check()) {
|
if ($topic->id !== 0
|
||||||
|
|| $forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)
|
||||||
|
|| session_check()) {
|
||||||
return compact('topic', 'forum');
|
return compact('topic', 'forum');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,9 +229,7 @@ class TopicController extends Controller
|
||||||
$message = "This post doesn't exist or you don't have access to it!";
|
$message = "This post doesn't exist or you don't have access to it!";
|
||||||
$redirect = route('forums.index');
|
$redirect = route('forums.index');
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the topic exists
|
// Check if the topic exists
|
||||||
|
@ -254,9 +241,7 @@ class TopicController extends Controller
|
||||||
$message = "You are not allowed to post in this topic!";
|
$message = "You are not allowed to post in this topic!";
|
||||||
$redirect = route('forums.topic', $topic->id);
|
$redirect = route('forums.topic', $topic->id);
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length
|
// Length
|
||||||
|
@ -269,7 +254,7 @@ class TopicController extends Controller
|
||||||
// Check requirments
|
// Check requirments
|
||||||
if ($tooShort
|
if ($tooShort
|
||||||
|| $tooLong) {
|
|| $tooLong) {
|
||||||
$route = Router::route('forums.topic', $topic->id);
|
$route = route('forums.topic', $topic->id);
|
||||||
|
|
||||||
$message = "Your post is " . (
|
$message = "Your post is " . (
|
||||||
$tooShort
|
$tooShort
|
||||||
|
@ -278,15 +263,13 @@ class TopicController extends Controller
|
||||||
);
|
);
|
||||||
$redirect = "{$route}#reply";
|
$redirect = "{$route}#reply";
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
if (!isset($_SESSION['replyText'])) {
|
if (!isset($_SESSION['replyText'])) {
|
||||||
$_SESSION['replyText'] = [];
|
$_SESSION['replyText'] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$_SESSION['replyText']["t{$topic->id}"] = $text;
|
$_SESSION['replyText']["t{$topic->id}"] = $text;
|
||||||
|
|
||||||
return Template::render('global/information');
|
return view('global/information', compact('message', 'redirect'));
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($_SESSION['replyText']["t{$topic->id}"]);
|
unset($_SESSION['replyText']["t{$topic->id}"]);
|
||||||
|
@ -306,4 +289,90 @@ class TopicController extends Controller
|
||||||
// Head to the post
|
// Head to the post
|
||||||
return header("Location: {$postLink}");
|
return header("Location: {$postLink}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function create($id = 0)
|
||||||
|
{
|
||||||
|
$title = $_POST['title'] ?? null;
|
||||||
|
$text = $_POST['text'] ?? null;
|
||||||
|
|
||||||
|
// And attempt to get the forum
|
||||||
|
$forum = new Forum($id);
|
||||||
|
|
||||||
|
// Check if the forum exists
|
||||||
|
if ($forum->id === 0
|
||||||
|
|| $forum->type !== 0
|
||||||
|
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)
|
||||||
|
|| !$forum->permission(ForumPerms::REPLY, ActiveUser::$user->id)
|
||||||
|
|| !$forum->permission(ForumPerms::CREATE_THREADS, ActiveUser::$user->id)) {
|
||||||
|
$message = "This forum doesn't exist or you don't have access to it!";
|
||||||
|
$redirect = route('forums.index');
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($text && $title) {
|
||||||
|
// Length
|
||||||
|
$titleLength = strlen($title);
|
||||||
|
$textLength = strlen($text);
|
||||||
|
$titleMin = config('forum.min_title_length');
|
||||||
|
$titleMax = config('forum.max_title_length');
|
||||||
|
$textMin = config('forum.min_post_length');
|
||||||
|
$textMax = config('forum.max_post_length');
|
||||||
|
|
||||||
|
// Checks
|
||||||
|
$titleTooShort = $titleLength < $titleMin;
|
||||||
|
$titleTooLong = $titleLength > $titleMax;
|
||||||
|
$textTooShort = $textLength < $textMin;
|
||||||
|
$textTooLong = $textLength > $textMax;
|
||||||
|
|
||||||
|
// Check requirments
|
||||||
|
if ($titleTooShort
|
||||||
|
|| $titleTooLong
|
||||||
|
|| $textTooShort
|
||||||
|
|| $textTooLong) {
|
||||||
|
$message = "";
|
||||||
|
|
||||||
|
if ($titleTooShort) {
|
||||||
|
$message = "This title is too short, it has to be longer than {$titleMin} characters!";
|
||||||
|
} elseif ($titleTooLong) {
|
||||||
|
$message = "This title is too long, keep it under {$titleMax} characters!";
|
||||||
|
} elseif ($textTooShort) {
|
||||||
|
$message = "Please make your post a little bit longer, at least {$textMin} characters!";
|
||||||
|
} elseif ($textTooLong) {
|
||||||
|
$message = "Your post is too long, you're gonna have to cut a little!"
|
||||||
|
. " Can't be more than {$textMax} characters.";
|
||||||
|
}
|
||||||
|
|
||||||
|
$redirect = route('forums.new', $forum->id);
|
||||||
|
|
||||||
|
if (!isset($_SESSION['replyText'])) {
|
||||||
|
$_SESSION['replyText'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['replyText']["f{$forum->id}"]["title"] = $title;
|
||||||
|
$_SESSION['replyText']["f{$forum->id}"]["text"] = $text;
|
||||||
|
|
||||||
|
return view('global/information', compact('message', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($_SESSION['replyText']["f{$forum->id}"]);
|
||||||
|
|
||||||
|
// Create the post
|
||||||
|
$post = Post::create(
|
||||||
|
$title,
|
||||||
|
$text,
|
||||||
|
ActiveUser::$user,
|
||||||
|
0,
|
||||||
|
$forum->id
|
||||||
|
);
|
||||||
|
|
||||||
|
// Go to the post
|
||||||
|
$postLink = route('forums.post', $post->id);
|
||||||
|
|
||||||
|
// Head to the post
|
||||||
|
return header("Location: {$postLink}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('forum/topic', compact('forum'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,630 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Holds the forum pages controllers.
|
|
||||||
*
|
|
||||||
* @package Sakura
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Sakura\Controllers;
|
|
||||||
|
|
||||||
use Sakura\ActiveUser;
|
|
||||||
use Sakura\Config;
|
|
||||||
use Sakura\DB;
|
|
||||||
use Sakura\Forum\Forum;
|
|
||||||
use Sakura\Forum\Post;
|
|
||||||
use Sakura\Forum\Topic;
|
|
||||||
use Sakura\Perms;
|
|
||||||
use Sakura\Perms\Forum as ForumPerms;
|
|
||||||
use Sakura\Router;
|
|
||||||
use Sakura\Template;
|
|
||||||
use Sakura\User;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Forum page controllers.
|
|
||||||
*
|
|
||||||
* @package Sakura
|
|
||||||
* @author Julian van de Groep <me@flash.moe>
|
|
||||||
*/
|
|
||||||
class ForumController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Serves the forum index.
|
|
||||||
*
|
|
||||||
* @return string HTML for the forum index.
|
|
||||||
*/
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
// Get the most active topics
|
|
||||||
$activeTopicsIds = DB::table('posts')
|
|
||||||
->where('forum_id', '!=', config('forum.trash'))
|
|
||||||
->groupBy('topic_id')
|
|
||||||
->orderByRaw('COUNT(*) DESC')
|
|
||||||
->limit(10)
|
|
||||||
->get(['topic_id']);
|
|
||||||
$activeTopics = [];
|
|
||||||
|
|
||||||
// make this not disgusting
|
|
||||||
while (list($_n, $_t) = each($activeTopicsIds)) {
|
|
||||||
// Create the topic object
|
|
||||||
$topic = new Topic($_t->topic_id);
|
|
||||||
|
|
||||||
// Create a forum object
|
|
||||||
$forum = new Forum($topic->forum);
|
|
||||||
|
|
||||||
// Check if we have permission to view it
|
|
||||||
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
|
||||||
$fetch = DB::table('posts')
|
|
||||||
->groupBy('topic_id')
|
|
||||||
->orderByRaw('COUNT(*) DESC')
|
|
||||||
->skip(11 + $_n)
|
|
||||||
->take(1)
|
|
||||||
->get(['topic_id']);
|
|
||||||
|
|
||||||
if ($fetch) {
|
|
||||||
$activeTopicsIds[] = $fetch[0];
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$activeTopics[$topic->id] = $topic;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the latest posts
|
|
||||||
$latestPostsIds = DB::table('posts')
|
|
||||||
->where('forum_id', '!=', config('forum.trash'))
|
|
||||||
->orderBy('post_id', 'desc')
|
|
||||||
->limit(10)
|
|
||||||
->get(['post_id']);
|
|
||||||
$latestPosts = [];
|
|
||||||
|
|
||||||
while (list($_n, $_p) = each($latestPostsIds)) {
|
|
||||||
// Create new post object
|
|
||||||
$post = new Post($_p->post_id);
|
|
||||||
|
|
||||||
// Forum id
|
|
||||||
$forum = new Forum($post->forum);
|
|
||||||
|
|
||||||
// Check if we have permission to view it
|
|
||||||
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
|
||||||
$fetch = DB::table('posts')
|
|
||||||
->orderBy('post_id', 'desc')
|
|
||||||
->skip(11 + $_n)
|
|
||||||
->take(1)
|
|
||||||
->get(['post_id']);
|
|
||||||
|
|
||||||
if ($fetch) {
|
|
||||||
$latestPostsIds[] = $fetch[0];
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$latestPosts[$post->id] = $post;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the most active poster
|
|
||||||
$activePosterId = DB::table('posts')
|
|
||||||
->where('forum_id', '!=', config('forum.trash'))
|
|
||||||
->where('post_time', '>', time() - (24 * 60 * 60))
|
|
||||||
->groupBy('poster_id')
|
|
||||||
->orderByRaw('COUNT(*) DESC')
|
|
||||||
->limit(1)
|
|
||||||
->get(['poster_id']);
|
|
||||||
$activePoster = User::construct(
|
|
||||||
$activePosterId ? $activePosterId[0]->poster_id : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create the forum object
|
|
||||||
$forum = new Forum;
|
|
||||||
|
|
||||||
Template::vars(compact('forum', 'activeTopics', 'latestPosts', 'activePoster'));
|
|
||||||
|
|
||||||
// Return the compiled page
|
|
||||||
return Template::render('forum/index');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a forum page.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function forum($id = 0)
|
|
||||||
{
|
|
||||||
// Get the forum
|
|
||||||
$forum = new Forum($id);
|
|
||||||
|
|
||||||
// Redirect forum id 0 to the main page
|
|
||||||
if ($forum->id === 0) {
|
|
||||||
return header('Location: ' . Router::route('forums.index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($forum->id < 0) {
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'The forum you tried to access does not exist.',
|
|
||||||
'redirect' => Router::route('forums.index'),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the user has access to the forum
|
|
||||||
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'You do not have access to this forum.',
|
|
||||||
'redirect' => Router::route('forums.index'),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the forum isn't a link
|
|
||||||
if ($forum->type === 2) {
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'The forum you tried to access is a link. You\'re being redirected.',
|
|
||||||
'redirect' => $forum->link,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set parse variables
|
|
||||||
Template::vars([
|
|
||||||
'forum' => $forum,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('forum/forum');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark a forum as read.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function markForumRead($id = 0)
|
|
||||||
{
|
|
||||||
// Check if the session id was supplied
|
|
||||||
if (!isset($_GET['s']) || $_GET['s'] != session_id()) {
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'Your session expired! Go back and try again.',
|
|
||||||
'redirect' => Router::route('forums.index'),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the forum
|
|
||||||
$forum = new Forum($id);
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($forum->id < 1) {
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'The forum you tried to access does not exist.',
|
|
||||||
'redirect' => Router::route('forums.index'),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the user has access to the forum
|
|
||||||
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'You do not have access to this forum.',
|
|
||||||
'redirect' => Router::route('forums.index'),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the function
|
|
||||||
$forum->trackUpdateAll(ActiveUser::$user->id);
|
|
||||||
|
|
||||||
// Set render data
|
|
||||||
Template::vars([
|
|
||||||
'page' => [
|
|
||||||
'message' => 'All topics have been marked as read.',
|
|
||||||
'redirect' => Router::route('forums.forum', $forum->id),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Print page contents
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect to the position of a post in a topic.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function post($id = 0)
|
|
||||||
{
|
|
||||||
// Attempt to get the post
|
|
||||||
$post = new Post($id);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$topic = new Topic($post->topic);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$forum = new Forum($topic->forum);
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($post->id == 0
|
|
||||||
|| $topic->id == 0
|
|
||||||
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
|
||||||
$message = "This post doesn't exist or you don't have access to it!";
|
|
||||||
$redirect = Router::route('forums.index');
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate link
|
|
||||||
$topicLink = Router::route('forums.topic', $topic->id);
|
|
||||||
|
|
||||||
// Get all post ids from the database
|
|
||||||
$postIds = DB::table('posts')
|
|
||||||
->where('topic_id', $topic->id)
|
|
||||||
->get(['post_id']);
|
|
||||||
$postIds = array_column($postIds, 'post_id');
|
|
||||||
|
|
||||||
// Find in array
|
|
||||||
$postAt = ceil(array_search($post->id, $postIds) / 10);
|
|
||||||
|
|
||||||
// Only append the page variable if it's more than 1
|
|
||||||
if ($postAt > 1) {
|
|
||||||
$topicLink .= "?page={$postAt}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return header("Location: {$topicLink}#p{$post->id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the raw text of a post.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function postRaw($id = 0)
|
|
||||||
{
|
|
||||||
// Attempt to get the post
|
|
||||||
$post = new Post($id);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$topic = new Topic($post->topic);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$forum = new Forum($topic->forum);
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($post->id == 0
|
|
||||||
|| $topic->id == 0
|
|
||||||
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $post->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a topic.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function createTopic($id = 0)
|
|
||||||
{
|
|
||||||
$title = isset($_POST['title']) ? $_POST['title'] : null;
|
|
||||||
$text = isset($_POST['text']) ? $_POST['text'] : null;
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$forum = new Forum($id);
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($forum->id === 0
|
|
||||||
|| $forum->type !== 0
|
|
||||||
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)
|
|
||||||
|| !$forum->permission(ForumPerms::REPLY, ActiveUser::$user->id)
|
|
||||||
|| !$forum->permission(ForumPerms::CREATE_THREADS, ActiveUser::$user->id)) {
|
|
||||||
$message = "This forum doesn't exist or you don't have access to it!";
|
|
||||||
$redirect = Router::route('forums.index');
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($text && $title) {
|
|
||||||
// Length
|
|
||||||
$titleLength = strlen($title);
|
|
||||||
$textLength = strlen($text);
|
|
||||||
$titleMin = config('forum.min_title_length');
|
|
||||||
$titleMax = config('forum.max_title_length');
|
|
||||||
$textMin = config('forum.min_post_length');
|
|
||||||
$textMax = config('forum.max_post_length');
|
|
||||||
|
|
||||||
// Checks
|
|
||||||
$titleTooShort = $titleLength < $titleMin;
|
|
||||||
$titleTooLong = $titleLength > $titleMax;
|
|
||||||
$textTooShort = $textLength < $textMin;
|
|
||||||
$textTooLong = $textLength > $textMax;
|
|
||||||
|
|
||||||
// Check requirments
|
|
||||||
if ($titleTooShort
|
|
||||||
|| $titleTooLong
|
|
||||||
|| $textTooShort
|
|
||||||
|| $textTooLong) {
|
|
||||||
$message = "";
|
|
||||||
|
|
||||||
if ($titleTooShort) {
|
|
||||||
$message = "This title is too short!";
|
|
||||||
} elseif ($titleTooLong) {
|
|
||||||
$message = "This title is too long!";
|
|
||||||
} elseif ($textTooShort) {
|
|
||||||
$message = "Please make your post a little bit longer!";
|
|
||||||
} elseif ($textTooLong) {
|
|
||||||
$message = "Your post is too long, you're gonna have to cut a little!";
|
|
||||||
}
|
|
||||||
|
|
||||||
$redirect = Router::route('forums.new', $forum->id);
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
if (!isset($_SESSION['replyText'])) {
|
|
||||||
$_SESSION['replyText'] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['replyText']["f{$forum->id}"]["title"] = $title;
|
|
||||||
$_SESSION['replyText']["f{$forum->id}"]["text"] = $text;
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($_SESSION['replyText']["f{$forum->id}"]);
|
|
||||||
|
|
||||||
// Create the post
|
|
||||||
$post = Post::create(
|
|
||||||
$title,
|
|
||||||
$text,
|
|
||||||
ActiveUser::$user,
|
|
||||||
0,
|
|
||||||
$forum->id
|
|
||||||
);
|
|
||||||
|
|
||||||
// Go to the post
|
|
||||||
$postLink = Router::route('forums.post', $post->id);
|
|
||||||
|
|
||||||
// Head to the post
|
|
||||||
return header("Location: {$postLink}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::vars(compact('forum'));
|
|
||||||
|
|
||||||
return Template::render('forum/topic');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit a post.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function editPost($id = 0)
|
|
||||||
{
|
|
||||||
$title = isset($_POST['title']) ? $_POST['title'] : null;
|
|
||||||
$text = isset($_POST['text']) ? $_POST['text'] : null;
|
|
||||||
|
|
||||||
// Attempt to get the post
|
|
||||||
$post = new Post($id);
|
|
||||||
|
|
||||||
// Attempt to get the topic
|
|
||||||
$topic = new Topic($post->topic);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$forum = new Forum($topic->forum);
|
|
||||||
|
|
||||||
// Check permissions
|
|
||||||
$noAccess = $post->id == 0
|
|
||||||
|| $topic->id == 0
|
|
||||||
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id);
|
|
||||||
|
|
||||||
$noEdit = (
|
|
||||||
$post->poster->id === ActiveUser::$user->id
|
|
||||||
? !ActiveUser::$user->permission(ForumPerms::EDIT_OWN, Perms::FORUM)
|
|
||||||
: !$forum->permission(ForumPerms::EDIT_ANY, ActiveUser::$user->id)
|
|
||||||
) || (
|
|
||||||
$topic->status === 1
|
|
||||||
&& !$forum->permission(ForumPerms::LOCK, ActiveUser::$user->id)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($noAccess || $noEdit) {
|
|
||||||
if ($noDelete) {
|
|
||||||
$message = "You aren't allowed to edit posts in this topic!";
|
|
||||||
$redirect = Router::route('forums.post', $post->id);
|
|
||||||
} else {
|
|
||||||
$message = "This post doesn't exist or you don't have access to it!";
|
|
||||||
$redirect = Router::route('forums.index');
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length
|
|
||||||
$titleLength = strlen($title);
|
|
||||||
$textLength = strlen($text);
|
|
||||||
$titleMin = config('forum.min_title_length');
|
|
||||||
$titleMax = config('forum.max_title_length');
|
|
||||||
$textMin = config('forum.min_post_length');
|
|
||||||
$textMax = config('forum.max_post_length');
|
|
||||||
|
|
||||||
// Checks
|
|
||||||
$titleTooShort = $title !== null
|
|
||||||
&& $post->id === $topic->firstPost()->id
|
|
||||||
&& $titleLength < $titleMin;
|
|
||||||
$titleTooLong = $title !== null
|
|
||||||
&& $post->id === $topic->firstPost()->id
|
|
||||||
&& $titleLength > $titleMax;
|
|
||||||
$textTooShort = $textLength < $textMin;
|
|
||||||
$textTooLong = $textLength > $textMax;
|
|
||||||
|
|
||||||
// Check requirments
|
|
||||||
if ($titleTooShort
|
|
||||||
|| $titleTooLong
|
|
||||||
|| $textTooShort
|
|
||||||
|| $textTooLong) {
|
|
||||||
$message = "";
|
|
||||||
|
|
||||||
if ($titleTooShort) {
|
|
||||||
$message = "This title is too short!";
|
|
||||||
} elseif ($titleTooLong) {
|
|
||||||
$message = "This title is too long!";
|
|
||||||
} elseif ($textTooShort) {
|
|
||||||
$message = "Please make your post a little bit longer!";
|
|
||||||
} elseif ($textTooLong) {
|
|
||||||
$message = "Your post is too long, you're gonna have to cut a little!";
|
|
||||||
}
|
|
||||||
|
|
||||||
$redirect = Router::route('forums.post', $post->id);
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
if (!isset($_SESSION['replyText'])) {
|
|
||||||
$_SESSION['replyText'] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['replyText']["t{$forum->id}"] = $text;
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($_SESSION['replyText']["t{$forum->id}"]);
|
|
||||||
|
|
||||||
if ($post->id !== $topic->firstPost()->id || $title === null) {
|
|
||||||
$title = "Re: {$topic->title}";
|
|
||||||
} else {
|
|
||||||
$topic->title = $title;
|
|
||||||
$topic->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the post
|
|
||||||
$post->subject = $title;
|
|
||||||
$post->text = $text;
|
|
||||||
$post->editTime = time();
|
|
||||||
$post->editReason = '';
|
|
||||||
$post->editUser = ActiveUser::$user;
|
|
||||||
$post = $post->update();
|
|
||||||
|
|
||||||
// Go to the post
|
|
||||||
$postLink = Router::route('forums.post', $post->id);
|
|
||||||
|
|
||||||
// Head to the post
|
|
||||||
return header("Location: {$postLink}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a post.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function deletePost($id = 0)
|
|
||||||
{
|
|
||||||
$action = isset($_POST['yes']) && isset($_POST['sessionid'])
|
|
||||||
? $_POST['sessionid'] === session_id()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Attempt to get the post
|
|
||||||
$post = new Post($id);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$topic = new Topic($post->topic);
|
|
||||||
|
|
||||||
// And attempt to get the forum
|
|
||||||
$forum = new Forum($topic->forum);
|
|
||||||
|
|
||||||
// Check permissions
|
|
||||||
$noAccess = $post->id == 0
|
|
||||||
|| $topic->id == 0
|
|
||||||
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id);
|
|
||||||
|
|
||||||
$noDelete = (
|
|
||||||
$post->poster->id === ActiveUser::$user->id
|
|
||||||
? !ActiveUser::$user->permission(ForumPerms::DELETE_OWN, Perms::FORUM)
|
|
||||||
: !$forum->permission(ForumPerms::DELETE_ANY, ActiveUser::$user->id)
|
|
||||||
) || (
|
|
||||||
$topic->status === 1
|
|
||||||
&& !$forum->permission(ForumPerms::LOCK, ActiveUser::$user->id)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if the forum exists
|
|
||||||
if ($noAccess || $noDelete) {
|
|
||||||
if ($noDelete) {
|
|
||||||
$message = "You aren't allowed to delete posts in this topic!";
|
|
||||||
$redirect = Router::route('forums.post', $post->id);
|
|
||||||
} else {
|
|
||||||
$message = "This post doesn't exist or you don't have access to it!";
|
|
||||||
$redirect = Router::route('forums.index');
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($action !== null) {
|
|
||||||
if ($action) {
|
|
||||||
// Set message
|
|
||||||
$message = "Deleted the post!";
|
|
||||||
|
|
||||||
// Check if the topic only has 1 post
|
|
||||||
if ($topic->replyCount() === 1) {
|
|
||||||
// Delete the entire topic
|
|
||||||
$topic->delete();
|
|
||||||
|
|
||||||
$redirect = Router::route('forums.forum', $forum->id);
|
|
||||||
} else {
|
|
||||||
// Just delete the post
|
|
||||||
$post->delete();
|
|
||||||
|
|
||||||
$redirect = Router::route('forums.topic', $topic->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::vars(compact('message', 'redirect'));
|
|
||||||
|
|
||||||
return Template::render('global/information');
|
|
||||||
}
|
|
||||||
|
|
||||||
$postLink = Router::route('forums.post', $post->id);
|
|
||||||
return header("Location: {$postLink}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = "Are you sure?";
|
|
||||||
|
|
||||||
Template::vars(compact('message'));
|
|
||||||
|
|
||||||
return Template::render('global/confirm');
|
|
||||||
}
|
|
||||||
}
|
|
37
app/Controllers/Manage/Controller.php
Normal file
37
app/Controllers/Manage/Controller.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Holds the base controller for manage.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\Controllers\Manage;
|
||||||
|
|
||||||
|
use Sakura\Controllers\Controller as BaseController;
|
||||||
|
use Sakura\Template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base management controller (which other controllers should extend on).
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
* @author Julian van de Groep <me@flash.moe>
|
||||||
|
*/
|
||||||
|
class Controller extends BaseController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$navigation = $this->navigation();
|
||||||
|
|
||||||
|
Template::vars(compact('navigation'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function navigation()
|
||||||
|
{
|
||||||
|
$nav = [];
|
||||||
|
|
||||||
|
// Overview
|
||||||
|
$nav["Overview"]["Index"] = route('manage.overview.index');
|
||||||
|
|
||||||
|
return $nav;
|
||||||
|
}
|
||||||
|
}
|
46
app/Controllers/Manage/OverviewController.php
Normal file
46
app/Controllers/Manage/OverviewController.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Holds the overview controller.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura\Controllers\Manage;
|
||||||
|
|
||||||
|
use Sakura\DB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overview controller.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
* @author Julian van de Groep <me@flash.moe>
|
||||||
|
*/
|
||||||
|
class OverviewController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('manage/overview/index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function data()
|
||||||
|
{
|
||||||
|
$data = new \stdClass;
|
||||||
|
|
||||||
|
$data->postsCount = DB::table('posts')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$data->topicsCount = DB::table('topics')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$data->usersCount = DB::table('users')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$data->commentsCount = DB::table('comments')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$data->uploadsCount = DB::table('uploads')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return $this->json($data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ namespace Sakura;
|
||||||
use Twig_Environment;
|
use Twig_Environment;
|
||||||
use Twig_Extension_StringLoader;
|
use Twig_Extension_StringLoader;
|
||||||
use Twig_Loader_Filesystem;
|
use Twig_Loader_Filesystem;
|
||||||
|
use Twig_SimpleFilter;
|
||||||
use Twig_SimpleFunction;
|
use Twig_SimpleFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,10 +52,18 @@ class Template
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected static $utility = [
|
protected static $utilityFunctions = [
|
||||||
'route',
|
'route',
|
||||||
'config',
|
'config',
|
||||||
'session_id',
|
'session_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of utility filters to add to templating
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $utilityFilters = [
|
||||||
'json_decode',
|
'json_decode',
|
||||||
'byte_symbol',
|
'byte_symbol',
|
||||||
];
|
];
|
||||||
|
@ -99,8 +108,13 @@ class Template
|
||||||
self::$engine->addExtension(new Twig_Extension_StringLoader());
|
self::$engine->addExtension(new Twig_Extension_StringLoader());
|
||||||
|
|
||||||
// Add utility functions
|
// Add utility functions
|
||||||
foreach (self::$utility as $utility) {
|
foreach (self::$utilityFunctions as $function) {
|
||||||
self::$engine->addFunction(new Twig_SimpleFunction($utility, $utility));
|
self::$engine->addFunction(new Twig_SimpleFunction($function, $function));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add utility filters
|
||||||
|
foreach (self::$utilityFilters as $filter) {
|
||||||
|
self::$engine->addFilter(new Twig_SimpleFilter($filter, $filter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ elixir(function(mix) {
|
||||||
mix
|
mix
|
||||||
.less('aitemu/master.less', 'public/css/aitemu.css')
|
.less('aitemu/master.less', 'public/css/aitemu.css')
|
||||||
.less('yuuno/master.less', 'public/css/yuuno.css')
|
.less('yuuno/master.less', 'public/css/yuuno.css')
|
||||||
.typescript('master/**/*.ts', 'public/js/master.js')
|
.typescript('app/**/*.ts', 'public/js/app.js')
|
||||||
.typescript('aitemu/**/*.ts', 'public/js/aitemu.js')
|
.typescript('aitemu/**/*.ts', 'public/js/aitemu.js')
|
||||||
.typescript('yuuno/**/*.ts', 'public/js/yuuno.js')
|
.typescript('yuuno/**/*.ts', 'public/js/yuuno.js')
|
||||||
.scripts([
|
.scripts([
|
||||||
|
|
147
resources/assets/typescript/app/AJAX.ts
Normal file
147
resources/assets/typescript/app/AJAX.ts
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class AJAX
|
||||||
|
{
|
||||||
|
// XMLHTTPRequest container
|
||||||
|
private Request: XMLHttpRequest;
|
||||||
|
private Callbacks: any;
|
||||||
|
private Headers: any;
|
||||||
|
private URL: string;
|
||||||
|
private Send: string = null;
|
||||||
|
private Asynchronous: boolean = true;
|
||||||
|
|
||||||
|
// Prepares the XMLHttpRequest and stuff
|
||||||
|
constructor(async: boolean = true) {
|
||||||
|
this.Request = new XMLHttpRequest();
|
||||||
|
this.Callbacks = new Object();
|
||||||
|
this.Headers = new Object();
|
||||||
|
this.Asynchronous = async;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start
|
||||||
|
public Start(method: HTTPMethod, avoidCache: boolean = false): void {
|
||||||
|
// Open the connection
|
||||||
|
this.Request.open(HTTPMethod[method], this.URL + (avoidCache ? (this.URL.indexOf("?") < 0 ? '?' : '&') + "no-cache=" + Date.now() : ""), this.Asynchronous);
|
||||||
|
|
||||||
|
// Set headers
|
||||||
|
this.PrepareHeaders();
|
||||||
|
|
||||||
|
// Watch the ready state
|
||||||
|
this.Request.onreadystatechange = () => {
|
||||||
|
// Only invoke when complete
|
||||||
|
if (this.Request.readyState === 4) {
|
||||||
|
// Check if a callback if present
|
||||||
|
if ((typeof this.Callbacks[this.Request.status]).toLowerCase() === 'function') {
|
||||||
|
this.Callbacks[this.Request.status](this);
|
||||||
|
} else { // Else check if there's a generic fallback present
|
||||||
|
if ((typeof this.Callbacks['0']).toLowerCase() === 'function') {
|
||||||
|
// Call that
|
||||||
|
this.Callbacks['0'](this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Request.send(this.Send);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop
|
||||||
|
public Stop(): void {
|
||||||
|
this.Request = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set content type required for forms
|
||||||
|
public Form(): void {
|
||||||
|
this.ContentType("application/x-www-form-urlencoded");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add post data
|
||||||
|
public SetSend(data: any): void {
|
||||||
|
// Storage array
|
||||||
|
var store: Array<string> = new Array<string>();
|
||||||
|
|
||||||
|
// Iterate over the object and them in the array with an equals sign inbetween
|
||||||
|
for (var item in data) {
|
||||||
|
store.push(encodeURIComponent(item) + "=" + encodeURIComponent(data[item]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign to send
|
||||||
|
this.Send = store.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set raw post
|
||||||
|
public SetRawSend(data: string): void {
|
||||||
|
this.Send = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get response
|
||||||
|
public Response(): string {
|
||||||
|
return this.Request.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically JSON parse the response
|
||||||
|
public JSON(): Object {
|
||||||
|
return JSON.parse(this.Response());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all headers
|
||||||
|
public ResponseHeaders(): string {
|
||||||
|
return this.Request.getAllResponseHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a header
|
||||||
|
public ResponseHeader(name: string): string {
|
||||||
|
return this.Request.getResponseHeader(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set charset
|
||||||
|
public ContentType(type: string, charset: string = null): void {
|
||||||
|
this.AddHeader('Content-Type', type + ';charset=' + (charset ? charset : 'utf-8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a header
|
||||||
|
public AddHeader(name: string, value: string): void {
|
||||||
|
// Attempt to remove a previous instance
|
||||||
|
this.RemoveHeader(name);
|
||||||
|
|
||||||
|
// Add the new header
|
||||||
|
this.Headers[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a header
|
||||||
|
public RemoveHeader(name: string): void {
|
||||||
|
if ((typeof this.Headers[name]).toLowerCase() !== 'undefined') {
|
||||||
|
delete this.Headers[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare Request headers
|
||||||
|
public PrepareHeaders(): void {
|
||||||
|
for (var header in this.Headers) {
|
||||||
|
this.Request.setRequestHeader(header, this.Headers[header]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a callback
|
||||||
|
public AddCallback(status: number, callback: Function): void {
|
||||||
|
// Attempt to remove previous instances
|
||||||
|
this.RemoveCallback(status);
|
||||||
|
|
||||||
|
// Add the new callback
|
||||||
|
this.Callbacks[status] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a callback
|
||||||
|
public RemoveCallback(status: number): void {
|
||||||
|
// Delete the callback if present
|
||||||
|
if ((typeof this.Callbacks[status]).toLowerCase() === 'function') {
|
||||||
|
delete this.Callbacks[status];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the URL
|
||||||
|
public SetUrl(url: string): void {
|
||||||
|
this.URL = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
resources/assets/typescript/app/Changelog.ts
Normal file
87
resources/assets/typescript/app/Changelog.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Changelog
|
||||||
|
{
|
||||||
|
private static Client: AJAX;
|
||||||
|
private static Element: DOM;
|
||||||
|
private static Fetch: number = 0;
|
||||||
|
private static Colours: string[] = [
|
||||||
|
'inherit', // Unknown
|
||||||
|
'#2A2', // Add
|
||||||
|
'#2AA', // Update
|
||||||
|
'#2AA', // Fix
|
||||||
|
'#A22', // Remove
|
||||||
|
'#62C', // Export
|
||||||
|
'#C44', // Revert
|
||||||
|
];
|
||||||
|
|
||||||
|
public static Build(target: DOM)
|
||||||
|
{
|
||||||
|
this.Client = new AJAX;
|
||||||
|
this.Element = DOM.Create('table', 'changelog panelTable');
|
||||||
|
|
||||||
|
this.Element.Element.style.borderSpacing = '0 1px';
|
||||||
|
|
||||||
|
var title: DOM = DOM.Create('div', 'head'),
|
||||||
|
link: DOM = DOM.Create('a', 'underline');
|
||||||
|
|
||||||
|
title.Element.style.marginBottom = '1px';
|
||||||
|
|
||||||
|
link.Text('Changelog');
|
||||||
|
(<HTMLLinkElement>link.Element).href = Config.ChangelogUrl + '#r' + Config.Revision;
|
||||||
|
(<HTMLLinkElement>link.Element).target = '_blank';
|
||||||
|
|
||||||
|
title.Append(link);
|
||||||
|
target.Append(title);
|
||||||
|
target.Append(this.Element);
|
||||||
|
|
||||||
|
this.Client.SetUrl(Config.ChangelogUrl + Config.ChangelogApi);
|
||||||
|
|
||||||
|
this.Client.AddCallback(200, (client: AJAX) => {
|
||||||
|
Changelog.Add(<IChangelogDate>client.JSON());
|
||||||
|
|
||||||
|
if (Changelog.Fetch < 2) {
|
||||||
|
Changelog.Fetch++;
|
||||||
|
Changelog.Client.SetUrl(Config.ChangelogUrl + Config.ChangelogApi + Changelog.Fetch);
|
||||||
|
Changelog.Client.Start(HTTPMethod.GET);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.Client.SetUrl(Config.ChangelogUrl + Config.ChangelogApi + Changelog.Fetch);
|
||||||
|
this.Client.Start(HTTPMethod.GET);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Add(changelog: IChangelogDate)
|
||||||
|
{
|
||||||
|
var header: DOM = DOM.Create('tr', 'changelog__row changelog__row--header'),
|
||||||
|
headerInner: DOM = DOM.Create('th', 'changelog__header');
|
||||||
|
|
||||||
|
headerInner.Text(changelog.date);
|
||||||
|
headerInner.Element.style.fontSize = '1.2em';
|
||||||
|
(<HTMLTableHeaderCellElement>headerInner.Element).colSpan = 2;
|
||||||
|
|
||||||
|
header.Append(headerInner);
|
||||||
|
this.Element.Append(header);
|
||||||
|
|
||||||
|
for (var _i in changelog.changes)
|
||||||
|
{
|
||||||
|
var change: IChangelogChange = changelog.changes[_i],
|
||||||
|
row: DOM = DOM.Create('tr', 'changelog__row'),
|
||||||
|
action: DOM = DOM.Create('td', 'changelog__column'),
|
||||||
|
message: DOM = DOM.Create('td', 'changelog__column');
|
||||||
|
|
||||||
|
action.Text(change.action.name);
|
||||||
|
action.Element.style.backgroundColor = this.Colours[change.action.id];
|
||||||
|
action.Element.style.borderBottom = '1px solid ' + this.Colours[change.action.id];
|
||||||
|
|
||||||
|
message.Text(change.message);
|
||||||
|
message.Element.style.borderBottom = '1px solid ' + this.Colours[change.action.id];
|
||||||
|
|
||||||
|
row.Append(action);
|
||||||
|
row.Append(message);
|
||||||
|
|
||||||
|
this.Element.Append(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
resources/assets/typescript/app/Comments.ts
Normal file
6
resources/assets/typescript/app/Comments.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Comments
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
21
resources/assets/typescript/app/Config.ts
Normal file
21
resources/assets/typescript/app/Config.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Config
|
||||||
|
{
|
||||||
|
public static Revision: number = 0;
|
||||||
|
public static SessionId: string = "";
|
||||||
|
public static UserNameMinLength: number = 3;
|
||||||
|
public static UserNameMaxLength: number = 16;
|
||||||
|
public static PasswordMinEntropy: number = 48;
|
||||||
|
public static LoggedIn: boolean = false;
|
||||||
|
public static ChangelogUrl: string = "https://sakura.flash.moe/";
|
||||||
|
public static ChangelogApi: string = "api.php/";
|
||||||
|
|
||||||
|
public static Set(config: Object): void
|
||||||
|
{
|
||||||
|
for (var key in config) {
|
||||||
|
this[key] = config[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
resources/assets/typescript/app/Cookies.ts
Normal file
33
resources/assets/typescript/app/Cookies.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Cookies
|
||||||
|
{
|
||||||
|
public static Get(name: string): string {
|
||||||
|
// Do a regex on document.cookie
|
||||||
|
var get: RegExpExecArray = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)').exec(document.cookie);
|
||||||
|
|
||||||
|
// Return the value
|
||||||
|
return get ? get[2] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set(name: string, value: string): void {
|
||||||
|
// Check if the cookie already exists
|
||||||
|
if (this.Get(name).length > 1) {
|
||||||
|
this.Delete(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lifetime
|
||||||
|
var life: Date = new Date();
|
||||||
|
|
||||||
|
// Cookies live for a year
|
||||||
|
life.setFullYear(life.getFullYear() + 1);
|
||||||
|
|
||||||
|
// Assign the cookie
|
||||||
|
document.cookie = name + '=' + value + ';expires=' + life.toUTCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Delete(name: string): void {
|
||||||
|
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
resources/assets/typescript/app/DOM.ts
Normal file
74
resources/assets/typescript/app/DOM.ts
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class DOM
|
||||||
|
{
|
||||||
|
public Element: HTMLElement;
|
||||||
|
|
||||||
|
constructor(object: any, mode: DOMSelector) {
|
||||||
|
switch (mode) {
|
||||||
|
case DOMSelector.ID:
|
||||||
|
this.Element = document.getElementById(object);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DOMSelector.CLASS:
|
||||||
|
this.Element = <HTMLElement>document.getElementsByClassName(object)[0];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DOMSelector.ELEMENT:
|
||||||
|
this.Element = object;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DOMSelector.QUERY:
|
||||||
|
this.Element = <HTMLElement>document.querySelector(object);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Create(element: string, className: string = null, id: string = null): DOM {
|
||||||
|
var elem: HTMLElement = document.createElement(element),
|
||||||
|
cont: DOM = new DOM(elem, DOMSelector.ELEMENT);
|
||||||
|
|
||||||
|
if (className !== null) {
|
||||||
|
cont.SetClass(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id !== null) {
|
||||||
|
cont.SetId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Text(text: string): void {
|
||||||
|
this.Element.appendChild(document.createTextNode(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Append(element: DOM): void {
|
||||||
|
this.Element.appendChild(element.Element);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Prepend(element: DOM, before: HTMLElement | Node = null): void {
|
||||||
|
if (before === null) {
|
||||||
|
before = this.Element.firstChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Element.children.length) {
|
||||||
|
this.Element.insertBefore(element.Element, before);
|
||||||
|
} else {
|
||||||
|
this.Append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetId(id: string): void {
|
||||||
|
this.Element.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetClass(name: string): void {
|
||||||
|
this.Element.className = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Remove(): void {
|
||||||
|
this.Element.parentNode.removeChild(this.Element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
resources/assets/typescript/app/DOMSelector.ts
Normal file
10
resources/assets/typescript/app/DOMSelector.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export enum DOMSelector
|
||||||
|
{
|
||||||
|
ID,
|
||||||
|
CLASS,
|
||||||
|
ELEMENT,
|
||||||
|
QUERY
|
||||||
|
}
|
||||||
|
}
|
47
resources/assets/typescript/app/Friend.ts
Normal file
47
resources/assets/typescript/app/Friend.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
declare var ajaxBusyView: any;
|
||||||
|
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Friend
|
||||||
|
{
|
||||||
|
private static Client: AJAX;
|
||||||
|
|
||||||
|
public static Init(): void
|
||||||
|
{
|
||||||
|
this.Client = new AJAX;
|
||||||
|
this.Client.Form();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Add(id: number): void
|
||||||
|
{
|
||||||
|
this.Mode("/friends/1/add".replace('1', id.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Remove(id: number): void
|
||||||
|
{
|
||||||
|
this.Mode("/friends/1/remove".replace('1', id.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mode(url: string): void
|
||||||
|
{
|
||||||
|
this.Client.SetUrl(url);
|
||||||
|
this.Client.SetSend({ "session": Config.SessionId });
|
||||||
|
this.Client.AddCallback(200, (client: AJAX) => {
|
||||||
|
var response: IFriendResponse = <IFriendResponse>client.JSON(),
|
||||||
|
error: string = response.error || null;
|
||||||
|
|
||||||
|
if (error !== null) {
|
||||||
|
ajaxBusyView(true, error, 'fail');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
ajaxBusyView(false);
|
||||||
|
}, 1500);
|
||||||
|
} else {
|
||||||
|
ajaxBusyView(true, response.message, 'ok');
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.Client.Start(HTTPMethod.POST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
resources/assets/typescript/app/HTTPMethod.ts
Normal file
11
resources/assets/typescript/app/HTTPMethod.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export enum HTTPMethod
|
||||||
|
{
|
||||||
|
GET,
|
||||||
|
HEAD,
|
||||||
|
POST,
|
||||||
|
PUT,
|
||||||
|
DELETE
|
||||||
|
}
|
||||||
|
}
|
8
resources/assets/typescript/app/IChangelogAction.ts
Normal file
8
resources/assets/typescript/app/IChangelogAction.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export interface IChangelogAction
|
||||||
|
{
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
}
|
12
resources/assets/typescript/app/IChangelogChange.ts
Normal file
12
resources/assets/typescript/app/IChangelogChange.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export interface IChangelogChange
|
||||||
|
{
|
||||||
|
id: number;
|
||||||
|
action?: IChangelogAction;
|
||||||
|
contributor?: IChangelogContributor;
|
||||||
|
major: boolean;
|
||||||
|
url: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
}
|
9
resources/assets/typescript/app/IChangelogContributor.ts
Normal file
9
resources/assets/typescript/app/IChangelogContributor.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export interface IChangelogContributor
|
||||||
|
{
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
}
|
9
resources/assets/typescript/app/IChangelogDate.ts
Normal file
9
resources/assets/typescript/app/IChangelogDate.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export interface IChangelogDate
|
||||||
|
{
|
||||||
|
date: string;
|
||||||
|
release?: IChangelogRelease;
|
||||||
|
changes: IChangelogChange[];
|
||||||
|
}
|
||||||
|
}
|
9
resources/assets/typescript/app/IChangelogRelease.ts
Normal file
9
resources/assets/typescript/app/IChangelogRelease.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export interface IChangelogRelease
|
||||||
|
{
|
||||||
|
id: number;
|
||||||
|
colour: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
}
|
9
resources/assets/typescript/app/IFriendResponse.ts
Normal file
9
resources/assets/typescript/app/IFriendResponse.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export interface IFriendResponse
|
||||||
|
{
|
||||||
|
message: string;
|
||||||
|
level: number;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
|
}
|
76
resources/assets/typescript/app/Legacy.ts
Normal file
76
resources/assets/typescript/app/Legacy.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
declare function escape(a);
|
||||||
|
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Legacy
|
||||||
|
{
|
||||||
|
// Alternative for Math.log2() since it's still experimental
|
||||||
|
public static log2(num: number): number {
|
||||||
|
return Math.log(num) / Math.log(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of unique characters in a string
|
||||||
|
public static unique(string: string): number {
|
||||||
|
// Store the already found character
|
||||||
|
var used: string[] = [];
|
||||||
|
|
||||||
|
// The amount of characters we've already found
|
||||||
|
var count: number = 0;
|
||||||
|
|
||||||
|
// Count the amount of unique characters
|
||||||
|
for (var i = 0; i < string.length; i++) {
|
||||||
|
// Check if we already counted this character
|
||||||
|
if (used.indexOf(string[i]) == -1) {
|
||||||
|
// Push the character into the used array
|
||||||
|
used.push(string[i]);
|
||||||
|
|
||||||
|
// Up the count
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the count
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate password entropy
|
||||||
|
public static entropy(string: string): number {
|
||||||
|
// Decode utf-8 encoded characters
|
||||||
|
string = this.utf8_decode(string);
|
||||||
|
|
||||||
|
// Count the unique characters in the string
|
||||||
|
var unique: number = this.unique(string);
|
||||||
|
|
||||||
|
// Do the entropy calculation
|
||||||
|
return unique * this.log2(256);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate string lengths
|
||||||
|
public static stringLength(string: string, minimum: number, maximum: number): boolean {
|
||||||
|
// Get length of string
|
||||||
|
var length = string.length;
|
||||||
|
|
||||||
|
// Check if it meets the minimum/maximum
|
||||||
|
if (length < minimum || length > maximum) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it passes both return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate email address formats
|
||||||
|
public static validateEmail(email: string): boolean {
|
||||||
|
// RFC compliant e-mail address regex
|
||||||
|
var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,48})+$/;
|
||||||
|
|
||||||
|
// Test it on the email var which'll return a boolean
|
||||||
|
return re.test(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a utf-8 string
|
||||||
|
public static utf8_decode(string): string {
|
||||||
|
return decodeURIComponent(escape(string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
resources/assets/typescript/app/Main.ts
Normal file
15
resources/assets/typescript/app/Main.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class Main
|
||||||
|
{
|
||||||
|
public static Startup(): void {
|
||||||
|
console.log(this.Supported());
|
||||||
|
TimeAgo.Init();
|
||||||
|
Friend.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Supported(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
resources/assets/typescript/app/TimeAgo.ts
Normal file
56
resources/assets/typescript/app/TimeAgo.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
namespace Sakura
|
||||||
|
{
|
||||||
|
export class TimeAgo
|
||||||
|
{
|
||||||
|
private static WatchClass: string = "time-ago";
|
||||||
|
|
||||||
|
public static Init(): void
|
||||||
|
{
|
||||||
|
var watchElements: NodeListOf<Element> = document.getElementsByClassName(this.WatchClass);
|
||||||
|
|
||||||
|
for (var _i in watchElements) {
|
||||||
|
if ((typeof watchElements[_i]).toLowerCase() !== 'object') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var elem: HTMLElement = <HTMLElement>watchElements[_i],
|
||||||
|
date: Date = new Date(elem.getAttribute('dateTime') || elem.innerText);
|
||||||
|
|
||||||
|
elem.title = elem.innerText;
|
||||||
|
elem.innerText = this.Parse(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parse(date: Date, append: string = ' ago', none: string = 'Just now'): string {
|
||||||
|
var time: number = (Date.now() - date.getTime()) / 1000;
|
||||||
|
|
||||||
|
if (time < 1) {
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
|
||||||
|
var times: Object = {
|
||||||
|
31536000: ['year', 'a'],
|
||||||
|
2592000: ['month', 'a'],
|
||||||
|
604800: ['week', 'a'],
|
||||||
|
86400: ['day', 'a'],
|
||||||
|
3600: ['hour', 'an'],
|
||||||
|
60: ['minute', 'a'],
|
||||||
|
1: ['second', 'a']
|
||||||
|
};
|
||||||
|
|
||||||
|
var timeKeys: string[] = Object.keys(times).reverse();
|
||||||
|
|
||||||
|
for (var i in timeKeys) {
|
||||||
|
var calc: number = time / parseInt(timeKeys[i]);
|
||||||
|
|
||||||
|
if (calc >= 1) {
|
||||||
|
var display: number = Math.floor(calc);
|
||||||
|
|
||||||
|
return (display === 1 ? times[timeKeys[i]][1] : display) + " " + times[timeKeys[i]][0] + (display === 1 ? '' : 's') + append;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,322 +0,0 @@
|
||||||
/*
|
|
||||||
* Shared client side code
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Meta functions
|
|
||||||
class Sakura {
|
|
||||||
public static cookiePrefix: string = ""; // Cookie prefix, gets prepended to cookie names
|
|
||||||
public static cookiePath: string = "/"; // Cookie path, can in most cases be left untouched
|
|
||||||
|
|
||||||
// Get or set a cookie value
|
|
||||||
public static cookie(name: string, value: string = null): string {
|
|
||||||
// If value is null only get the cookie's value
|
|
||||||
if (value) {
|
|
||||||
// Delete the old instance
|
|
||||||
document.cookie = this.cookiePrefix + name + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT; path=' + this.cookiePath;
|
|
||||||
|
|
||||||
// Assign the cookie
|
|
||||||
document.cookie = this.cookiePrefix + name + '=' + value + '; path=' + this.cookiePath;
|
|
||||||
|
|
||||||
// Pass the value through
|
|
||||||
return value;
|
|
||||||
} else {
|
|
||||||
// Perform a regex on document.cookie
|
|
||||||
var get = new RegExp('(^|; )' + encodeURIComponent(this.cookiePrefix + name) + '=([^;]*)').exec(document.cookie);
|
|
||||||
|
|
||||||
// If anything was returned return it (professional phrasing)
|
|
||||||
return get ? get[2] : '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unix timestamp
|
|
||||||
public static epoch(): number {
|
|
||||||
return Math.floor(Date.now() / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle a class
|
|
||||||
public static toggleClass(element: HTMLElement, name: string): void {
|
|
||||||
// Check if the class already exists and if not add it
|
|
||||||
if (element.className.indexOf(name) < 0) {
|
|
||||||
element.className += ' ' + name;
|
|
||||||
} else { // If so remove it and kill additional spaces
|
|
||||||
element.className = element.className.replace(name, '').trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove every element with a specific class name
|
|
||||||
public static removeByClass(name: string): void {
|
|
||||||
// Get the elements
|
|
||||||
var objs = document.getElementsByClassName(name);
|
|
||||||
|
|
||||||
// Use a while loop to remove each element
|
|
||||||
while (objs.length > 0) {
|
|
||||||
objs[0].parentNode.removeChild(objs[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a single element with a specific id
|
|
||||||
public static removeById(id: string): void {
|
|
||||||
// Get the element
|
|
||||||
var obj = document.getElementById(id);
|
|
||||||
|
|
||||||
// If the element exists use the parent node to remove it
|
|
||||||
if (typeof (obj) != "undefined" && obj !== null) {
|
|
||||||
obj.parentNode.removeChild(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alternative for Math.log2() since it's still experimental
|
|
||||||
public static log2(num: number): number {
|
|
||||||
return Math.log(num) / Math.log(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the number of unique characters in a string
|
|
||||||
public static unique(string: string): number {
|
|
||||||
// Store the already found character
|
|
||||||
var used: string[] = [];
|
|
||||||
|
|
||||||
// The amount of characters we've already found
|
|
||||||
var count: number = 0;
|
|
||||||
|
|
||||||
// Count the amount of unique characters
|
|
||||||
for (var i = 0; i < string.length; i++) {
|
|
||||||
// Check if we already counted this character
|
|
||||||
if (used.indexOf(string[i]) == -1) {
|
|
||||||
// Push the character into the used array
|
|
||||||
used.push(string[i]);
|
|
||||||
|
|
||||||
// Up the count
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the count
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate password entropy
|
|
||||||
public static entropy(string: string): number {
|
|
||||||
// Decode utf-8 encoded characters
|
|
||||||
string = utf8.decode(string);
|
|
||||||
|
|
||||||
// Count the unique characters in the string
|
|
||||||
var unique: number = this.unique(string);
|
|
||||||
|
|
||||||
// Do the entropy calculation
|
|
||||||
return unique * this.log2(256);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate string lengths
|
|
||||||
public static stringLength(string: string, minimum: number, maximum: number): boolean {
|
|
||||||
// Get length of string
|
|
||||||
var length = string.length;
|
|
||||||
|
|
||||||
// Check if it meets the minimum/maximum
|
|
||||||
if (length < minimum || length > maximum) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it passes both return true
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate email address formats
|
|
||||||
public static validateEmail(email: string): boolean {
|
|
||||||
// RFC compliant e-mail address regex
|
|
||||||
var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,48})+$/;
|
|
||||||
|
|
||||||
// Test it on the email var which'll return a boolean
|
|
||||||
return re.test(email);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the time that has elapsed since a certain data (doesn't take leap years in account).
|
|
||||||
public static timeElapsed(timestamp: number, append: string = ' ago', none: string = 'Just now'): string {
|
|
||||||
// Subtract the entered timestamp from the current timestamp
|
|
||||||
var time: number = this.epoch() - timestamp;
|
|
||||||
|
|
||||||
// If the new timestamp is below 1 return a standard string
|
|
||||||
if (time < 1) {
|
|
||||||
return none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Times array
|
|
||||||
var times: Object = {
|
|
||||||
31536000: ['year', 'a'],
|
|
||||||
2592000: ['month', 'a'],
|
|
||||||
604800: ['week', 'a'],
|
|
||||||
86400: ['day', 'a'],
|
|
||||||
3600: ['hour', 'an'],
|
|
||||||
60: ['minute', 'a'],
|
|
||||||
1: ['second', 'a']
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
var timeKeys: string[] = Object.keys(times).reverse();
|
|
||||||
|
|
||||||
// Iterate over the times
|
|
||||||
for (var i in timeKeys) {
|
|
||||||
// Do a devision to check if the given timestamp fits in the current "type"
|
|
||||||
var calc: number = time / parseInt(timeKeys[i]);
|
|
||||||
|
|
||||||
// Check if we have a match
|
|
||||||
if (calc >= 1) {
|
|
||||||
// Round the number
|
|
||||||
var display: number = Math.floor(calc);
|
|
||||||
|
|
||||||
// Return the formatted string
|
|
||||||
return (display === 1 ? times[timeKeys[i]][1] : display) + " " + times[timeKeys[i]][0] + (display === 1 ? '' : 's') + append;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If everything fails just return none
|
|
||||||
return none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare function unescape(a);
|
|
||||||
declare function escape(a);
|
|
||||||
|
|
||||||
// UTF-8 functions
|
|
||||||
class utf8 {
|
|
||||||
// Encode a utf-8 string
|
|
||||||
public static encode(string): string {
|
|
||||||
return unescape(encodeURIComponent(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode a utf-8 string
|
|
||||||
public static decode(string): string {
|
|
||||||
return decodeURIComponent(escape(string));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP methods
|
|
||||||
enum HTTPMethods {
|
|
||||||
GET,
|
|
||||||
HEAD,
|
|
||||||
POST,
|
|
||||||
PUT,
|
|
||||||
DELETE
|
|
||||||
}
|
|
||||||
|
|
||||||
// AJAX functions
|
|
||||||
class AJAX {
|
|
||||||
// XMLHTTPRequest container
|
|
||||||
private request: XMLHttpRequest;
|
|
||||||
private callbacks: Object;
|
|
||||||
private headers: Object;
|
|
||||||
private url: string;
|
|
||||||
private send: string = null;
|
|
||||||
|
|
||||||
// Prepares the XMLHttpRequest and stuff
|
|
||||||
constructor() {
|
|
||||||
this.request = new XMLHttpRequest();
|
|
||||||
this.callbacks = new Object();
|
|
||||||
this.headers = new Object();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start
|
|
||||||
public start(method: HTTPMethods): void {
|
|
||||||
// Open the connection
|
|
||||||
this.request.open(HTTPMethods[method], this.url, true);
|
|
||||||
|
|
||||||
// Set headers
|
|
||||||
this.prepareHeaders();
|
|
||||||
|
|
||||||
// Watch the ready state
|
|
||||||
this.request.onreadystatechange = () => {
|
|
||||||
// Only invoke when complete
|
|
||||||
if (this.request.readyState === 4) {
|
|
||||||
// Check if a callback if present
|
|
||||||
if ((typeof this.callbacks[this.request.status]).toLowerCase() === 'function') {
|
|
||||||
this.callbacks[this.request.status]();
|
|
||||||
} else { // Else check if there's a generic fallback present
|
|
||||||
if ((typeof this.callbacks['0']).toLowerCase() === 'function') {
|
|
||||||
// Call that
|
|
||||||
this.callbacks['0']();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.request.send(this.send);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop
|
|
||||||
public stop(): void {
|
|
||||||
this.request = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add post data
|
|
||||||
public setSend(data: Object): void {
|
|
||||||
// Storage array
|
|
||||||
var store: Array<string> = new Array<string>();
|
|
||||||
|
|
||||||
// Iterate over the object and them in the array with an equals sign inbetween
|
|
||||||
for (var item in data) {
|
|
||||||
store.push(encodeURIComponent(item) + "=" + encodeURIComponent(data[item]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign to send
|
|
||||||
this.send = store.join('&');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set raw post
|
|
||||||
public setRawSend(data: string) {
|
|
||||||
this.send = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get response
|
|
||||||
public response(): string {
|
|
||||||
return this.request.responseText;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set charset
|
|
||||||
public contentType(type: string, charset: string = null): void {
|
|
||||||
this.addHeader('Content-Type', type + ';charset=' + (charset ? charset : 'utf-8'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a header
|
|
||||||
public addHeader(name: string, value: string): void {
|
|
||||||
// Attempt to remove a previous instance
|
|
||||||
this.removeHeader(name);
|
|
||||||
|
|
||||||
// Add the new header
|
|
||||||
this.headers[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a header
|
|
||||||
public removeHeader(name: string): void {
|
|
||||||
if ((typeof this.headers[name]).toLowerCase() !== 'undefined') {
|
|
||||||
delete this.headers[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare request headers
|
|
||||||
public prepareHeaders(): void {
|
|
||||||
for (var header in this.headers) {
|
|
||||||
this.request.setRequestHeader(header, this.headers[header]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a callback
|
|
||||||
public addCallback(status: number, callback: Function): void {
|
|
||||||
// Attempt to remove previous instances
|
|
||||||
this.removeCallback(status);
|
|
||||||
|
|
||||||
// Add the new callback
|
|
||||||
this.callbacks[status] = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete a callback
|
|
||||||
public removeCallback(status: number): void {
|
|
||||||
// Delete the callback if present
|
|
||||||
if ((typeof this.callbacks[status]).toLowerCase() === 'function') {
|
|
||||||
delete this.callbacks[status];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the URL
|
|
||||||
public setUrl(url: string): void {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
}
|
|
10
resources/assets/typescript/yuuno/Main.ts
Normal file
10
resources/assets/typescript/yuuno/Main.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Yuuno
|
||||||
|
{
|
||||||
|
export class Main
|
||||||
|
{
|
||||||
|
public static Startup()
|
||||||
|
{
|
||||||
|
Sakura.Main.Startup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,7 +101,7 @@ function notifyClose(id: string): void {
|
||||||
|
|
||||||
// Remove after 410 ms
|
// Remove after 410 ms
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Sakura.removeById(id);
|
(new Sakura.DOM(id, Sakura.DOMSelector.ID)).Remove();
|
||||||
}, 410);
|
}, 410);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,13 +122,13 @@ function notifyRequest(session: string): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create AJAX object
|
// Create AJAX object
|
||||||
var get: any = new AJAX();
|
var get = new Sakura.AJAX();
|
||||||
get.setUrl('/notifications');
|
get.SetUrl('/notifications');
|
||||||
|
|
||||||
// Add callbacks
|
// Add callbacks
|
||||||
get.addCallback(200, () => {
|
get.AddCallback(200, () => {
|
||||||
// Assign the parsed JSON
|
// Assign the parsed JSON
|
||||||
var data: Notification = JSON.parse(get.response());
|
var data: Notification = JSON.parse(get.Response());
|
||||||
|
|
||||||
// Check if nothing went wrong
|
// Check if nothing went wrong
|
||||||
if ((typeof data).toLowerCase() === 'undefined') {
|
if ((typeof data).toLowerCase() === 'undefined') {
|
||||||
|
@ -142,7 +142,7 @@ function notifyRequest(session: string): void {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
get.start(HTTPMethods.GET);
|
get.Start(Sakura.HTTPMethod.GET);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the full page busy window
|
// Show the full page busy window
|
||||||
|
@ -216,7 +216,7 @@ function ajaxBusyView(show: boolean, message: string = null, type: string = null
|
||||||
if (parseInt(cont.style.opacity) > 0) {
|
if (parseInt(cont.style.opacity) > 0) {
|
||||||
cont.style.opacity = (parseInt(cont.style.opacity) - 0.1).toString();
|
cont.style.opacity = (parseInt(cont.style.opacity) - 0.1).toString();
|
||||||
} else {
|
} else {
|
||||||
Sakura.removeById('ajaxBusy');
|
(new Sakura.DOM('ajaxBusy', Sakura.DOMSelector.ID)).Remove();
|
||||||
clearInterval(out);
|
clearInterval(out);
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
|
@ -227,29 +227,29 @@ function ajaxBusyView(show: boolean, message: string = null, type: string = null
|
||||||
// Making a post request using AJAX
|
// Making a post request using AJAX
|
||||||
function ajaxPost(url: string, data: Object, callback: Function) {
|
function ajaxPost(url: string, data: Object, callback: Function) {
|
||||||
// Create AJAX
|
// Create AJAX
|
||||||
var request: any = new AJAX();
|
var request = new Sakura.AJAX;
|
||||||
|
|
||||||
// Set url
|
// Set url
|
||||||
request.setUrl(url);
|
request.SetUrl(url);
|
||||||
|
|
||||||
// Add callbacks
|
// Add callbacks
|
||||||
request.addCallback(200, function() {
|
request.AddCallback(200, function() {
|
||||||
callback.call(request.response())
|
callback.call(request.Response())
|
||||||
});
|
});
|
||||||
request.addCallback(0, function() {
|
request.AddCallback(0, function() {
|
||||||
ajaxBusyView(false);
|
ajaxBusyView(false);
|
||||||
|
|
||||||
throw "POST Request failed";
|
throw "POST Request failed";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add header
|
// Add header
|
||||||
request.addHeader('Content-Type', 'application/x-www-form-urlencoded');
|
request.AddHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
// Set the post data
|
// Set the post data
|
||||||
request.setSend(data);
|
request.SetSend(data);
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
request.start(HTTPMethods.POST);
|
request.Start(Sakura.HTTPMethod.POST);
|
||||||
|
|
||||||
// Return the AJAX object
|
// Return the AJAX object
|
||||||
return request;
|
return request;
|
||||||
|
@ -399,7 +399,7 @@ function submitPostHandler(data: string, busyView: boolean, resetCaptcha: boolea
|
||||||
|
|
||||||
// Check if a password is within the minimum entropy value
|
// Check if a password is within the minimum entropy value
|
||||||
function checkPwdEntropy(pwd: string): boolean {
|
function checkPwdEntropy(pwd: string): boolean {
|
||||||
return (Sakura.entropy(pwd) >= sakuraVars.minPwdEntropy);
|
return (Sakura.Legacy.entropy(pwd) >= sakuraVars.minPwdEntropy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check registration variables
|
// Check registration variables
|
||||||
|
@ -420,12 +420,12 @@ function registerVarCheck(id: string, mode: string, option: any = null): void {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'email':
|
case 'email':
|
||||||
check = Sakura.validateEmail(input.value);
|
check = Sakura.Legacy.validateEmail(input.value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'username':
|
case 'username':
|
||||||
default:
|
default:
|
||||||
check = Sakura.stringLength(input.value, sakuraVars.minUserLen, sakuraVars.maxUserLen);
|
check = Sakura.Legacy.stringLength(input.value, sakuraVars.minUserLen, sakuraVars.maxUserLen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Login' %}
|
{% set title = 'Login' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Reactivate account' %}
|
{% set title = 'Reactivate account' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Register' %}
|
{% set title = 'Register' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Reset Password' %}
|
{% set title = 'Reset Password' %}
|
||||||
|
|
||||||
|
|
|
@ -26,22 +26,22 @@
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var commentClient = new AJAX();
|
var commentClient = new Sakura.AJAX();
|
||||||
|
|
||||||
commentClient.contentType("application/x-www-form-urlencoded");
|
commentClient.ContentType("application/x-www-form-urlencoded");
|
||||||
|
|
||||||
function commentPost(element, url) {
|
function commentPost(element, url) {
|
||||||
var text = element.querySelector('[name="text"]'),
|
var text = element.querySelector('[name="text"]'),
|
||||||
session = element.querySelector('[name="session"]');
|
session = element.querySelector('[name="session"]');
|
||||||
|
|
||||||
commentClient.setSend({"text":text.value,"session":session.value});
|
commentClient.SetSend({"text":text.value,"session":session.value});
|
||||||
|
|
||||||
text.value = '';
|
text.value = '';
|
||||||
|
|
||||||
commentClient.setUrl(url);
|
commentClient.SetUrl(url);
|
||||||
|
|
||||||
commentClient.addCallback(200, function () {
|
commentClient.AddCallback(200, function () {
|
||||||
var resp = JSON.parse(commentClient.response());
|
var resp = JSON.parse(commentClient.Response());
|
||||||
|
|
||||||
if (resp.error) {
|
if (resp.error) {
|
||||||
ajaxBusyView(true, resp.error, 'fail');
|
ajaxBusyView(true, resp.error, 'fail');
|
||||||
|
@ -53,10 +53,10 @@
|
||||||
commentAdd(resp);
|
commentAdd(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
commentClient.setRawSend("");
|
commentClient.SetRawSend("");
|
||||||
});
|
});
|
||||||
|
|
||||||
commentClient.start(HTTPMethods.POST);
|
commentClient.Start(Sakura.HTTPMethod.POST);
|
||||||
}
|
}
|
||||||
|
|
||||||
function commentAdd(obj) {
|
function commentAdd(obj) {
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
|
|
||||||
var controlsInner = document.createElement('ul');
|
var controlsInner = document.createElement('ul');
|
||||||
|
|
||||||
if (Sakura.cookie('id') == obj.user) {
|
if (Sakura.Cookies.Get(sakuraVars.cookie.prefix + 'id') == obj.user) {
|
||||||
var controlsTrashContainer = document.createElement('li');
|
var controlsTrashContainer = document.createElement('li');
|
||||||
var controlsTrash = document.createElement('a');
|
var controlsTrash = document.createElement('a');
|
||||||
controlsTrash.href = 'javascript:void(0);';
|
controlsTrash.href = 'javascript:void(0);';
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
|
|
||||||
// Remove it if it already exists
|
// Remove it if it already exists
|
||||||
if (replyBox) {
|
if (replyBox) {
|
||||||
Sakura.removeById('comment-reply-container-' + id);
|
(new Sakura.DOM('comment-reply-container-' + id, Sakura.DOMSelector.ID)).Remove();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +250,10 @@
|
||||||
function commentDelete(id) {
|
function commentDelete(id) {
|
||||||
var url = "{{ route('comments.comment.delete', 1) }}".replace(1, id);
|
var url = "{{ route('comments.comment.delete', 1) }}".replace(1, id);
|
||||||
|
|
||||||
commentClient.setUrl(url);
|
commentClient.SetUrl(url);
|
||||||
|
|
||||||
commentClient.addCallback(200, function () {
|
commentClient.AddCallback(200, function () {
|
||||||
var resp = JSON.parse(commentClient.response());
|
var resp = JSON.parse(commentClient.Response());
|
||||||
|
|
||||||
if (resp.error) {
|
if (resp.error) {
|
||||||
ajaxBusyView(true, resp.error, 'fail');
|
ajaxBusyView(true, resp.error, 'fail');
|
||||||
|
@ -262,11 +262,11 @@
|
||||||
ajaxBusyView(false);
|
ajaxBusyView(false);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
Sakura.removeById("comment-" + id);
|
(new Sakura.DOM("comment-" + id, Sakura.DOMSelector.ID)).Remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
commentClient.start(HTTPMethods.POST);
|
commentClient.Start(Sakura.HTTPMethod.POST);
|
||||||
}
|
}
|
||||||
|
|
||||||
function commentVote(id, vote) {
|
function commentVote(id, vote) {
|
||||||
|
@ -274,12 +274,12 @@
|
||||||
upvotes = document.getElementById("comment-" + id + "-likes"),
|
upvotes = document.getElementById("comment-" + id + "-likes"),
|
||||||
downvotes = document.getElementById("comment-" + id + "-dislikes");
|
downvotes = document.getElementById("comment-" + id + "-dislikes");
|
||||||
|
|
||||||
commentClient.setSend({"vote":vote});
|
commentClient.SetSend({"vote":vote});
|
||||||
|
|
||||||
commentClient.setUrl(url);
|
commentClient.SetUrl(url);
|
||||||
|
|
||||||
commentClient.addCallback(200, function () {
|
commentClient.AddCallback(200, function () {
|
||||||
var resp = JSON.parse(commentClient.response());
|
var resp = JSON.parse(commentClient.Response());
|
||||||
|
|
||||||
if (resp.error) {
|
if (resp.error) {
|
||||||
ajaxBusyView(true, resp.error, 'fail');
|
ajaxBusyView(true, resp.error, 'fail');
|
||||||
|
@ -292,10 +292,10 @@
|
||||||
downvotes.innerText = resp.downvotes;
|
downvotes.innerText = resp.downvotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
commentClient.setRawSend("");
|
commentClient.SetRawSend("");
|
||||||
});
|
});
|
||||||
|
|
||||||
commentClient.start(HTTPMethods.POST);
|
commentClient.Start(Sakura.HTTPMethod.POST);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
All active users in the past 2 minutes
|
All active users in the past 2 minutes
|
||||||
<table class="panelTable">
|
<table class="panelTable">
|
||||||
{% for amount,onlineUser in stats.onlineUsers %}
|
{% 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 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('D Y-m-d H:i:s T') }}</time></td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
<div class="news-post-time">
|
<div class="news-post-time">
|
||||||
Posted <time 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('D Y-m-d H:i:s T') }}</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 %}
|
{% 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>
|
</div>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<div>
|
<div>
|
||||||
{% if forum.lastPost.id %}
|
{% 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>
|
<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 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('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>
|
||||||
{% else %}
|
{% else %}
|
||||||
There are no posts in this forum.<br>
|
There are no posts in this forum.<br>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -53,14 +53,14 @@
|
||||||
rText = document.getElementById('previewText'),
|
rText = document.getElementById('previewText'),
|
||||||
lastParsed = Date.now(),
|
lastParsed = Date.now(),
|
||||||
lastKeystroke = Date.now(),
|
lastKeystroke = Date.now(),
|
||||||
parser = new AJAX(),
|
parser = new Sakura.AJAX(),
|
||||||
postFetch = new AJAX(),
|
postFetch = new Sakura.AJAX(),
|
||||||
parserActive = false,
|
parserActive = false,
|
||||||
op = {{ topic is defined ? topic.firstPost.id : 0 }},
|
op = {{ topic is defined ? topic.firstPost.id : 0 }},
|
||||||
topicName = "{{ topic is defined ? topic.firstPost.subject : '' }}";
|
topicName = "{{ topic is defined ? topic.firstPost.subject : '' }}";
|
||||||
|
|
||||||
parser.setUrl("{{ route('helper.bbcode.parse') }}");
|
parser.SetUrl("{{ route('helper.bbcode.parse') }}");
|
||||||
parser.contentType("application/x-www-form-urlencoded");
|
parser.ContentType("application/x-www-form-urlencoded");
|
||||||
|
|
||||||
pText.addEventListener("focus", function () {
|
pText.addEventListener("focus", function () {
|
||||||
preview.style.display = null;
|
preview.style.display = null;
|
||||||
|
@ -89,10 +89,10 @@
|
||||||
} else {
|
} else {
|
||||||
parserActive = true;
|
parserActive = true;
|
||||||
|
|
||||||
parser.setSend({"text":text});
|
parser.SetSend({"text":text});
|
||||||
|
|
||||||
parser.addCallback(200, function () {
|
parser.AddCallback(200, function () {
|
||||||
rText.innerHTML = parser.response();
|
rText.innerHTML = parser.Response();
|
||||||
|
|
||||||
var codeBlocks = rText.querySelectorAll("pre code");
|
var codeBlocks = rText.querySelectorAll("pre code");
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
parserActive = false;
|
parserActive = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.start(HTTPMethods.POST);
|
parser.Start(Sakura.HTTPMethod.POST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
@ -156,10 +156,10 @@
|
||||||
|
|
||||||
url = "{{ route('forums.post.raw', '1') }}".replace('1', id);
|
url = "{{ route('forums.post.raw', '1') }}".replace('1', id);
|
||||||
|
|
||||||
postFetch.setUrl(url);
|
postFetch.SetUrl(url);
|
||||||
|
|
||||||
postFetch.addCallback(200, function () {
|
postFetch.AddCallback(200, function () {
|
||||||
pText.value = postFetch.response();
|
pText.value = postFetch.Response();
|
||||||
pStopEdit.style.display = null;
|
pStopEdit.style.display = null;
|
||||||
pForm.action = "{{ route('forums.post.edit', '1') }}".replace('1', id);
|
pForm.action = "{{ route('forums.post.edit', '1') }}".replace('1', id);
|
||||||
pMode.innerText = 'Editing #' + id;
|
pMode.innerText = 'Editing #' + id;
|
||||||
|
@ -172,7 +172,7 @@
|
||||||
pText.focus();
|
pText.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
postFetch.start(HTTPMethods.GET);
|
postFetch.Start(Sakura.HTTPMethod.GET);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopEdit() {
|
function stopEdit() {
|
||||||
|
|
|
@ -22,6 +22,6 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
[deleted user]
|
[deleted user]
|
||||||
{% endif %} <a href="{{ route('forums.post', topic.lastPost.id) }}" class="default fa fa-tag"></a><br>
|
{% endif %} <a href="{{ route('forums.post', topic.lastPost.id) }}" class="default fa fa-tag"></a><br>
|
||||||
<time 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('D Y-m-d H:i:s T') }}</time>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title %}Forums / {{ forum.name }}{% endset %}
|
{% set title %}Forums / {{ forum.name }}{% endset %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Forums' %}
|
{% set title = 'Forums' %}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
<td style="text-align: left; border-bottom: 1px solid #9475b2;">
|
<td style="text-align: left; border-bottom: 1px solid #9475b2;">
|
||||||
<a href="{{ route('forums.topic', _t.id) }}" class="default">{{ _t.title }}</a>
|
<a href="{{ route('forums.topic', _t.id) }}" class="default">{{ _t.title }}</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="rightAlign" style="border-bottom: 1px solid #9475b2;"><time 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('D Y-m-d H:i:s T') }}</time></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
by
|
by
|
||||||
<a href="{{ route('user.profile', _p.poster.id) }}" class="default"><span style="color: {{ _p.poster.colour }};">{{ _p.poster.username }}</span></a>
|
<a href="{{ route('user.profile', _p.poster.id) }}" class="default"><span style="color: {{ _p.poster.colour }};">{{ _p.poster.username }}</span></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="rightAlign" style="border-bottom: 1px solid #9475b2;"><time 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('D Y-m-d H:i:s T') }}</time></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set forumBackLink %}{{ route('forums.forum', forum.id) }}{% endset %}
|
{% set forumBackLink %}{{ route('forums.forum', forum.id) }}{% endset %}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not (post.poster.permission(constant('Sakura\\Perms\\Site::DEACTIVATED')) or post.poster.permission(constant('Sakura\\Perms\\Site::RESTRICTED')) or user.id == post.poster.id) %}
|
{% if not (post.poster.permission(constant('Sakura\\Perms\\Site::DEACTIVATED')) or post.poster.permission(constant('Sakura\\Perms\\Site::RESTRICTED')) or user.id == post.poster.id) %}
|
||||||
<a class="fa fa-{% if user.isFriends(post.poster.id) == 2 %}heart{% else %}star{% endif %} friend-{{ post.poster.id }}-level" title="You are friends" {% if user.isFriends(post.poster.id) == 0 %}style="display: none;"{% endif %}></a>
|
<a class="fa fa-{% if user.isFriends(post.poster.id) == 2 %}heart{% else %}star{% endif %} friend-{{ post.poster.id }}-level" title="You are friends" {% if user.isFriends(post.poster.id) == 0 %}style="display: none;"{% endif %}></a>
|
||||||
<a class="fa fa-user-{% if user.isFriends(post.poster.id) == 0 %}plus{% else %}times{% endif %} forum-friend-toggle friend-{{ post.poster.id }}-toggle" title="{% if user.isFriends(post.poster.id) == 0 %}Add {{ post.poster.username }} as a friend{% else %}Remove friend{% endif %}" href="javascript:void(0);" onclick="{% if user.isFriends(post.poster.id) == 0 %}addFriend({{ post.poster.id }}){% else %}removeFriend({{ post.poster.id }}){% endif %}"></a>
|
<a class="fa fa-user-{% if user.isFriends(post.poster.id) == 0 %}plus{% else %}times{% endif %} forum-friend-toggle friend-{{ post.poster.id }}-toggle" title="{% if user.isFriends(post.poster.id) == 0 %}Add {{ post.poster.username }} as a friend{% else %}Remove friend{% endif %}" href="javascript:void(0);" onclick="Sakura.Friend.{% if user.isFriends(post.poster.id) == 0 %}Add({{ post.poster.id }}){% else %}Remove({{ post.poster.id }}){% endif %}"></a>
|
||||||
<a class="fa fa-flag" title="Report {{ post.poster.username }}" href="{{ route('user.report', post.poster.id) }}"></a>
|
<a class="fa fa-flag" title="Report {{ post.poster.username }}" href="{{ route('user.report', post.poster.id) }}"></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="fa fa-reply" title="Quote this post" href="javascript:void(0);" onclick="quotePost({{ post.id }});"></a>
|
<a class="fa fa-reply" title="Quote this post" href="javascript:void(0);" onclick="quotePost({{ post.id }});"></a>
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
<a href="#p{{ post.id }}" class="clean">{{ post.subject|slice(0, 50) }}{% if post.subject|length > 50 %}...{% endif %}</a>
|
<a href="#p{{ post.id }}" class="clean">{{ post.subject|slice(0, 50) }}{% if post.subject|length > 50 %}...{% endif %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="date">
|
<div class="date">
|
||||||
<a href="{{ route('forums.post', post.id) }}" class="clean">#{{ post.id }} - <time 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('D Y-m-d H:i:s T') }}</time></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Confirmation' %}
|
{% set title = 'Confirmation' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Information' %}
|
{% set title = 'Information' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Restricted' %}
|
{% set title = 'Restricted' %}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="content standalone bbcode">
|
<div class="content standalone bbcode">
|
||||||
|
|
27
resources/views/yuuno/manage/master.twig
Normal file
27
resources/views/yuuno/manage/master.twig
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
|
{% set title = category ~ ' / ' ~ mode %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="content settings messages">
|
||||||
|
<div class="content-right content-column">
|
||||||
|
<div class="head">
|
||||||
|
Navigation
|
||||||
|
</div>
|
||||||
|
<div class="right-menu-nav">
|
||||||
|
{% for name, links in navigation %}
|
||||||
|
<div>{{ name }}</div>
|
||||||
|
{% for name,link in links %}
|
||||||
|
<a href="{{ link }}">{{ name }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content-left content-column">
|
||||||
|
<div class="head">{{ title }}</div>
|
||||||
|
<div class="settings-explanation">{{ block('description') }}</div>
|
||||||
|
{{ block('manageContent') }}
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
11
resources/views/yuuno/manage/overview/index.twig
Normal file
11
resources/views/yuuno/manage/overview/index.twig
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends 'manage/overview/master.twig' %}
|
||||||
|
|
||||||
|
{% set mode = 'Index' %}
|
||||||
|
|
||||||
|
{% block description %}
|
||||||
|
<p>A quick overview on what's going on.</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block manageContent %}
|
||||||
|
<h1>wew</h1>
|
||||||
|
{% endblock %}
|
3
resources/views/yuuno/manage/overview/master.twig
Normal file
3
resources/views/yuuno/manage/overview/master.twig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends 'manage/master.twig' %}
|
||||||
|
|
||||||
|
{% set category = 'Overview' %}
|
|
@ -1,7 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<!-- META -->
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{{ title|default(config('general.name')) }}</title>
|
<title>{{ title|default(config('general.name')) }}</title>
|
||||||
<meta name="description" content="{{ description|default(config('general.description')) }}">
|
<meta name="description" content="{{ description|default(config('general.description')) }}">
|
||||||
|
@ -10,13 +9,13 @@
|
||||||
<meta http-equiv="refresh" content="{{ redirectTimeout ? redirectTimeout : '3' }}; URL={{ redirect }}">
|
<meta http-equiv="refresh" content="{{ redirectTimeout ? redirectTimeout : '3' }}; URL={{ redirect }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ block('meta') }}
|
{{ block('meta') }}
|
||||||
<!-- CSS -->
|
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" type="text/css">
|
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" type="text/css">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/libraries.css">
|
<link rel="stylesheet" type="text/css" href="/css/libraries.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/yuuno.css">
|
<link rel="stylesheet" type="text/css" href="/css/yuuno.css">
|
||||||
{{ block('css') }}
|
{{ block('css') }}
|
||||||
<!-- JS -->
|
|
||||||
<script type="text/javascript" src="/js/master.js"></script>
|
<script type="text/javascript" src="/js/app.js"></script>
|
||||||
<script type="text/javascript" src="/js/yuuno.js"></script>
|
<script type="text/javascript" src="/js/yuuno.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
// Create an object so we can access certain settings from remote JavaScript files
|
// Create an object so we can access certain settings from remote JavaScript files
|
||||||
|
@ -35,9 +34,6 @@
|
||||||
"checkLogin": {{ user.isActive ? 'true' : 'false' }}
|
"checkLogin": {{ user.isActive ? 'true' : 'false' }}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set cookie prefix and path
|
|
||||||
Sakura.cookiePrefix = "{{ config('cookie.prefix') }}";
|
|
||||||
|
|
||||||
// Error reporter
|
// Error reporter
|
||||||
window.onerror = function(msg, url, line, col, error) {
|
window.onerror = function(msg, url, line, col, error) {
|
||||||
notifyUI({
|
notifyUI({
|
||||||
|
@ -73,7 +69,7 @@
|
||||||
<a class="menu-item avatar" href="{{ route('user.profile', user.id) }}" title="Logged in as {{ user.username }}" style="background-image: url('{{ route('file.avatar', user.id) }}'); width: auto; color: {{ user.colour }}; border-color: {{ user.colour }}; font-weight: 700;"></a>
|
<a class="menu-item avatar" href="{{ route('user.profile', user.id) }}" title="Logged in as {{ user.username }}" style="background-image: url('{{ route('file.avatar', user.id) }}'); width: auto; color: {{ user.colour }}; border-color: {{ user.colour }}; font-weight: 700;"></a>
|
||||||
{#<a class="menu-item fa-envelope" href="#" title="Messages"></a>#}
|
{#<a class="menu-item fa-envelope" href="#" title="Messages"></a>#}
|
||||||
{% if user.permission(constant('Sakura\\Perms\\Manage::USE_MANAGE'), constant('Sakura\\Perms::MANAGE')) %}
|
{% if user.permission(constant('Sakura\\Perms\\Manage::USE_MANAGE'), constant('Sakura\\Perms::MANAGE')) %}
|
||||||
<a class="menu-item fa-gavel" href="#" title="Manage"></a>
|
<a class="menu-item fa-gavel" href="{{ route('manage.index') }}" title="Manage"></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="menu-item fa-cogs" href="{{ route('settings.index') }}" title="Settings"></a>
|
<a class="menu-item fa-cogs" href="{{ route('settings.index') }}" title="Settings"></a>
|
||||||
<a class="menu-item fa-sign-out" href="{{ route('auth.logout') }}?s={{ session_id() }}" title="Logout" id="headerLogoutLink"></a>
|
<a class="menu-item fa-sign-out" href="{{ route('auth.logout') }}?s={{ session_id() }}" title="Logout" id="headerLogoutLink"></a>
|
||||||
|
@ -164,175 +160,26 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
// Parse time elements
|
Sakura.Config.Set({
|
||||||
var timeElems = document.getElementsByTagName('time');
|
Revision: {{ constant('SAKURA_VERSION') }},
|
||||||
|
UserNameMinLength: {{ config('user.name_min') }},
|
||||||
|
UserNameMaxLength: {{ config('user.name_max') }},
|
||||||
|
PasswordMinEntropy: {{ config('user.pass_min_entropy') }},
|
||||||
|
LoggedIn: {{ user.isActive ? 'true' : 'false' }},
|
||||||
|
SessionId: "{{ session_id() }}",
|
||||||
|
});
|
||||||
|
|
||||||
// Iterate over them
|
Yuuno.Main.Startup();
|
||||||
for (var timeElem in timeElems) {
|
|
||||||
console.log(timeElems[timeElem].dateTime);
|
|
||||||
// Attempt to parse it
|
|
||||||
var parsed = Date.parse(timeElems[timeElem].dateTime);
|
|
||||||
|
|
||||||
// If it can be parsed do DOM edits
|
|
||||||
if (!isNaN(parsed)) {
|
|
||||||
timeElems[timeElem].title = timeElems[timeElem].innerText;
|
|
||||||
timeElems[timeElem].innerText = Sakura.timeElapsed(Math.floor(parsed / 1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyRequest('{{ session_id() }}');
|
|
||||||
|
|
||||||
setInterval(function() {
|
|
||||||
notifyRequest('{{ session_id() }}');
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
var friendClient = new AJAX();
|
|
||||||
|
|
||||||
friendClient.contentType("application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
function addFriend(id) {
|
|
||||||
var url = "{{ route('friends.add', 1) }}".replace(1, id);
|
|
||||||
friendMode(url, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeFriend(id) {
|
|
||||||
var url = "{{ route('friends.remove', 1) }}".replace(1, id);
|
|
||||||
friendMode(url, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function friendMode(url, id) {
|
|
||||||
var level = document.querySelectorAll('.friend-' + id + '-level'),
|
|
||||||
toggle = document.querySelectorAll('.friend-' + id + '-toggle');
|
|
||||||
|
|
||||||
friendClient.setUrl(url);
|
|
||||||
|
|
||||||
friendClient.setSend({"session":"{{ session_id() }}"});
|
|
||||||
|
|
||||||
friendClient.addCallback(200, function () {
|
|
||||||
var resp = JSON.parse(friendClient.response());
|
|
||||||
|
|
||||||
friendClient.setRawSend("");
|
|
||||||
|
|
||||||
if (resp.error) {
|
|
||||||
ajaxBusyView(true, resp.error, 'fail');
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
ajaxBusyView(false);
|
|
||||||
}, 1500);
|
|
||||||
} else {
|
|
||||||
ajaxBusyView(true, resp.message, 'ok');
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
friendClient.start(HTTPMethods.POST);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% if config('dev.show_changelog', true) and stats %}
|
{% if config('dev.show_changelog', true) and stats %}
|
||||||
<script type="text/javascript">
|
Sakura.Changelog.Build(new Sakura.DOM('indexPanel', Sakura.DOMSelector.ID));
|
||||||
// Column colours for actions
|
|
||||||
var changelogColours = [
|
|
||||||
'inherit', // Unknown
|
|
||||||
'#2A2', // Add
|
|
||||||
'#2AA', // Update
|
|
||||||
'#2AA', // Fix
|
|
||||||
'#A22', // Remove
|
|
||||||
'#62C', // Export
|
|
||||||
'#C44' // Revert
|
|
||||||
];
|
|
||||||
|
|
||||||
function yuunoCreateChangelog() {
|
|
||||||
// Grab the index panel
|
|
||||||
var _panel = document.getElementById('indexPanel');
|
|
||||||
|
|
||||||
// Create the head container
|
|
||||||
var _cltitle = document.createElement('div');
|
|
||||||
_cltitle.className = 'head';
|
|
||||||
_cltitle.style.marginBottom = '1px';
|
|
||||||
|
|
||||||
// Create a link
|
|
||||||
var _cllink = document.createElement('a');
|
|
||||||
_cllink.className = 'underline';
|
|
||||||
_cllink.target = '_blank';
|
|
||||||
_cllink.href = 'https://sakura.flash.moe/#r{{ constant('SAKURA_VERSION') }}';
|
|
||||||
|
|
||||||
// Append everything
|
|
||||||
_cllink.appendChild(document.createTextNode('Changelog'));
|
|
||||||
_cltitle.appendChild(_cllink);
|
|
||||||
_panel.appendChild(_cltitle);
|
|
||||||
|
|
||||||
// Create changelog table
|
|
||||||
var _cltable = document.createElement('table');
|
|
||||||
_cltable.className = 'panelTable';
|
|
||||||
_cltable.style.borderSpacing = '0 1px';
|
|
||||||
_cltable.id = 'yuunoChangelogTable';
|
|
||||||
|
|
||||||
// Append it to indexPanel
|
|
||||||
indexPanel.appendChild(_cltable);
|
|
||||||
}
|
|
||||||
|
|
||||||
function yuunoAddToChangelog(object) {
|
|
||||||
_cltable = document.getElementById('yuunoChangelogTable');
|
|
||||||
|
|
||||||
// Create header
|
|
||||||
var _hr = document.createElement('tr');
|
|
||||||
var _hri = document.createElement('td');
|
|
||||||
|
|
||||||
// Set data
|
|
||||||
_hri.appendChild(document.createTextNode(object.date));
|
|
||||||
_hri.style.background = '#9475b2';
|
|
||||||
_hri.style.color = '#306';
|
|
||||||
_hri.style.fontWeight = '700';
|
|
||||||
_hri.style.fontSize = '1.2em';
|
|
||||||
_hri.setAttribute('colspan', '2');
|
|
||||||
|
|
||||||
// Append
|
|
||||||
_hr.appendChild(_hri);
|
|
||||||
_cltable.appendChild(_hr);
|
|
||||||
|
|
||||||
for (var _e in object.changes) {
|
|
||||||
// Reassign _e
|
|
||||||
_e = object.changes[_e];
|
|
||||||
|
|
||||||
// Create elements
|
|
||||||
var _clr = document.createElement('tr');
|
|
||||||
var _clca = document.createElement('td');
|
|
||||||
var _clcm = document.createElement('td');
|
|
||||||
|
|
||||||
// Set data
|
|
||||||
_clca.appendChild(document.createTextNode(_e.action.name));
|
|
||||||
_clca.style.background = changelogColours[_e.action.id];
|
|
||||||
_clca.style.borderBottom = '1px solid ' + changelogColours[_e.action.id];
|
|
||||||
_clcm.style.borderBottom = '1px solid ' + changelogColours[_e.action.id];
|
|
||||||
_clcm.appendChild(document.createTextNode(_e.message));
|
|
||||||
|
|
||||||
// Append
|
|
||||||
_clr.appendChild(_clca);
|
|
||||||
_clr.appendChild(_clcm);
|
|
||||||
_cltable.appendChild(_clr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
yuunoCreateChangelog();
|
|
||||||
|
|
||||||
var changelog = {},
|
|
||||||
fetch = 0,
|
|
||||||
clg = new AJAX();
|
|
||||||
|
|
||||||
clg.addCallback(200, function () {
|
|
||||||
yuunoAddToChangelog(JSON.parse(clg.response()));
|
|
||||||
if (fetch < 2) {
|
|
||||||
fetch++;
|
|
||||||
clg.setUrl('https://sakura.flash.moe/api.php/' + fetch);
|
|
||||||
clg.start(HTTPMethods.GET);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
clg.setUrl('https://sakura.flash.moe/api.php/' + fetch);
|
|
||||||
clg.start(HTTPMethods.GET);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
notifyRequest(Sakura.Config.SessionId);
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
notifyRequest(Sakura.Config.SessionId);
|
||||||
|
}, 60000);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'You are banned!' %}
|
{% set title = 'You are banned!' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Frequently Asked Questions' %}
|
{% set title = 'Frequently Asked Questions' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="content homepage">
|
<div class="content homepage">
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Search' %}
|
{% set title = 'Search' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title %}{{ page.category }} / {{ page.mode }}{% endset %}
|
{% set title %}{{ page.category }} / {{ page.mode }}{% endset %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'News' %}
|
{% set title = 'News' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = post.title %}
|
{% set title = post.title %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = 'Purchase complete!' %}
|
{% set title = 'Purchase complete!' %}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title %}Support {{ config('general.name') }}{% endset %}
|
{% set title %}Support {{ config('general.name') }}{% endset %}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{% block settingsContent %}
|
{% block settingsContent %}
|
||||||
<form enctype="multipart/form-data" method="post" action="{{ route('settings.account.username') }}">
|
<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>
|
<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 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('D Y-m-d H:i:s T') }}</time>.{% else %}This is your first username change.{% endif %}</h3>
|
||||||
{% if eligible %}
|
{% if eligible %}
|
||||||
<div class="profile-field">
|
<div class="profile-field">
|
||||||
<div><h2>Username</h2></div>
|
<div><h2>Username</h2></div>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
{{ s.user_agent }}
|
{{ s.user_agent }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<time 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('D Y-m-d H:i:s T') }}</time>
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 90px;">
|
<td style="width: 90px;">
|
||||||
<form method="post" action="{{ route('settings.advanced.sessions') }}">
|
<form method="post" action="{{ route('settings.advanced.sessions') }}">
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var parser = new AJAX(),
|
var parser = new Sakura.AJAX(),
|
||||||
textMax = {{ maxLength }},
|
textMax = {{ maxLength }},
|
||||||
form = document.getElementById("settingsEditor"),
|
form = document.getElementById("settingsEditor"),
|
||||||
preview = document.getElementById("settingsPreview");
|
preview = document.getElementById("settingsPreview");
|
||||||
|
|
||||||
parser.setUrl("{{ route('helper.bbcode.parse') }}");
|
parser.SetUrl("{{ route('helper.bbcode.parse') }}");
|
||||||
parser.contentType("application/x-www-form-urlencoded");
|
parser.ContentType("application/x-www-form-urlencoded");
|
||||||
|
|
||||||
function settingsPreview() {
|
function settingsPreview() {
|
||||||
var text = form.value;
|
var text = form.value;
|
||||||
|
@ -15,10 +15,10 @@
|
||||||
} else if (text.length > textMax) {
|
} else if (text.length > textMax) {
|
||||||
preview.innerHTML = "<span style='color: red;'>Too long!</span>";
|
preview.innerHTML = "<span style='color: red;'>Too long!</span>";
|
||||||
} else {
|
} else {
|
||||||
parser.setSend({"text":text});
|
parser.SetSend({"text":text});
|
||||||
|
|
||||||
parser.addCallback(200, function () {
|
parser.AddCallback(200, function () {
|
||||||
preview.innerHTML = parser.response();
|
preview.innerHTML = parser.Response();
|
||||||
|
|
||||||
var codeBlocks = preview.querySelectorAll("pre code");
|
var codeBlocks = preview.querySelectorAll("pre code");
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.start(HTTPMethods.POST);
|
parser.Start(Sakura.HTTPMethod.POST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="friends-list-name" style="color: {{ friend.colour }};">{{ friend.username }}</div>
|
<div class="friends-list-name" style="color: {{ friend.colour }};">{{ friend.username }}</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="friends-list-actions">
|
<div class="friends-list-actions">
|
||||||
<a class="remove fill fa fa-remove" title="Remove friend" href="javascript:void(0);" onclick="removeFriend({{ friend.id }});"></a>
|
<a class="remove fill fa fa-remove" title="Remove friend" href="javascript:void(0);" onclick="Sakura.Friend.Remove({{ friend.id }});"></a>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
<div class="friends-list-name" style="color: {{ friend.colour }};">{{ friend.username }}</div>
|
<div class="friends-list-name" style="color: {{ friend.colour }};">{{ friend.username }}</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="friends-list-actions">
|
<div class="friends-list-actions">
|
||||||
<a class="add fa fa-check" title="Add friend" href="javascript:void(0);" onclick="addFriend({{ friend.id }});"></a>
|
<a class="add fa fa-check" title="Add friend" href="javascript:void(0);" onclick="Sakura.Friend.Add({{ friend.id }});"></a>
|
||||||
<a class="remove fa fa-remove" title="Remove friend" href="javascript:void(0);" onclick="removeFriend({{ friend.id }});"></a>
|
<a class="remove fa fa-remove" title="Remove friend" href="javascript:void(0);" onclick="Sakura.Friend.Remove({{ friend.id }});"></a>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set title = category ~ ' / ' ~ mode %}
|
{% set title = category ~ ' / ' ~ mode %}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="notif-hist-time">
|
<div class="notif-hist-time">
|
||||||
<time 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('D Y-m-d H:i:s T') }}</time>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set sorts = ['boxes', 'rectangles', 'list'] %}
|
{% set sorts = ['boxes', 'rectangles', 'list'] %}
|
||||||
{% set sort = get.sort in sorts ? get.sort : sorts[0] %}
|
{% set sort = get.sort in sorts ? get.sort : sorts[0] %}
|
||||||
|
@ -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>
|
<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>
|
||||||
<td>
|
<td>
|
||||||
<time 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('D Y-m-d H:i:s T') }}</time>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if user.lastOnline == 0 %}<i>Never logged in.</i>{% else %}<time 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('D Y-m-d H:i:s T') }}</time>{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ user.title }}
|
{{ user.title }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% set profileHidden = profile.permission(constant('Sakura\\Perms\\Site::DEACTIVATED')) or (profile.permission(constant('Sakura\\Perms\\Site::RESTRICTED')) and (user.id != profile.id and not user.permission(constant('Sakura\\Perms\\Manage::USE_MANAGE'), constant('Sakura\\Perms::MANAGE')))) %}
|
{% set profileHidden = profile.permission(constant('Sakura\\Perms\\Site::DEACTIVATED')) or (profile.permission(constant('Sakura\\Perms\\Site::RESTRICTED')) and (user.id != profile.id and not user.permission(constant('Sakura\\Perms\\Manage::USE_MANAGE'), constant('Sakura\\Perms::MANAGE')))) %}
|
||||||
|
|
||||||
|
@ -84,12 +84,12 @@
|
||||||
{% 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>
|
{% 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>
|
||||||
<div class="new-profile-dates">
|
<div class="new-profile-dates">
|
||||||
<b>Joined</b> <time 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('D Y-m-d H:i:s T') }}</time>
|
||||||
<br>
|
<br>
|
||||||
{% if profile.lastOnline < 1 %}
|
{% if profile.lastOnline < 1 %}
|
||||||
<b>{{ profile.username }} hasn't logged in yet.</b>
|
<b>{{ profile.username }} hasn't logged in yet.</b>
|
||||||
{% else %}
|
{% else %}
|
||||||
<b>Last online</b> <time 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('D Y-m-d H:i:s T') }}</time>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if profile.birthday != '0000-00-00' and profile.birthday|split('-')[0] > 0 %}
|
{% 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>
|
<br><b>Age</b> <span title="{{ profile.birthday }}">{{ profile.birthday(true) }} years old</span>
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
<a class="fa fa-pencil-square-o" title="Edit your profile" href="{{ route('settings.general.profile') }}"></a>
|
<a class="fa fa-pencil-square-o" title="Edit your profile" href="{{ route('settings.general.profile') }}"></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if user.isFriends(profile.id) != 0 %}<a class="fa fa-{% if user.isFriends(profile.id) == 2 %}heart{% else %}star{% endif %}" title="You are friends"></a>{% endif %}
|
{% if user.isFriends(profile.id) != 0 %}<a class="fa fa-{% if user.isFriends(profile.id) == 2 %}heart{% else %}star{% endif %}" title="You are friends"></a>{% endif %}
|
||||||
<a class="fa fa-user-{% if user.isFriends(profile.id) == 0 %}plus{% else %}times{% endif %}" title="{% if user.isFriends(profile.id) == 0 %}Add {{ profile.username }} as a friend{% else %}Remove friend{% endif %}" href="javascript:void(0);" onclick="{% if user.isFriends(profile.id) == 0 %}addFriend({{ profile.id }}){% else %}removeFriend({{ profile.id }}){% endif %}"></a>
|
<a class="fa fa-user-{% if user.isFriends(profile.id) == 0 %}plus{% else %}times{% endif %}" title="{% if user.isFriends(profile.id) == 0 %}Add {{ profile.username }} as a friend{% else %}Remove friend{% endif %}" href="javascript:void(0);" onclick="Sakura.Friend.{% if user.isFriends(profile.id) == 0 %}Add({{ profile.id }}){% else %}Remove({{ profile.id }}){% endif %}"></a>
|
||||||
<a class="fa fa-exclamation-circle" title="Report {{ profile.username }}" href="{{ route('user.report', profile.id) }}"></a>
|
<a class="fa fa-exclamation-circle" title="Report {{ profile.username }}" href="{{ route('user.report', profile.id) }}"></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.permission(constant('Sakura\\Perms\\Manage::CAN_RESTRICT_USERS'), constant('Sakura\\Perms::MANAGE')) %}
|
{% if user.permission(constant('Sakura\\Perms\\Manage::CAN_RESTRICT_USERS'), constant('Sakura\\Perms::MANAGE')) %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'global/master.twig' %}
|
{% extends 'master.twig' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="stylised" style="text-align: center; margin: 2em auto;">I'll actually make reporting a thing, someday...</h1>
|
<h1 class="stylised" style="text-align: center; margin: 2em auto;">I'll actually make reporting a thing, someday...</h1>
|
||||||
|
|
50
routes.php
50
routes.php
|
@ -75,8 +75,8 @@ Router::group(['before' => 'maintenance'], function () {
|
||||||
'chat' => 'chat.redirect',
|
'chat' => 'chat.redirect',
|
||||||
//'irc' => 'chat.irc',
|
//'irc' => 'chat.irc',
|
||||||
'feedback' => 'forums.index',
|
'feedback' => 'forums.index',
|
||||||
//'mcp' => 'manage.index',
|
'mcp' => 'manage.index',
|
||||||
//'mcptest' => 'manage.index',
|
'mcptest' => 'manage.index',
|
||||||
//'report' => 'report.something',
|
//'report' => 'report.something',
|
||||||
//'osu' => 'eventual link to flashii team',
|
//'osu' => 'eventual link to flashii team',
|
||||||
//'filehost' => '???',
|
//'filehost' => '???',
|
||||||
|
@ -120,12 +120,12 @@ Router::group(['before' => 'maintenance'], function () {
|
||||||
Router::group(['prefix' => 'forum'], function () {
|
Router::group(['prefix' => 'forum'], function () {
|
||||||
// Post
|
// Post
|
||||||
Router::group(['prefix' => 'post'], function () {
|
Router::group(['prefix' => 'post'], function () {
|
||||||
Router::get('/{id:i}', 'ForumController@post', 'forums.post');
|
Router::get('/{id:i}', 'Forum.PostController@find', 'forums.post');
|
||||||
Router::group(['before' => 'loginCheck'], function () {
|
Router::group(['before' => 'loginCheck'], function () {
|
||||||
Router::get('/{id:i}/raw', 'ForumController@postRaw', 'forums.post.raw');
|
Router::get('/{id:i}/raw', 'Forum.PostController@raw', 'forums.post.raw');
|
||||||
Router::get('/{id:i}/delete', 'ForumController@deletePost', 'forums.post.delete');
|
Router::get('/{id:i}/delete', 'Forum.PostController@delete', 'forums.post.delete');
|
||||||
Router::post('/{id:i}/delete', 'ForumController@deletePost', 'forums.post.delete');
|
Router::post('/{id:i}/delete', 'Forum.PostController@delete', 'forums.post.delete');
|
||||||
Router::post('/{id:i}/edit', 'ForumController@editPost', 'forums.post.edit');
|
Router::post('/{id:i}/edit', 'Forum.PostController@edit', 'forums.post.edit');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -142,12 +142,12 @@ Router::group(['before' => 'maintenance'], function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Forum
|
// Forum
|
||||||
Router::get('/', 'ForumController@index', 'forums.index');
|
Router::get('/', 'Forum.ForumController@index', 'forums.index');
|
||||||
Router::get('/{id:i}', 'ForumController@forum', 'forums.forum');
|
Router::get('/{id:i}', 'Forum.ForumController@forum', 'forums.forum');
|
||||||
Router::group(['before' => 'loginCheck'], function () {
|
Router::group(['before' => 'loginCheck'], function () {
|
||||||
Router::get('/{id:i}/mark', 'ForumController@markForumRead', 'forums.mark');
|
Router::get('/{id:i}/mark', 'Forum.ForumController@markRead', 'forums.mark');
|
||||||
Router::get('/{id:i}/new', 'ForumController@createTopic', 'forums.new');
|
Router::get('/{id:i}/new', 'Forum.TopicController@create', 'forums.new');
|
||||||
Router::post('/{id:i}/new', 'ForumController@createTopic', 'forums.new');
|
Router::post('/{id:i}/new', 'Forum.TopicController@create', 'forums.new');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -308,16 +308,26 @@ Router::group(['before' => 'maintenance'], function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
Router::group(['prefix' => 'manage', 'before' => 'loginCheck'], function () {
|
||||||
|
Router::get('/', function () {
|
||||||
|
$route = Router::route('manage.overview');
|
||||||
|
return header("Location: {$route}");
|
||||||
|
}, 'manage.index');
|
||||||
|
|
||||||
|
// Overview section
|
||||||
|
Router::group(['prefix' => 'overview'], function () {
|
||||||
|
Router::get('/', function () {
|
||||||
|
$route = Router::route('manage.overview.index');
|
||||||
|
return header("Location: {$route}");
|
||||||
|
}, 'manage.overview');
|
||||||
|
|
||||||
|
Router::get('/index', 'Manage.OverviewController@index', 'manage.overview.index');
|
||||||
|
Router::get('/data', 'Manage.OverviewController@data', 'manage.overview.data');
|
||||||
|
});
|
||||||
|
});
|
||||||
// Management
|
// Management
|
||||||
/*
|
/*
|
||||||
* General
|
|
||||||
* - Dashboard
|
|
||||||
* - Info pages (possibly deprecate with wiki)
|
|
||||||
* Configuration
|
|
||||||
* - General
|
|
||||||
* - Files
|
|
||||||
* - User
|
|
||||||
* - Mail
|
|
||||||
* Forums
|
* Forums
|
||||||
* - Manage
|
* - Manage
|
||||||
* - Settings
|
* - Settings
|
||||||
|
|
Reference in a new issue