it's happening

This commit is contained in:
flash 2016-07-30 15:48:09 +02:00
parent 781a93326c
commit 3f2a71c023
49 changed files with 870 additions and 1499 deletions

View file

@ -10,6 +10,18 @@
I will include a full list of required extensions later.
## Development setup
Copy config.example.ini, set everything up to your liking (database is most important). I'd also recommend setting `show_errors` to `true` for development. Then run the following commands in the root.
```
php mahou database-install
php mahou database-migrate
php mahou setup
```
After that you can either use `php mahou serve` to use the built in development server or serve the public folder through your webserver of choice.
## Contributing
Right now I'm not accepting big PRs because of a set of big things not being fully implemented yet, bug fix PRs are more than welcome though!

View file

@ -33,14 +33,6 @@ class ActiveUser
&& !$user->permission(Site::DEACTIVATED)) {
// Assign the user object
self::$user = $user;
// Update last online
DB::table('users')
->where('user_id', self::$user->id)
->update([
'user_last_online' => time(),
'last_ip' => Net::pton(Net::ip()),
]);
} else {
self::$user = User::construct(0);
}

View file

@ -8,6 +8,8 @@
namespace Sakura\Console\Command;
use CLIFramework\Command;
use Illuminate\Database\Migrations\Migrator;
use Illuminate\Filesystem\Filesystem;
use Sakura\DB;
class DatabaseInstallCommand extends Command
@ -20,6 +22,13 @@ class DatabaseInstallCommand extends Command
public function execute()
{
$repository = DB::getMigrationRepository();
$migrator = new Migrator($repository, $repository->getConnectionResolver(), new Filesystem);
if ($migrator->repositoryExists()) {
$this->getLogger()->writeln("The migration repository already exists!");
return;
}
$repository->createRepository();
$this->getLogger()->writeln("Created the migration repository!");
}

View file

@ -34,7 +34,7 @@ class DatabaseMigrateCommand extends Command
$migrator->run(ROOT . self::MIGRATIONS);
foreach ($migrator->getNotes() as $note) {
$this->getLogger()->writeln($note);
$this->getLogger()->writeln(strip_tags($note));
}
}
}

View file

@ -0,0 +1,38 @@
<?php
/**
* Holds the migration reset command controller.
*
* @package Sakura
*/
namespace Sakura\Console\Command;
use CLIFramework\Command;
use Illuminate\Database\Migrations\Migrator;
use Illuminate\Filesystem\Filesystem;
use Sakura\DB;
class DatabaseResetCommand extends Command
{
public function brief()
{
return 'Rollback all database migrations';
}
public function execute()
{
$repository = DB::getMigrationRepository();
$migrator = new Migrator($repository, $repository->getConnectionResolver(), new Filesystem);
if (!$migrator->repositoryExists()) {
$this->getLogger()->writeln("The migration repository doesn't exist!");
return;
}
$migrator->reset();
foreach ($migrator->getNotes() as $note) {
$this->getLogger()->writeln(strip_tags($note));
}
}
}

View file

@ -0,0 +1,33 @@
<?php
/**
* Holds the migration rollback command controller.
*
* @package Sakura
*/
namespace Sakura\Console\Command;
use CLIFramework\Command;
use Illuminate\Database\Migrations\Migrator;
use Illuminate\Filesystem\Filesystem;
use Sakura\DB;
class DatabaseRollbackCommand extends Command
{
public function brief()
{
return 'Rollback the last database migration';
}
public function execute()
{
$repository = DB::getMigrationRepository();
$migrator = new Migrator($repository, $repository->getConnectionResolver(), new Filesystem);
$migrator->rollback();
foreach ($migrator->getNotes() as $note) {
$this->getLogger()->writeln(strip_tags($note));
}
}
}

View file

@ -0,0 +1,50 @@
<?php
/**
* Holds the migration status command controller.
*
* @package Sakura
*/
namespace Sakura\Console\Command;
use CLIFramework\Command;
use CLIFramework\Component\Table\Table;
use Illuminate\Database\Migrations\Migrator;
use Illuminate\Filesystem\Filesystem;
use Sakura\DB;
class DatabaseStatusCommand extends Command
{
const MIGRATIONS = "database/";
public function brief()
{
return 'Show the status of each migration';
}
public function execute()
{
$repository = DB::getMigrationRepository();
$migrator = new Migrator($repository, $repository->getConnectionResolver(), new Filesystem);
if (!$migrator->repositoryExists()) {
$this->getLogger()->writeln("No migrations found!");
return;
}
$ran = $repository->getRan();
$migrations = new Table;
$migrations->setHeaders([
'Ran?',
'Migration',
]);
foreach ($migrator->getMigrationFiles(ROOT . self::MIGRATIONS) as $migration) {
$migrations->addRow([in_array($migration, $ran) ? 'Y' : 'N', $migration]);
}
$this->getLogger()->write($migrations->render());
}
}

View file

@ -23,6 +23,8 @@ class ServeCommand extends Command
$php_dir = PHP_BINDIR;
$host = config('dev.host');
$this->getLogger()->writeln("Starting Sakura development server on {$host}.");
exec("{$php_dir}/php -S {$host} -t {$document_root} {$router_proxy}");
}
}

View file

@ -0,0 +1,269 @@
<?php
/**
* Holds the setup command controller.
*
* @package Sakura
*/
namespace Sakura\Console\Command;
use CLIFramework\Command;
use Sakura\DB;
use Sakura\Net;
use Sakura\User;
class SetupCommand extends Command
{
public function brief()
{
return 'Adds the required data to the tables, only needed once after the initial migration.';
}
public function execute()
{
// Check if the users table has user with id 1
$userCheck = DB::table('users')->where('user_id', 1)->count();
// If positive, stop
if ($userCheck > 0) {
$this->getLogger()->writeln("It appears that you've already done the setup already!");
$this->getLogger()->writeln("If this isn't the case, make sure your tables are empty.");
return;
}
// Rank data (uses column names)
$ranks = [
[
'rank_hierarchy' => 0,
'rank_name' => 'Inactive',
'rank_hidden' => 1,
'rank_colour' => '#555',
'rank_description' => 'Users that are yet to be activated or have deactivated their account.',
'rank_title' => 'Inactive',
],
[
'rank_hierarchy' => 1,
'rank_name' => 'Normal user',
'rank_multiple' => 's',
'rank_description' => 'Regular users with regular permissions.',
'rank_title' => 'Member',
],
[
'rank_hierarchy' => 3,
'rank_name' => 'Moderator',
'rank_multiple' => 's',
'rank_colour' => '#fa3703',
'rank_description' => 'Users with special permissions to keep the community at peace.',
'rank_title' => 'Moderator',
],
[
'rank_hierarchy' => 4,
'rank_name' => 'Administrator',
'rank_multiple' => 's',
'rank_colour' => '#824ca0',
'rank_description' => 'Users that manage the and everything around that.',
'rank_title' => 'Administrator',
],
[
'rank_hierarchy' => 1,
'rank_name' => 'Bot',
'rank_multiple' => 's',
'rank_hidden' => 1,
'rank_colour' => '#9e8da7',
'rank_description' => 'Reserved accounts for services.',
'rank_title' => 'Bot',
],
[
'rank_hierarchy' => 2,
'rank_name' => 'Premium',
'rank_colour' => '#ee9400',
'rank_description' => 'Users that purchased premium to help us keep the site and its service alive.',
'rank_title' => 'Premium',
],
[
'rank_hierarchy' => 1,
'rank_name' => 'Alumni',
'rank_colour' => '#ff69b4',
'rank_description' => 'Users who made big contributions to the site but have since moved on.',
'rank_title' => 'Alumni',
],
[
'rank_hierarchy' => 0,
'rank_name' => 'Banned',
'rank_colour' => '#666',
'rank_description' => 'Banned users.',
'rank_title' => 'Banned',
],
];
// Insert all the ranks into the database
foreach ($ranks as $rank) {
DB::table('ranks')->insert($rank);
}
// Permission data (alumni doesn't have special privs)
$permissions = [
[
'rank_id' => config('rank.inactive'),
'permissions_site' => '00000000000000000000000000000001',
'permissions_manage' => '00',
],
[
'rank_id' => config('rank.regular'),
'permissions_site' => '11110000111111111100111101101100',
'permissions_manage' => '00',
],
[
'rank_id' => config('rank.mod'),
'permissions_site' => '11110001111111111111111111111100',
'permissions_manage' => '11',
],
[
'rank_id' => config('rank.admin'),
'permissions_site' => '11110111111111111111111111111100',
'permissions_manage' => '11',
],
[
'rank_id' => config('rank.bot'),
'permissions_site' => '11110000111111111100111101101100',
'permissions_manage' => '00',
],
[
'rank_id' => config('rank.premium'),
'permissions_site' => '11110001111111111111111111111100',
'permissions_manage' => '00',
],
[
'rank_id' => config('rank.banned'),
'permissions_site' => '11110000000011010100101000100010',
'permissions_manage' => '00',
],
];
// Insert all the permission strings into the database
foreach ($permissions as $perm) {
DB::table('permissions')->insert($perm);
}
// Forum data
$forums = [
[
'forum_order' => 1,
'forum_name' => 'Your first category',
'forum_type' => 1,
],
[
'forum_order' => 1,
'forum_name' => 'Your first playpen',
'forum_desc' => 'Description of your first forum.',
'forum_category' => 1,
'forum_icon' => 'fa-smile-o',
],
[
'forum_order' => 2,
'forum_name' => 'Private',
'forum_type' => 1,
],
[
'forum_order' => 1,
'forum_name' => 'Trash',
'forum_desc' => 'Where the deleted topics go before being permanently removed.',
'forum_category' => 3,
'forum_icon' => 'fa-trash',
],
];
// Insert all the forums into the database
foreach ($forums as $forum) {
DB::table('forums')->insert($forum);
}
// Forum permission data
$forum_perms = [
[
'forum_id' => 1,
'rank_id' => config('rank.inactive'),
'forum_perms' => '00000000001',
],
[
'forum_id' => 3,
'rank_id' => config('rank.inactive'),
'forum_perms' => '00000000000',
],
[
'forum_id' => 1,
'rank_id' => config('rank.regular'),
'forum_perms' => '00000011111',
],
[
'forum_id' => 3,
'rank_id' => config('rank.regular'),
'forum_perms' => '00000000000',
],
[
'forum_id' => 1,
'rank_id' => config('rank.mod'),
'forum_perms' => '11111111111',
],
[
'forum_id' => 3,
'rank_id' => config('rank.mod'),
'forum_perms' => '00000111111',
],
[
'forum_id' => 1,
'rank_id' => config('rank.admin'),
'forum_perms' => '11111111111',
],
[
'forum_id' => 3,
'rank_id' => config('rank.admin'),
'forum_perms' => '11111111111',
],
[
'forum_id' => 1,
'rank_id' => config('rank.banned'),
'forum_perms' => '00000000001',
],
[
'forum_id' => 3,
'rank_id' => config('rank.banned'),
'forum_perms' => '00000000000',
],
];
// Insert all the forum permissions into the database
foreach ($forum_perms as $fperm) {
DB::table('forum_permissions')->insert($fperm);
}
// Bot user
$botUserId = DB::table('users')->insertGetId([
'username' => 'Railgun',
'username_clean' => 'railgun',
'password' => password_hash('railgun', PASSWORD_BCRYPT),
'email' => config('mail.contact_address'),
'register_ip' => Net::pton('::1'),
'last_ip' => Net::pton('::1'),
'user_registered' => time(),
'user_last_online' => 0,
'user_country' => 'JP',
]);
// Create the actual user object
$botUser = User::construct($botUserId);
// Add ranks to the user
$botUser->addRanks([
config('rank.regular'),
config('rank.bot'),
config('rank.admin'),
]);
// Set the main rank to bot
$botUser->setMainRank(config('rank.bot'));
$this->getLogger()->writeln("Success! You can now start a development server use the serve command for mahou.");
$this->getLogger()->writeln("The default username and password are both railgun.");
}
}

View file

@ -15,6 +15,25 @@ namespace Sakura\Controllers;
*/
class Controller
{
// Middleware to execute upon creating this class
protected $middleware = [
'UpdateLastOnline',
];
// Used to except middleware in controllers that extend this one
protected $exceptMiddleware = [];
public function __construct()
{
// filter excepted middlewares
$middlewares = array_diff($this->middleware, $this->exceptMiddleware);
foreach ($middlewares as $middleware) {
$className = "Sakura\\Middleware\\{$middleware}";
(new $className)->run();
}
}
public function json($object)
{
header('Content-Type: application/json; charset=utf-8');

View file

@ -12,7 +12,7 @@ use Sakura\Config;
use Sakura\DB;
use Sakura\Forum\Forum;
use Sakura\Forum\Post;
use Sakura\Forum\Thread;
use Sakura\Forum\Topic;
use Sakura\Perms;
use Sakura\Perms\Forum as ForumPerms;
use Sakura\Router;
@ -34,21 +34,22 @@ class ForumController extends Controller
*/
public function index()
{
// Get the most active threads
$activeThreadsIds = DB::table('posts')
// 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']);
$activeThreads = [];
$activeTopics = [];
while (list($_n, $_t) = each($activeThreadsIds)) {
// Create the thread object
$thread = new Thread($_t->topic_id);
// 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($thread->forum);
$forum = new Forum($topic->forum);
// Check if we have permission to view it
if (!$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
@ -60,12 +61,12 @@ class ForumController extends Controller
->get(['topic_id']);
if ($fetch) {
$activeThreadsIds[] = $fetch[0];
$activeTopicsIds[] = $fetch[0];
}
continue;
}
$activeThreads[$thread->id] = $thread;
$activeTopics[$topic->id] = $topic;
}
// Get the latest posts
@ -115,7 +116,7 @@ class ForumController extends Controller
// Create the forum object
$forum = new Forum;
Template::vars(compact('forum', 'activeThreads', 'latestPosts', 'activePoster'));
Template::vars(compact('forum', 'activeTopics', 'latestPosts', 'activePoster'));
// Return the compiled page
return Template::render('forum/index');
@ -245,7 +246,7 @@ class ForumController extends Controller
// Set render data
Template::vars([
'page' => [
'message' => 'All threads have been marked as read.',
'message' => 'All topics have been marked as read.',
'redirect' => Router::route('forums.forum', $forum->id),
],
]);
@ -255,24 +256,24 @@ class ForumController extends Controller
}
/**
* View a thread.
* View a topic.
*
* @return string
*/
public function thread($id = 0)
public function topic($id = 0)
{
// Attempt to get the thread
$thread = new Thread($id);
// Attempt to get the topic
$topic = new Topic($id);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Check if the forum exists
if ($thread->id == 0 || !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
if ($topic->id == 0 || !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
// Set render data
Template::vars([
'page' => [
'message' => 'This thread 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' => Router::route('forums.index'),
],
]);
@ -282,41 +283,41 @@ class ForumController extends Controller
}
// Update the tracking status
$thread->trackUpdate(ActiveUser::$user->id);
$topic->trackUpdate(ActiveUser::$user->id);
// Update views
$thread->viewsUpdate();
$topic->viewsUpdate();
// Set parse variables
Template::vars(compact('forum', 'thread'));
Template::vars(compact('forum', 'topic'));
// Print page contents
return Template::render('forum/thread');
return Template::render('forum/topic');
}
/**
* Moderate a thread.
* Moderate a topic.
*
* @return string
*/
public function threadModerate($id = 0)
public function topicModerate($id = 0)
{
// Attempt to get the thread
$thread = new Thread($id);
// Attempt to get the topic
$topic = new Topic($id);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Default stuff
$message = 'Unknown moderation action.';
$redirect = Router::route('forums.thread', $thread->id);
$redirect = Router::route('forums.topic', $topic->id);
// Check if the forum exists
if ($thread->id == 0
if ($topic->id == 0
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)
|| !isset($_POST['session'])
|| $_POST['session'] != session_id()) {
$message = 'This thread 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 = Router::route('forums.index');
} else {
// Take the action
@ -332,14 +333,14 @@ class ForumController extends Controller
}
// Update the type
$thread->type = $thread->type !== 1 ? 1 : 0;
$topic->type = $topic->type !== 1 ? 1 : 0;
$thread->update();
$topic->update();
// Add page variable stuff
$message = $thread->type
? 'Changed the thread to sticky!'
: 'Reverted the thread back to normal!';
$message = $topic->type
? 'Changed the topic to sticky!'
: 'Reverted the topic back to normal!';
break;
case 'announce':
@ -350,14 +351,14 @@ class ForumController extends Controller
}
// Update the type
$thread->type = $thread->type !== 2 ? 2 : 0;
$topic->type = $topic->type !== 2 ? 2 : 0;
$thread->update();
$topic->update();
// Add page variable stuff
$message = $thread->type
? 'Changed the thread to into an announcement!'
: 'Reverted the thread back to normal!';
$message = $topic->type
? 'Changed the topic to into an announcement!'
: 'Reverted the topic back to normal!';
break;
case 'lock':
@ -368,12 +369,12 @@ class ForumController extends Controller
}
// Update the status
$thread->status = $thread->status !== 1 ? 1 : 0;
$topic->status = $topic->status !== 1 ? 1 : 0;
$thread->update();
$topic->update();
// Add page variable stuff
$message = ($thread->status ? 'Locked' : 'Unlocked') . ' the thread!';
$message = ($topic->status ? 'Locked' : 'Unlocked') . ' the topic!';
break;
case 'delete':
@ -381,18 +382,18 @@ class ForumController extends Controller
$trash = config('forum.trash');
// Check if we're operating from the trash
if ($thread->forum == $trash) {
if ($topic->forum == $trash) {
// Check permission
if (!$forum->permission(ForumPerms::DELETE_ANY, ActiveUser::$user->id)) {
$message = "You're not allowed to do this!";
break;
}
// Delete the thread
$thread->delete();
// Delete the topic
$topic->delete();
// Set message
$message = "Deleted the thread!";
$message = "Deleted the topic!";
$redirect = Router::route('forums.forum', $trash);
} else {
// Check permission
@ -401,23 +402,23 @@ class ForumController extends Controller
break;
}
// Move the thread
$thread->move($trash);
// Move the topic
$topic->move($trash);
// Trashed!
$message = "Moved the thread to the trash!";
$message = "Moved the topic to the trash!";
}
break;
case 'restore':
// Check if this thread has record of being in a previous forum
if ($thread->oldForum) {
// Move the thread back
$thread->move($thread->oldForum, false);
// Check if this topic has record of being in a previous forum
if ($topic->oldForum) {
// Move the topic back
$topic->move($topic->oldForum, false);
$message = "Moved the thread back to it's old location!";
$message = "Moved the topic back to it's old location!";
} else {
$message = "This thread has never been moved!";
$message = "This topic has never been moved!";
}
break;
}
@ -431,7 +432,7 @@ class ForumController extends Controller
}
/**
* Redirect to the position of a post in a thread.
* Redirect to the position of a post in a topic.
*
* @return mixed
*/
@ -441,14 +442,14 @@ class ForumController extends Controller
$post = new Post($id);
// And attempt to get the forum
$thread = new Thread($post->thread);
$topic = new Topic($post->topic);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Check if the forum exists
if ($post->id == 0
|| $thread->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');
@ -459,11 +460,11 @@ class ForumController extends Controller
}
// Generate link
$threadLink = Router::route('forums.thread', $thread->id);
$topicLink = Router::route('forums.topic', $topic->id);
// Get all post ids from the database
$postIds = DB::table('posts')
->where('topic_id', $thread->id)
->where('topic_id', $topic->id)
->get(['post_id']);
$postIds = array_column($postIds, 'post_id');
@ -472,10 +473,10 @@ class ForumController extends Controller
// Only append the page variable if it's more than 1
if ($postAt > 1) {
$threadLink .= "?page={$postAt}";
$topicLink .= "?page={$postAt}";
}
return header("Location: {$threadLink}#p{$post->id}");
return header("Location: {$topicLink}#p{$post->id}");
}
/**
@ -489,14 +490,14 @@ class ForumController extends Controller
$post = new Post($id);
// And attempt to get the forum
$thread = new Thread($post->thread);
$topic = new Topic($post->topic);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Check if the forum exists
if ($post->id == 0
|| $thread->id == 0
|| $topic->id == 0
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
return "";
}
@ -505,22 +506,22 @@ class ForumController extends Controller
}
/**
* Reply to a thread.
* Reply to a topic.
*
* @return string
*/
public function threadReply($id = 0)
public function topicReply($id = 0)
{
$text = isset($_POST['text']) ? $_POST['text'] : null;
// Attempt to get the forum
$thread = new Thread($id);
$topic = new Topic($id);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Check if the thread exists
if ($thread->id == 0
// Check if the topic exists
if ($topic->id == 0
|| $forum->type !== 0
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id)) {
$message = "This post doesn't exist or you don't have access to it!";
@ -531,14 +532,14 @@ class ForumController extends Controller
return Template::render('global/information');
}
// Check if the thread exists
// Check if the topic exists
if (!$forum->permission(ForumPerms::REPLY, ActiveUser::$user->id)
|| (
$thread->status === 1
$topic->status === 1
&& !$forum->permission(ForumPerms::LOCK, ActiveUser::$user->id)
)) {
$message = "You are not allowed to post in this thread!";
$redirect = Router::route('forums.thread', $thread->id);
$message = "You are not allowed to post in this topic!";
$redirect = Router::route('forums.topic', $topic->id);
Template::vars(compact('message', 'redirect'));
@ -555,7 +556,7 @@ class ForumController extends Controller
// Check requirments
if ($tooShort
|| $tooLong) {
$route = Router::route('forums.thread', $thread->id);
$route = Router::route('forums.topic', $topic->id);
$message = "Your post is " . (
$tooShort
@ -570,19 +571,19 @@ class ForumController extends Controller
$_SESSION['replyText'] = [];
}
$_SESSION['replyText']["t{$thread->id}"] = $text;
$_SESSION['replyText']["t{$topic->id}"] = $text;
return Template::render('global/information');
}
unset($_SESSION['replyText']["t{$thread->id}"]);
unset($_SESSION['replyText']["t{$topic->id}"]);
// Create the post
$post = Post::create(
"Re: {$thread->title}",
"Re: {$topic->title}",
$text,
ActiveUser::$user,
$thread->id,
$topic->id,
$forum->id
);
@ -594,11 +595,11 @@ class ForumController extends Controller
}
/**
* Create a thread.
* Create a topic.
*
* @return string
*/
public function createThread($id = 0)
public function createTopic($id = 0)
{
$title = isset($_POST['title']) ? $_POST['title'] : null;
$text = isset($_POST['text']) ? $_POST['text'] : null;
@ -686,7 +687,7 @@ class ForumController extends Controller
Template::vars(compact('forum'));
return Template::render('forum/thread');
return Template::render('forum/topic');
}
/**
@ -702,15 +703,15 @@ class ForumController extends Controller
// Attempt to get the post
$post = new Post($id);
// Attempt to get the thread
$thread = new Thread($post->thread);
// Attempt to get the topic
$topic = new Topic($post->topic);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Check permissions
$noAccess = $post->id == 0
|| $thread->id == 0
|| $topic->id == 0
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id);
$noEdit = (
@ -718,14 +719,14 @@ class ForumController extends Controller
? !ActiveUser::$user->permission(ForumPerms::EDIT_OWN, Perms::FORUM)
: !$forum->permission(ForumPerms::EDIT_ANY, ActiveUser::$user->id)
) || (
$thread->status === 1
$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 thread!";
$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!";
@ -747,10 +748,10 @@ class ForumController extends Controller
// Checks
$titleTooShort = $title !== null
&& $post->id === $thread->firstPost()->id
&& $post->id === $topic->firstPost()->id
&& $titleLength < $titleMin;
$titleTooLong = $title !== null
&& $post->id === $thread->firstPost()->id
&& $post->id === $topic->firstPost()->id
&& $titleLength > $titleMax;
$textTooShort = $textLength < $textMin;
$textTooLong = $textLength > $textMax;
@ -787,11 +788,11 @@ class ForumController extends Controller
unset($_SESSION['replyText']["t{$forum->id}"]);
if ($post->id !== $thread->firstPost()->id || $title === null) {
$title = "Re: {$thread->title}";
if ($post->id !== $topic->firstPost()->id || $title === null) {
$title = "Re: {$topic->title}";
} else {
$thread->title = $title;
$thread->update();
$topic->title = $title;
$topic->update();
}
// Create the post
@ -824,14 +825,14 @@ class ForumController extends Controller
$post = new Post($id);
// And attempt to get the forum
$thread = new Thread($post->thread);
$topic = new Topic($post->topic);
// And attempt to get the forum
$forum = new Forum($thread->forum);
$forum = new Forum($topic->forum);
// Check permissions
$noAccess = $post->id == 0
|| $thread->id == 0
|| $topic->id == 0
|| !$forum->permission(ForumPerms::VIEW, ActiveUser::$user->id);
$noDelete = (
@ -839,14 +840,14 @@ class ForumController extends Controller
? !ActiveUser::$user->permission(ForumPerms::DELETE_OWN, Perms::FORUM)
: !$forum->permission(ForumPerms::DELETE_ANY, ActiveUser::$user->id)
) || (
$thread->status === 1
$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 thread!";
$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!";
@ -863,17 +864,17 @@ class ForumController extends Controller
// Set message
$message = "Deleted the post!";
// Check if the thread only has 1 post
if ($thread->replyCount() === 1) {
// Delete the entire thread
$thread->delete();
// 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.thread', $thread->id);
$redirect = Router::route('forums.topic', $topic->id);
}
Template::vars(compact('message', 'redirect'));

View file

@ -33,6 +33,8 @@ class PremiumController extends Controller
*/
public function __construct()
{
parent::__construct();
Payments::init();
}

View file

@ -66,14 +66,10 @@ class AppearanceController extends Controller
$confp = $mode === 'header' ? 'cover' : $mode;
// Check dimensions
$minWidth = config("file.{$confp}.min_width");
$minHeight = config("file.{$confp}.min_height");
$maxWidth = config("file.{$confp}.max_width");
$maxHeight = config("file.{$confp}.max_height");
if ($meta[0] < $minWidth
|| $meta[1] < $minHeight
|| $meta[0] > $maxWidth
if ($meta[0] > $maxWidth
|| $meta[1] > $maxHeight) {
return "Your image has to be at least {$minWidth}x{$minHeight}"
. " and not bigger than {$maxWidth}x{$maxHeight}, yours was {$meta[0]}x{$meta[1]}!";

View file

@ -95,11 +95,11 @@ class Forum
private $forumsCache = [];
/**
* Cached instances of the threads in this forum.
* Cached instances of the topics in this forum.
*
* @var array
*/
private $threadsCache = [];
private $topicsCache = [];
/**
* The permission container.
@ -197,36 +197,36 @@ class Forum
}
/**
* Gets the threads in this forum.
* Gets the topics in this forum.
*
* @return array Array containing all threads.
* @return array Array containing all topics.
*/
public function threads()
public function topics()
{
// Check if threadsCache is populated
if (!count($this->threadsCache)) {
// Check if topicsCache is populated
if (!count($this->topicsCache)) {
// Get all rows with the forum id for this forum
$threadRows = DB::table('topics')
$topicRows = DB::table('topics')
->where('forum_id', $this->id)
->orderBy('topic_type', 'desc')
->orderBy('topic_last_reply', 'desc')
->get(['topic_id']);
// Create a storage array
$threads = [];
$topics = [];
// Create new objects for each thread
foreach ($threadRows as $thread) {
$threads[$thread->topic_id] = new Thread($thread->topic_id);
// Create new objects for each topic
foreach ($topicRows as $topic) {
$topics[$topic->topic_id] = new Topic($topic->topic_id);
}
$this->threadsCache = $threads;
$this->topicsCache = $topics;
} else {
$threads = $this->threadsCache;
$topics = $this->topicsCache;
}
// Return the thread objects
return $threads;
// Return the topic objects
return $topics;
}
/**
@ -288,11 +288,11 @@ class Forum
}
/**
* Counts the amount of threads in this forum.
* Counts the amount of topics in this forum.
*
* @return int Number of threads in this forum.
* @return int Number of topics in this forum.
*/
public function threadCount()
public function topicCount()
{
return DB::table('topics')
->where('forum_id', $this->id)
@ -332,9 +332,9 @@ class Forum
}
}
// Check each thread
foreach ($this->threads() as $thread) {
if ($thread->unread($user)) {
// Check each topic
foreach ($this->topics() as $topic) {
if ($topic->unread($user)) {
return true;
}
}
@ -344,7 +344,7 @@ class Forum
}
/**
* Update the read status of all threads in this forum at once.
* Update the read status of all topics in this forum at once.
*
* @param int $user The id of the user in question.
*/
@ -356,10 +356,10 @@ class Forum
$forum->trackUpdateAll($user);
}
// Iterate over every thread
foreach ($this->threads() as $thread) {
// Update every thread
$thread->trackUpdate($user);
// Iterate over every topic
foreach ($this->topics() as $topic) {
// Update every topic
$topic->trackUpdate($user);
}
}
}

View file

@ -29,11 +29,11 @@ class Post
public $id = 0;
/**
* The id of the thread this post is a part of.
* The id of the topic this post is a part of.
*
* @var int
*/
public $thread = 0;
public $topic = 0;
/**
* The id of the forum this post is a part of.
@ -121,7 +121,7 @@ class Post
if ($postRow) {
$postRow = $postRow[0];
$this->id = $postRow->post_id;
$this->thread = $postRow->topic_id;
$this->topic = $postRow->topic_id;
$this->forum = $postRow->forum_id;
$this->poster = User::construct($postRow->poster_id);
$this->time = $postRow->post_time;
@ -147,33 +147,33 @@ class Post
/**
* Creating a new post.
*
* @param string $subject The subject of the thread.
* @param string $subject The subject of the topic.
* @param string $text The raw contents of the post.
* @param User $poster The User object of the poster.
* @param int $thread The ID of the thread this post is a reply to.
* @param int $topic The ID of the topic this post is a reply to.
* @param mixed $forum The forum this post is a reply in.
*
* @return null|self Either null, indicating a failure, or the Post object.
*/
public static function create($subject, $text, User $poster, $thread = 0, $forum = 0)
public static function create($subject, $text, User $poster, $topic = 0, $forum = 0)
{
// If no thread is specified create a new one
if ($thread) {
$thread = new Thread($thread);
// If no topic is specified create a new one
if ($topic) {
$topic = new Topic($topic);
} else {
$thread = Thread::create($forum, $subject);
$topic = Topic::create($forum, $subject);
}
// Stop if the thread ID is 0
if ($thread->id == 0) {
// Stop if the topic ID is 0
if ($topic->id == 0) {
return null;
}
// Insert the post
$id = DB::table('posts')
->insertGetId([
'topic_id' => $thread->id,
'forum_id' => $thread->forum,
'topic_id' => $topic->id,
'forum_id' => $topic->forum,
'poster_id' => $poster->id,
'poster_ip' => Net::pton(Net::ip()),
'post_time' => time(),
@ -182,7 +182,7 @@ class Post
]);
// Update the last post date
$thread->lastUpdate();
$topic->lastUpdate();
// Return the object
return new Post($id);
@ -195,15 +195,15 @@ class Post
*/
public function update()
{
// Create a thread object
$thread = new Thread($this->thread);
// Create a topic object
$topic = new Topic($this->topic);
// Update the post
DB::table('posts')
->where('post_id', $this->id)
->update([
'topic_id' => $thread->id,
'forum_id' => $thread->forum,
'topic_id' => $topic->id,
'forum_id' => $topic->forum,
'poster_id' => $this->poster->id,
'poster_ip' => Net::pton(Net::ip()),
'post_time' => $this->time,
@ -242,7 +242,7 @@ class Post
// Attempt to get track row from the database
$track = DB::table('topics_track')
->where('user_id', $user)
->where('topic_id', $this->thread)
->where('topic_id', $this->topic)
->where('mark_time', '>', $this->time)
->count();

View file

@ -1,6 +1,6 @@
<?php
/**
* Holds the thread object class.
* Holds the topic object class.
*
* @package Sakura
*/
@ -10,22 +10,22 @@ namespace Sakura\Forum;
use Sakura\DB;
/**
* Used to serve, create and update threads.
* Used to serve, create and update topics.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class Thread
class Topic
{
/**
* The ID of this thread.
* The ID of this topic.
*
* @var int
*/
public $id = 0;
/**
* The ID of the forum this thread is a part of.
* The ID of the forum this topic is a part of.
*
* @var int
*/
@ -39,35 +39,35 @@ class Thread
public $hidden = false;
/**
* The title of the thread.
* The title of the topic.
*
* @var string
*/
public $title = "";
/**
* The UNIX timestamp of when this thread was created.
* The UNIX timestamp of when this topic was created.
*
* @var int
*/
public $time = 0;
/**
* The UNIX timestamp of when this thread should be autolocked (currently unused).
* The UNIX timestamp of when this topic should be autolocked (currently unused).
*
* @var int
*/
public $timeLimit = 0;
/**
* The amount of times this thread has been viewed.
* The amount of times this topic has been viewed.
*
* @var int
*/
public $views = 0;
/**
* The status of this thread.
* The status of this topic.
* 0 - Unlocked
* 1 - Locked
*
@ -83,9 +83,9 @@ class Thread
public $statusChange = 0;
/**
* The thread type
* 0 - Normal thread
* 1 - Sticky thread
* The topic type
* 0 - Normal topic
* 1 - Sticky topic
* 2 - Announcement
*
* @var int
@ -93,7 +93,7 @@ class Thread
public $type = 0;
/**
* The ID of the forum this thread was a part of before the last move.
* The ID of the forum this topic was a part of before the last move.
*
* @var int
*/
@ -123,41 +123,41 @@ class Thread
/**
* Constructor.
*
* @param mixed $threadId ID of the thread that should be constructed.
* @param mixed $topicId ID of the topic that should be constructed.
*/
public function __construct($threadId)
public function __construct($topicId)
{
// Attempt to get the database row
$threadRow = DB::table('topics')
->where('topic_id', $threadId)
$topicRow = DB::table('topics')
->where('topic_id', $topicId)
->get();
// Assign data if a row was returned
if ($threadRow) {
$threadRow = $threadRow[0];
$this->id = $threadRow->topic_id;
$this->forum = $threadRow->forum_id;
$this->hidden = (bool) $threadRow->topic_hidden;
$this->title = $threadRow->topic_title;
$this->time = $threadRow->topic_time;
$this->timeLimit = $threadRow->topic_time_limit;
$this->views = $threadRow->topic_views;
$this->status = $threadRow->topic_status;
$this->statusChange = $threadRow->topic_status_change;
$this->type = $threadRow->topic_type;
$this->oldForum = $threadRow->topic_old_forum;
if ($topicRow) {
$topicRow = $topicRow[0];
$this->id = $topicRow->topic_id;
$this->forum = $topicRow->forum_id;
$this->hidden = (bool) $topicRow->topic_hidden;
$this->title = $topicRow->topic_title;
$this->time = $topicRow->topic_time;
$this->timeLimit = $topicRow->topic_time_limit;
$this->views = $topicRow->topic_views;
$this->status = $topicRow->topic_status;
$this->statusChange = $topicRow->topic_status_change;
$this->type = $topicRow->topic_type;
$this->oldForum = $topicRow->topic_old_forum;
}
}
/**
* Create a new thread.
* Create a new topic.
*
* @param mixed $forum ID of the forum this thread is part of.
* @param mixed $title Title of the thread.
* @param mixed $status Status of the thread.
* @param mixed $type Type of thread.
* @param mixed $forum ID of the forum this topic is part of.
* @param mixed $title Title of the topic.
* @param mixed $status Status of the topic.
* @param mixed $type Type of topic.
*
* @return self The new thread instance.
* @return self The new topic instance.
*/
public static function create($forum, $title, $status = 0, $type = 0)
{
@ -171,12 +171,12 @@ class Thread
'topic_type' => $type,
]);
// Return the thread object
return new Thread($id);
// Return the topic object
return new Topic($id);
}
/**
* Delete the current thread.
* Delete the current topic.
*/
public function delete()
{
@ -185,14 +185,14 @@ class Thread
->where('topic_id', $this->id)
->delete();
// Delete thread meta
// Delete topic meta
DB::table('topics')
->where('topic_id', $this->id)
->delete();
}
/**
* Move the thread.
* Move the topic.
*
* @param mixed $forum The new forum ID.
* @param mixed $setOld Remember the forum ID prior to the move for restoration.
@ -204,7 +204,7 @@ class Thread
->where('topic_id', $this->id)
->update(['forum_id' => $forum]);
// Update thread meta
// Update topic meta
DB::table('topics')
->where('topic_id', $this->id)
->update([
@ -214,9 +214,9 @@ class Thread
}
/**
* Update the thread data.
* Update the topic data.
*
* @return self The updated thread.
* @return self The updated topic.
*/
public function update()
{
@ -234,11 +234,11 @@ class Thread
]);
// Return new object
return new Thread($this->id);
return new Topic($this->id);
}
/**
* Get the replies to this thread.
* Get the replies to this topic.
*
* @return array Array containing Post instances.
*/
@ -246,7 +246,7 @@ class Thread
{
// Check if postsCache is something
if (!count($this->postsCache)) {
// Get all rows with the thread id
// Get all rows with the topic id
$postRows = DB::table('posts')
->where('topic_id', $this->id)
->get(['post_id']);
@ -329,7 +329,7 @@ class Thread
/**
* Get the amount of replies.
*
* @return int The number of replies to this thread.
* @return int The number of replies to this topic.
*/
public function replyCount()
{
@ -339,7 +339,7 @@ class Thread
}
/**
* Check if a user has read this thread before.
* Check if a user has read this topic before.
*
* @param mixed $user The id of the user in question.
*
@ -414,7 +414,7 @@ class Thread
}
/**
* Update the timestamp of when this thread was last replied to.
* Update the timestamp of when this topic was last replied to.
*/
public function lastUpdate()
{

View file

@ -0,0 +1,19 @@
<?php
/**
* Holds the middleware interface.
*
* @package Sakura
*/
namespace Sakura\Middleware;
/**
* Middleware interface.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
interface Middleware
{
public function run();
}

View file

@ -0,0 +1,26 @@
<?php
/**
* Holds the last online update middleware.
*
* @package Sakura
*/
namespace Sakura\Middleware;
use Sakura\ActiveUser;
/**
* Updates when the last online time of a user.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class UpdateLastOnline implements Middleware
{
public function run()
{
if (ActiveUser::$user->id !== 0) {
ActiveUser::$user->updateOnline();
}
}
}

View file

@ -26,7 +26,7 @@ class Forum
const REPLY = 2;
/**
* Can this user create threads in this forum?
* Can this user create topics in this forum?
*/
const CREATE_THREADS = 4;
@ -41,12 +41,12 @@ class Forum
const DELETE_OWN = 16;
/**
* Can this user change threads to the sticky type?
* Can this user change topics to the sticky type?
*/
const STICKY = 32;
/**
* Can this user change threads to the announcement type?
* Can this user change topics to the announcement type?
*/
const ANNOUNCEMENT = 64;
@ -61,12 +61,12 @@ class Forum
const DELETE_ANY = 256;
/**
* Can this user toggle the locked status on threads in this forum?
* Can this user toggle the locked status on topics in this forum?
*/
const LOCK = 512;
/**
* Can this user move threads to other forums from/to this forum?
* Can this user move topics to other forums from/to this forum?
*/
const MOVE = 1024;
}

View file

@ -86,7 +86,7 @@ class Rank
*
* @var array
*/
protected static $_rankCache = [];
protected static $rankCache = [];
/**
* Cached constructor.
@ -99,13 +99,13 @@ class Rank
public static function construct($rid, $forceRefresh = false)
{
// Check if a rank object isn't present in cache
if ($forceRefresh || !array_key_exists($rid, self::$_rankCache)) {
if ($forceRefresh || !array_key_exists($rid, self::$rankCache)) {
// If not create a new object and cache it
self::$_rankCache[$rid] = new Rank($rid);
self::$rankCache[$rid] = new Rank($rid);
}
// Return the cached object
return self::$_rankCache[$rid];
return self::$rankCache[$rid];
}
/**
@ -115,7 +115,6 @@ class Rank
*/
private function __construct($rankId)
{
// Get the rank database row
$rankRow = DB::table('ranks')
->where('rank_id', $rankId)

View file

@ -10,7 +10,6 @@ namespace Sakura;
use Twig_Environment;
use Twig_Extension_StringLoader;
use Twig_Loader_Filesystem;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
/**
@ -47,6 +46,19 @@ class Template
*/
const FILE_EXT = '.twig';
/**
* List of utility functions to add to templating
*
* @var array
*/
protected static $utility = [
'route',
'config',
'session_id',
'json_decode',
'byte_symbol',
];
/**
* Set the template name.
*
@ -66,16 +78,19 @@ class Template
*/
public static function init()
{
$views_dir = ROOT . 'resources/views/';
// Initialise Twig Filesystem Loader
$twigLoader = new Twig_Loader_Filesystem(ROOT . 'resources/views/' . self::$name);
$twigLoader = new Twig_Loader_Filesystem([$views_dir . self::$name, $views_dir . 'shared/']);
// Environment variable
$twigEnv = [];
// Enable caching
if (config("performance.template_cache")) {
$twigEnv['cache'] = ROOT . config("performance.cache_dir") . 'views';
}
$twigEnv = [
'cache' => config("performance.template_cache")
? realpath(ROOT . config("performance.cache_dir") . 'views')
: false,
'auto_reload' => true,
'debug' => config("dev.twig_debug"),
];
// And now actually initialise the templating engine
self::$engine = new Twig_Environment($twigLoader, $twigEnv);
@ -83,20 +98,10 @@ class Template
// Load String template loader
self::$engine->addExtension(new Twig_Extension_StringLoader());
// Add route function
self::$engine->addFunction(new Twig_SimpleFunction('route', 'route'));
// Add config function
self::$engine->addFunction(new Twig_SimpleFunction('config', 'config'));
// Method of getting the currently active session id
self::$engine->addFunction(new Twig_SimpleFunction('session_id', 'session_id'));
// json_decode filter (why doesn't this exist to begin with?)
self::$engine->addFilter(new Twig_SimpleFilter('json_decode', 'json_decode'));
// byte_symbol filter
self::$engine->addFilter(new Twig_SimpleFilter('byte_symbol', 'byte_symbol'));
// Add utility functions
foreach (self::$utility as $utility) {
self::$engine->addFunction(new Twig_SimpleFunction($utility, $utility));
}
}
/**

View file

@ -441,6 +441,22 @@ class User
return $this->lastOnline > (time() - 120);
}
/**
* Updates the last IP and online time of the user
*/
public function updateOnline()
{
$this->lastOnline = time();
$this->lastIp = Net::ip();
DB::table('users')
->where('user_id', $this->id)
->update([
'user_last_online' => $this->lastOnline,
'last_ip' => Net::pton($this->lastIp),
]);
}
/**
* Runs some checks to see if this user is activated.
*
@ -454,7 +470,7 @@ class User
/**
* Get a few forum statistics.
*
* @return array Post and thread counts.
* @return array Post and topic counts.
*/
public function forumStats()
{
@ -462,7 +478,7 @@ class User
->where('poster_id', $this->id)
->count();
$threads = DB::table('posts')
$topics = DB::table('posts')
->where('poster_id', $this->id)
->distinct()
->groupBy('topic_id')
@ -471,7 +487,7 @@ class User
return [
'posts' => $posts,
'topics' => $threads,
'topics' => $topics,
];
}

View file

@ -11,7 +11,7 @@
"php": ">=7.0.0",
"ext-curl": "*",
"ext-json": "*",
"twig/twig": "*",
"twig/twig": "~1.0",
"paypal/rest-api-sdk-php": "*",
"phroute/phroute": "^2.1",
"illuminate/database": "5.2.*",
@ -23,6 +23,9 @@
"illuminate/filesystem": "^5.2"
},
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"Sakura\\": "app/"
},

14
composer.lock generated
View file

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "1f0887a5e8183bc1ca24e7c50e054ba1",
"content-hash": "271f4f1bcfb9fdc9446336132938b762",
"hash": "f946afcc0c6da415e19157b0b4abe022",
"content-hash": "e8af98e57e4ec54d9e23cf833b2b733a",
"packages": [
{
"name": "corneltek/class-template",
@ -1513,16 +1513,16 @@
},
{
"name": "symfony/translation",
"version": "v3.1.2",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "d63a94528530c3ea5ff46924c8001cec4a398609"
"reference": "7713ddf81518d0823b027fe74ec390b80f6b6536"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/d63a94528530c3ea5ff46924c8001cec4a398609",
"reference": "d63a94528530c3ea5ff46924c8001cec4a398609",
"url": "https://api.github.com/repos/symfony/translation/zipball/7713ddf81518d0823b027fe74ec390b80f6b6536",
"reference": "7713ddf81518d0823b027fe74ec390b80f6b6536",
"shasum": ""
},
"require": {
@ -1573,7 +1573,7 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2016-06-29 05:41:56"
"time": "2016-07-26 08:04:17"
},
{
"name": "twig/twig",

View file

@ -74,9 +74,15 @@ template_cache = true
; Show detailed error logs in browser
show_errors = false
; Enable twig (the templating engine) debug mode
twig_debug = false
; Show a small version of the changelog loaded from sakura.flash.moe
show_changelog = false
; Enable twig debug mode
twig_debug = false
; Host for the mahou serve command
host = localhost:8000
@ -157,13 +163,17 @@ mode = sandbox
client_id =
secret_id =
; Ranks ids
; Ranks ids, these ranks are used by automated procedures in the backend
; If you're using the setup command in mahou these are already set correctly for you!
[rank]
inactive = 1
regular = 2
premium = 8
alumni = 9
banned = 10
mod = 3
admin = 4
bot = 5
premium = 6
alumni = 7
banned = 8
; Forum settings
[forum]
@ -173,7 +183,8 @@ max_title_length = 128
min_title_length = 4
; Id of the trash forum
trash = 19
; See second comment of the ranks category
trash = 4
; Comment settings
[comments]

View file

@ -97,10 +97,12 @@ class BaseTables extends Migration
->unsigned();
$table->integer('rank_id')
->unsigned();
->unsigned()
->default(0);
$table->integer('user_id')
->unsigned();
->unsigned()
->default(0);
$table->string('forum_perms', 255);
});
@ -113,9 +115,13 @@ class BaseTables extends Migration
$table->string('forum_name', 255);
$table->text('forum_desc');
$table->text('forum_desc')
->nullable()
->default(null);
$table->string('forum_link', 255);
$table->string('forum_link', 255)
->nullable()
->default(null);
$table->integer('forum_category')
->unsigned()
@ -125,7 +131,9 @@ class BaseTables extends Migration
->unsigned()
->default(0);
$table->string('forum_icon', 255);
$table->string('forum_icon', 255)
->nullable()
->default(null);
});
$schema->create('friends', function (Blueprint $table) {
@ -313,7 +321,9 @@ class BaseTables extends Migration
->unsigned()
->default(0);
$table->string('rank_colour', 255);
$table->string('rank_colour', 255)
->nullable()
->default(null);
$table->text('rank_description');
@ -554,7 +564,6 @@ class BaseTables extends Migration
$schema->drop('forums');
$schema->drop('friends');
$schema->drop('login_attempts');
$schema->drop('messages');
$schema->drop('news');
$schema->drop('notifications');
$schema->drop('optionfields');

View file

@ -1,244 +0,0 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 5.7.10-log - MySQL Community Server (GPL)
-- Server OS: Win64
-- HeidiSQL Version: 9.3.0.4984
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Dumping data for table sakura-development.sakura_config: ~79 rows (approximately)
/*!40000 ALTER TABLE `sakura_config` DISABLE KEYS */;
INSERT INTO `sakura_config` (`config_name`, `config_value`) VALUES
('admin_email', 'sakura@localhost'),
('alumni_rank_id', '9'),
('avatar_max_fsize', '2097152'),
('avatar_max_height', '512'),
('avatar_max_width', '512'),
('avatar_min_height', '20'),
('avatar_min_width', '20'),
('background_max_fsize', '5242880'),
('background_max_height', '1440'),
('background_max_width', '2560'),
('background_min_height', '16'),
('background_min_width', '16'),
('banned_avatar_img', 'public/content/data/{{ TPL }}/images/banned-av.png'),
('charset', 'utf-8'),
('comment_max_length', '500'),
('comment_min_length', '1'),
('content_path', '/content'),
('cookie_domain', 'localhost'),
('cookie_path', '/'),
('cookie_prefix', 'fii_'),
('date_format', 'D Y-m-d H:i:s T'),
('deactivated_avatar_img', 'public/content/data/{{ TPL }}/images/deactivated-av.png'),
('deactive_rank_id', '1'),
('default_rank_id', '2'),
('disable_registration', '0'),
('enable_tpl_cache', '0'),
('forum_text_max', '60000'),
('forum_text_min', '1'),
('forum_title_max', '128'),
('forum_title_min', '4'),
('forum_trash_id', '19'),
('front_page_news_posts', '3'),
('header_announcement_image', ''),
('header_announcement_link', ''),
('header_max_fsize', '2097152'),
('header_max_height', '500'),
('header_max_width', '2048'),
('header_min_height', '125'),
('header_min_width', '512'),
('lock_authentication', '0'),
('mail_signature', 'Sakura | http://localhost/'),
('max_online_time', '120'),
('max_reg_keys', '5'),
('members_per_page', '30'),
('min_entropy', '1'),
('news_posts_per_page', '3'),
('no_avatar_img', 'public/content/data/{{ TPL }}/images/no-av.png'),
('no_background_img', 'public/content/pixel.png'),
('no_cron_interval', '30'),
('no_cron_last', '1460167058'),
('no_cron_service', '1'),
('no_header_img', 'public/content/pixel.png'),
('old_username_reserve', '90'),
('paypal_client_id', ''),
('paypal_mode', 'sandbox'),
('paypal_secret', ''),
('pixel_img', 'public/content/pixel.png'),
('premium_amount_max', '24'),
('premium_price_per_month', '1.49'),
('premium_rank_id', '8'),
('recaptcha', '0'),
('recaptcha_private', ''),
('recaptcha_public', ''),
('require_activation', '1'),
('restricted_rank_id', '10'),
('session_check', '4'),
('site_closed', '0'),
('site_closed_reason', 'meow'),
('site_news_category', 'site-news'),
('site_style', 'yuuno'),
('sitedesc', 'Live development environment for the script that powers Flashii.net called Sakura.'),
('sitelogo', ''),
('sitename', 'Sakura'),
('sitetags', '["Flashii","Media","Flashwave","Circle","Zeniea","MalwareUp","Cybernetics","Saibateku","Community","osu!","osu"]'),
('smtp_auth', ''),
('smtp_from_email', ''),
('smtp_from_name', ''),
('smtp_password', '[ base 64 encoded ]'),
('smtp_port', ''),
('smtp_replyto_mail', ''),
('smtp_replyto_name', ''),
('smtp_secure', ''),
('smtp_server', ''),
('smtp_username', ''),
('url_main', 'locahost'),
('url_rewrite', '1'),
('use_gzip', '0'),
('user_uploads', 'uploads'),
('username_max_length', '16'),
('username_min_length', '3');
/*!40000 ALTER TABLE `sakura_config` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_emoticons: ~38 rows (approximately)
/*!40000 ALTER TABLE `sakura_emoticons` DISABLE KEYS */;
INSERT INTO `sakura_emoticons` (`emote_string`, `emote_path`) VALUES
(':amu:', '/content/images/emoticons/amu.png'),
(':angrier:', '/content/images/emoticons/angrier.png'),
(':angriest:', '/content/images/emoticons/angriest.png'),
(':angry:', '/content/images/emoticons/angry.gif'),
(':blank:', '/content/images/emoticons/blank.png'),
(':childish:', '/content/images/emoticons/childish.png'),
(':congrats:', '/content/images/emoticons/congrats.png'),
(':crying:', '/content/images/emoticons/crying.gif'),
(':dizzy:', '/content/images/emoticons/dizzy.gif'),
(':eat:', '/content/images/emoticons/eat.gif'),
(':evil:', '/content/images/emoticons/evil.png'),
(':extreme:', '/content/images/emoticons/extreme.png'),
(':glare:', '/content/images/emoticons/glare.gif'),
(':happy:', '/content/images/emoticons/happy.gif'),
(':horror:', '/content/images/emoticons/horror.gif'),
(':huh:', '/content/images/emoticons/huh.png'),
(':idea:', '/content/images/emoticons/idea.png'),
(':jew:', '/content/images/emoticons/jew.png'),
(':kiss:', '/content/images/emoticons/kiss.gif'),
(':lmao:', '/content/images/emoticons/lmao.gif'),
(':lol:', '/content/images/emoticons/lol.gif'),
(':love:', '/content/images/emoticons/love.png'),
(':meow:', '/content/images/emoticons/meow.png'),
(':omg:', '/content/images/emoticons/omg.gif'),
(':ouch:', '/content/images/emoticons/ouch.gif'),
(':puke:', '/content/images/emoticons/puke.gif'),
(':ruse:', '/content/images/emoticons/ruse.png'),
(':sad:', '/content/images/emoticons/sad.png'),
(':sigh:', '/content/images/emoticons/sigh.gif'),
(':suspicious:', '/content/images/emoticons/suspicious.gif'),
(':sweat:', '/content/images/emoticons/sweat.gif'),
(':tired:', '/content/images/emoticons/tired.gif'),
(':yay:', '/content/images/emoticons/vhappy.gif'),
(':winxp:', '/content/images/emoticons/winxp.png'),
(':wtf:', '/content/images/emoticons/wtf.gif'),
(':sleep:', '/content/images/emoticons/zzz.gif'),
(':what:', '/content/images/emoticons/what.png'),
(':smug:', '/content/images/emoticons/smug.png');
/*!40000 ALTER TABLE `sakura_emoticons` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_forums: ~18 rows (approximately)
/*!40000 ALTER TABLE `sakura_forums` DISABLE KEYS */;
INSERT INTO `sakura_forums` (`forum_id`, `forum_order`, `forum_name`, `forum_desc`, `forum_link`, `forum_category`, `forum_type`, `forum_icon`) VALUES
(1, 1, 'General', 'General category', '', 0, 1, ''),
(3, 2, 'General Discussion', 'Civilised discussions about things that don\'t have their own subforum.', '', 1, 0, 'fa-comments'),
(15, 3, 'Staff', 'Staff discussion', '', 0, 1, ''),
(18, 4, 'General', 'Discuss Staff Stuff.', '', 15, 0, 'fa-user-secret'),
(19, 5, 'Purgatorii', 'This is where deleted threads rot.', '', 15, 0, 'fa-trash');
/*!40000 ALTER TABLE `sakura_forums` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_forum_permissions: ~55 rows (approximately)
/*!40000 ALTER TABLE `sakura_forum_permissions` DISABLE KEYS */;
INSERT INTO `sakura_forum_permissions` (`forum_id`, `rank_id`, `user_id`, `forum_perms`) VALUES
(1, 1, 0, '00000000001'),
(1, 2, 0, '00000011111'),
(1, 3, 0, '11111111111'),
(1, 4, 0, '11111111111'),
(1, 5, 0, '11111111111'),
(1, 6, 0, '00000011111'),
(1, 7, 0, '00000111111'),
(1, 8, 0, '00000011111'),
(1, 9, 0, '00000011111'),
(1, 10, 0, '00000000001'),
(1, 11, 0, '00000011111'),
(15, 1, 0, '00000000000'),
(15, 2, 0, '00000000000'),
(15, 3, 0, '00000111111'),
(15, 4, 0, '11111111111'),
(15, 5, 0, '00000111111'),
(15, 6, 0, '00000000000'),
(15, 7, 0, '00000111111'),
(15, 8, 0, '00000000000'),
(15, 9, 0, '00000000000'),
(15, 10, 0, '00000000000'),
(15, 11, 0, '00000000000');
/*!40000 ALTER TABLE `sakura_forum_permissions` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_optionfields: ~3 rows (approximately)
/*!40000 ALTER TABLE `sakura_optionfields` DISABLE KEYS */;
INSERT INTO `sakura_optionfields` (`option_id`, `option_name`, `option_description`, `option_type`, `option_permission`) VALUES
('profileBackgroundSiteWide', 'Display profile background site wide', 'This will make the profile background you set on your profile appear on the entire site (except on other profiles).', 'checkbox', 'CHANGE_BACKGROUND'),
('useMisaki', 'Use the testing style', 'This will make the site use the new Misaki style instead of Yuuno.', 'checkbox', 'ALTER_PROFILE');
/*!40000 ALTER TABLE `sakura_optionfields` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_permissions: ~11 rows (approximately)
/*!40000 ALTER TABLE `sakura_permissions` DISABLE KEYS */;
INSERT INTO `sakura_permissions` (`rank_id`, `user_id`, `permissions_site`, `permissions_manage`) VALUES
(1, 0, '00000000000000000000000000000001', '00'),
(2, 0, '11110000111111111100111101101100', '00'),
(3, 0, '11110001111111111111111111111100', '11'),
(4, 0, '11110111111111111111111111111100', '11'),
(5, 0, '11110001111111111111111111111100', '11'),
(6, 0, '11110000111111111100111101101100', '00'),
(7, 0, '11110001111111111111111111111100', '01'),
(8, 0, '11110001111111111111111111111100', '00'),
(9, 0, '11110001111111111111111111111100', '00'),
(10, 0, '11110000000011010100101000100010', '00'),
(11, 0, '11110000111111111100111101101100', '00');
/*!40000 ALTER TABLE `sakura_permissions` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_profilefields: ~12 rows (approximately)
/*!40000 ALTER TABLE `sakura_profilefields` DISABLE KEYS */;
INSERT INTO `sakura_profilefields` (`field_id`, `field_name`, `field_type`, `field_link`, `field_linkformat`, `field_description`, `field_additional`) VALUES
(1, 'Website', 'url', 1, '{{ VAL }}', 'URL to your website', ''),
(2, 'Twitter', 'text', 1, 'https://twitter.com/{{ VAL }}', 'Your @twitter Username', ''),
(3, 'BitBucket', 'text', 1, 'https://bitbucket.org/{{ VAL }}', 'Your BitBucket Username', ''),
(4, 'Skype', 'text', 1, 'skype:{{ VAL }}?userinfo', 'Your Skype Username', ''),
(5, 'YouTube', 'text', 0, '', 'ID or Username excluding http://youtube.com/*/', '{"youtubetype": ["checkbox", "I <b>do not</b> have a Channel Username (url looks like https://www.youtube.com/channel/UCXZcw5hw5C7Neto-T_nRXBQ)."]}'),
(6, 'SoundCloud', 'text', 1, 'https://soundcloud.com/{{ VAL }}', 'Your SoundCloud username', ''),
(7, 'Steam', 'text', 1, 'https://steamcommunity.com/id/{{ VAL }}', 'Your Steam Community Username (may differ from login username)', ''),
(8, 'osu!', 'text', 1, 'https://osu.ppy.sh/u/{{ VAL }}', 'Your osu! Username', ''),
(9, 'Origin', 'text', 0, '', 'Your Origin User ID', ''),
(10, 'Xbox Live', 'text', 1, 'https://account.xbox.com/en-GB/Profile?Gamertag={{ VAL }}', 'Your Xbox User ID', ''),
(11, 'PSN', 'text', 1, 'http://psnprofiles.com/{{ VAL }}', 'Your PSN User ID', ''),
(12, 'Last.fm', 'text', 1, 'http://last.fm/user/{{ VAL }}', 'Your Last.fm username', '');
/*!40000 ALTER TABLE `sakura_profilefields` ENABLE KEYS */;
-- Dumping data for table sakura-development.sakura_ranks: ~11 rows (approximately)
/*!40000 ALTER TABLE `sakura_ranks` DISABLE KEYS */;
INSERT INTO `sakura_ranks` (`rank_id`, `rank_hierarchy`, `rank_name`, `rank_multiple`, `rank_hidden`, `rank_colour`, `rank_description`, `rank_title`) VALUES
(1, 0, 'Deactivated', '', 1, '#555', 'Users that are yet to be activated or that deactivated their own account.', 'Deactivated'),
(2, 1, 'Regular user', 's', 0, 'inherit', 'Regular users with regular permissions.', 'Regular user'),
(3, 3, 'Site moderator', 's', 0, '#FA3703', 'Users with special permissions like being able to ban and modify users if needed.', 'Moderator'),
(4, 4, 'Administrator', 's', 0, '#824CA0', 'Users that manage the server and everything around that.', 'Administrator'),
(5, 3, 'Developer', 's', 0, '#6EAC0A', 'Users that either create or test new features of the site.', 'Developer'),
(6, 1, 'Bot', 's', 1, '#9E8DA7', 'Reserved user accounts for services.', 'Bot'),
(7, 2, 'Chat moderator', 's', 0, '#09F', 'Moderators of the chat room.', 'Moderator'),
(8, 1, 'Tenshi', '', 0, '#EE9400', 'Users that bought premium to help us keep the site and its services alive!', 'Tenshi'),
(9, 1, 'Alumnii', '', 0, '#FF69B4', 'People who have made big contributions to the community but have moved on.', 'Alumni'),
(10, 0, 'Restricted', '', 1, '#666', 'Users that are restricted.', 'Restricted'),
(11, 1, 'Early Supporter', 's', 0, '#0049EE', 'User that donated before the premium system.', 'Early Supporter');
/*!40000 ALTER TABLE `sakura_ranks` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

View file

@ -1,436 +0,0 @@
SET NAMES utf8;
SET time_zone = '+00:00';
DROP TABLE IF EXISTS `osulb_scores`;
CREATE TABLE `osulb_scores` (
`osu_id` bigint(255) unsigned NOT NULL,
`fii_id` bigint(255) unsigned NOT NULL,
`last_update` int(11) unsigned NOT NULL,
`osu_name` varchar(16) COLLATE utf8_bin NOT NULL,
`fii_name` varchar(16) COLLATE utf8_bin NOT NULL,
`osu_mode` tinyint(1) unsigned NOT NULL,
`osu_count300` int(11) unsigned NOT NULL,
`osu_count100` int(11) unsigned NOT NULL,
`osu_count50` int(11) unsigned NOT NULL,
`osu_playcount` int(11) unsigned NOT NULL,
`osu_ranked_score` bigint(255) unsigned NOT NULL,
`osu_total_score` bigint(255) unsigned NOT NULL,
`osu_pp_rank` bigint(255) unsigned NOT NULL,
`osu_level` float unsigned NOT NULL,
`osu_pp_raw` float unsigned NOT NULL,
`osu_accuracy` float NOT NULL,
`osu_count_rank_ss` int(11) NOT NULL,
`osu_count_rank_s` int(11) NOT NULL,
`osu_count_rank_a` int(11) NOT NULL,
`osu_country` char(2) COLLATE utf8_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_actioncodes`;
CREATE TABLE `sakura_actioncodes` (
`code_action` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Action identifier so the backend knows what to do.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that would be affected by this action',
`action_code` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The URL key for using this code.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_apikeys`;
CREATE TABLE `sakura_apikeys` (
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`owner` bigint(128) unsigned NOT NULL COMMENT 'ID of user that owns this API key.',
`apikey` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'The API key.',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_bans`;
CREATE TABLE `sakura_bans` (
`ban_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of user that was banned, 0 for just an IP ban.',
`ban_begin` int(11) unsigned NOT NULL COMMENT 'Timestamp when the user was banned.',
`ban_end` int(11) unsigned NOT NULL COMMENT 'Timestamp when the user should regain access to the site.',
`ban_reason` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT 'Reason given for the ban.',
`ban_moderator` bigint(255) unsigned NOT NULL COMMENT 'ID of moderator that banned this user,',
PRIMARY KEY (`ban_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_comments`;
CREATE TABLE `sakura_comments` (
`comment_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`comment_category` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'Comment category.',
`comment_timestamp` int(11) unsigned NOT NULL COMMENT 'Timestamp of when this comment was posted.',
`comment_poster` bigint(255) unsigned NOT NULL COMMENT 'User ID of the poster.',
`comment_reply_to` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the comment this comment is a reply to',
`comment_text` text COLLATE utf8_bin NOT NULL COMMENT 'Content of the comment.',
PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_comment_votes`;
CREATE TABLE `sakura_comment_votes` (
`vote_comment` bigint(255) unsigned NOT NULL COMMENT 'ID of the comment that was voted on.',
`vote_user` bigint(255) unsigned NOT NULL COMMENT 'ID of the voter.',
`vote_state` tinyint(1) unsigned NOT NULL COMMENT '0 = dislike, 1 = like.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_config`;
CREATE TABLE `sakura_config` (
`config_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Array key for configuration value',
`config_value` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The value, obviously.',
UNIQUE KEY `config_name` (`config_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_emoticons`;
CREATE TABLE `sakura_emoticons` (
`emote_string` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'String to catch and replace',
`emote_path` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Path to the image file relative to the content domain.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_error_log`;
CREATE TABLE `sakura_error_log` (
`error_id` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'An ID that is created when an error occurs.',
`error_timestamp` varchar(128) COLLATE utf8_bin NOT NULL COMMENT 'A datestring from when the error occurred.',
`error_revision` int(16) unsigned NOT NULL COMMENT 'Sakura Revision number.',
`error_type` int(16) unsigned NOT NULL COMMENT 'The PHP error type of this error.',
`error_line` int(32) unsigned NOT NULL COMMENT 'The line that caused this error.',
`error_string` varchar(512) COLLATE utf8_bin NOT NULL COMMENT 'PHP''s description of this error.',
`error_file` varchar(512) COLLATE utf8_bin NOT NULL COMMENT 'The file in which this error occurred.',
`error_backtrace` text COLLATE utf8_bin NOT NULL COMMENT 'A full base64 and json encoded backtrace containing all environment data.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_faq`;
CREATE TABLE `sakura_faq` (
`faq_id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`faq_shorthand` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Used for linking directly to a question.',
`faq_question` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The question.',
`faq_answer` text COLLATE utf8_bin NOT NULL COMMENT 'The answer.',
PRIMARY KEY (`faq_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_forums`;
CREATE TABLE `sakura_forums` (
`forum_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`forum_order` bigint(255) unsigned NOT NULL COMMENT 'Forum sorting order.',
`forum_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display name of the forum.',
`forum_desc` text COLLATE utf8_bin NOT NULL COMMENT 'Description of the forum.',
`forum_link` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'If set forum will display as a link.',
`forum_category` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the category this forum falls under.',
`forum_type` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'Forum type, 0 for regular board, 1 for category and 2 for link.',
`forum_icon` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display icon for the forum.',
PRIMARY KEY (`forum_id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_forum_permissions`;
CREATE TABLE `sakura_forum_permissions` (
`forum_id` bigint(255) unsigned NOT NULL COMMENT 'Forum ID',
`rank_id` bigint(128) unsigned NOT NULL COMMENT 'Rank ID, leave 0 for a user',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User ID, leave 0 for a rank',
`forum_perms` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Forum action permission string'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_friends`;
CREATE TABLE `sakura_friends` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that added the friend.',
`friend_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that was added as a friend.',
`friend_timestamp` int(11) unsigned NOT NULL COMMENT 'Timestamp of action.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_infopages`;
CREATE TABLE `sakura_infopages` (
`page_shorthand` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Name used for calling this page up in the /r/URL',
`page_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title displayed on the top of the page',
`page_content` text COLLATE utf8_bin NOT NULL COMMENT 'Content of the page'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_login_attempts`;
CREATE TABLE `sakura_login_attempts` (
`attempt_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`attempt_success` tinyint(1) unsigned NOT NULL COMMENT 'Success boolean.',
`attempt_timestamp` int(11) unsigned NOT NULL COMMENT 'Unix timestamp of the event.',
`attempt_ip` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'IP that made this attempt.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that was attempted to log in to.',
PRIMARY KEY (`attempt_id`)
) ENGINE=InnoDB AUTO_INCREMENT=596 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_messages`;
CREATE TABLE `sakura_messages` (
`id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`from_user` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that sent this message.',
`to_user` bigint(255) unsigned NOT NULL COMMENT 'ID of user that should receive this message.',
`read` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'IDs of users who read this message.',
`deleted` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Indicator if one of the parties deleted the message, if it is already 1 the script will remove this row.',
`timestamp` int(11) unsigned NOT NULL COMMENT 'Timestamp of the time this message was sent',
`subject` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the message',
`content` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the message.',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_news`;
CREATE TABLE `sakura_news` (
`news_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`news_category` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Category ID.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of user who posted this news message.',
`news_timestamp` int(11) unsigned NOT NULL COMMENT 'News post timestamp.',
`news_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the post.',
`news_content` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the post',
PRIMARY KEY (`news_id`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_notifications`;
CREATE TABLE `sakura_notifications` (
`alert_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`user_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'User ID this notification is intended for.',
`alert_timestamp` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp when this notification was created.',
`alert_read` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Toggle for unread and read.',
`alert_sound` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Toggle if a sound should be played upon receiving the notification.',
`alert_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title displayed on the notification.',
`alert_text` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Text displayed.',
`alert_link` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Link (empty for no link).',
`alert_img` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Image path, prefix with font: to use a font class instead of an image.',
`alert_timeout` int(16) unsigned NOT NULL DEFAULT '0' COMMENT 'How long the notification should stay on screen in milliseconds, 0 for forever.',
PRIMARY KEY (`alert_id`)
) ENGINE=InnoDB AUTO_INCREMENT=160 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_optionfields`;
CREATE TABLE `sakura_optionfields` (
`option_id` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Unique identifier for accessing this option.',
`option_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Description of the field in a proper way.',
`option_description` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Longer description of the option.',
`option_type` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Type attribute in the input element.',
`option_permission` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The minimum permission level this option requires.',
UNIQUE KEY `id` (`option_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_permissions`;
CREATE TABLE `sakura_permissions` (
`rank_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the rank this permissions set is used for.',
`user_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the user this permissions set is used for.',
`permissions_site` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '0' COMMENT 'Site permissions.',
`permissions_manage` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '0' COMMENT 'Site management permissions'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_posts`;
CREATE TABLE `sakura_posts` (
`post_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`topic_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of topic this post is a part of.',
`forum_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of forum this was posted in.',
`poster_id` bigint(255) unsigned DEFAULT '0' COMMENT 'ID of poster of this post.',
`poster_ip` varchar(40) COLLATE utf8_bin NOT NULL COMMENT 'IP of poster.',
`post_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Time this post was made.',
`post_subject` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Subject of the post.',
`post_text` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the post.',
`post_edit_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Time this post was last edited.',
`post_edit_reason` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Reason this was edited.',
`post_edit_user` int(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of user that edited.',
PRIMARY KEY (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1208 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_premium`;
CREATE TABLE `sakura_premium` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that purchased Tenshi.',
`premium_start` int(11) unsigned NOT NULL COMMENT 'Timestamp of first purchase.',
`premium_expire` int(11) unsigned NOT NULL COMMENT 'Expiration timestamp.',
UNIQUE KEY `uid` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_premium_log`;
CREATE TABLE `sakura_premium_log` (
`transaction_id` int(16) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User ID of purchaser',
`transaction_amount` float NOT NULL COMMENT 'Amount that was transferred.',
`transaction_date` int(11) unsigned NOT NULL COMMENT 'Date when the purchase was made.',
`transaction_comment` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A short description of the action taken.',
PRIMARY KEY (`transaction_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_profilefields`;
CREATE TABLE `sakura_profilefields` (
`field_id` int(64) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID used for ordering on the userpage.',
`field_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Name of the field.',
`field_type` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Type attribute in the input element.',
`field_link` tinyint(1) unsigned NOT NULL COMMENT 'Set if this value should be put in a href.',
`field_linkformat` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'If the form is a link how should it be formatted? {{ VAL }} gets replace with the value.',
`field_description` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Description of the field displayed in the control panel.',
`field_additional` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Undocumented JSON array containing special options if needed (probably only going to be used for the YouTube field).',
PRIMARY KEY (`field_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_ranks`;
CREATE TABLE `sakura_ranks` (
`rank_id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`rank_hierarchy` int(11) unsigned NOT NULL COMMENT 'Rank hierarchy.',
`rank_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display name of the rank.',
`rank_multiple` varchar(10) COLLATE utf8_bin DEFAULT NULL COMMENT 'Used when addressing this rank as a multiple',
`rank_hidden` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Don''t show any public links to this rank.',
`rank_colour` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Colour used for the username of a member of this rank.',
`rank_description` text COLLATE utf8_bin NOT NULL COMMENT 'A description of what a user of this rank can do/is supposed to do.',
`rank_title` varchar(64) COLLATE utf8_bin NOT NULL COMMENT 'Default user title if user has none set.',
PRIMARY KEY (`rank_id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_reports`;
CREATE TABLE `sakura_reports` (
`id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`type` int(32) unsigned NOT NULL COMMENT 'Report type, entirely handled on the script side.',
`issuer` bigint(255) unsigned NOT NULL COMMENT 'ID of the person who issued this report.',
`subject` bigint(255) unsigned NOT NULL COMMENT 'ID pointing out what was reported (a more accurate description isn''t possible due to the type column).',
`title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A quick description of this report.',
`description` text COLLATE utf8_bin NOT NULL COMMENT 'And a detailed description.',
`reviewed` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the moderator that reviewed this report.',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_sessions`;
CREATE TABLE `sakura_sessions` (
`session_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management. ',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user this session is spawned for. ',
`user_ip` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'IP of the user this session is spawned for.',
`user_agent` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'User agent of the user this session is spawned for.',
`session_key` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Session key, allow direct access to the user''s account. ',
`session_start` int(16) unsigned NOT NULL COMMENT 'The timestamp for when the session was started. ',
`session_expire` int(16) unsigned NOT NULL COMMENT 'The timestamp for when this session should end, -1 for permanent. ',
`session_remember` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'If set to 1 session will be extended each time a page is loaded.',
PRIMARY KEY (`session_id`)
) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_topics`;
CREATE TABLE `sakura_topics` (
`topic_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`forum_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of forum this topic was created in.',
`topic_hidden` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Boolean to set the topic as hidden.',
`topic_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the topic.',
`topic_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp when the topic was created.',
`topic_time_limit` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'After how long a topic should be locked.',
`topic_views` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'Amount of times the topic has been viewed.',
`topic_status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Status of topic.',
`topic_status_change` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Date the topic status was changed (used for deletion cooldown as well).',
`topic_type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Type of the topic.',
`topic_last_reply` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of when the last reply made to this thread.',
`topic_old_forum` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'Pre-move forum id.',
PRIMARY KEY (`topic_id`)
) ENGINE=InnoDB AUTO_INCREMENT=191 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_topics_track`;
CREATE TABLE `sakura_topics_track` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user this row applies to.',
`topic_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the thread in question.',
`forum_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the forum in question.',
`mark_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of the event.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_uploads`;
CREATE TABLE `sakura_uploads` (
`file_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated value for management',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that uploaded the file',
`file_data` longblob,
`file_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Name of the file',
`file_mime` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Static mime type of the file',
`file_time` int(11) unsigned NOT NULL COMMENT 'Timestamp of when the file was uploaded',
`file_expire` int(11) unsigned NOT NULL COMMENT 'When should the file be removed, 0 for never',
PRIMARY KEY (`file_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_username_history`;
CREATE TABLE `sakura_username_history` (
`change_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier',
`change_time` int(11) unsigned NOT NULL COMMENT 'Timestamp of change',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User ID',
`username_new` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'New username',
`username_new_clean` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Clean new username',
`username_old` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Old username',
`username_old_clean` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Clean old username',
PRIMARY KEY (`change_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_users`;
CREATE TABLE `sakura_users` (
`user_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management. ',
`username` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Username set at registration.',
`username_clean` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A more cleaned up version of the username for backend usage.',
`password_hash` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Hashing algo used for the password hash.',
`password_salt` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Salt used for the password hash.',
`password_algo` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Algorithm used for the password hash.',
`password_iter` int(11) unsigned NOT NULL COMMENT 'Password hash iterations.',
`password_chan` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Last time the user changed their password.',
`email` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'E-mail of the user for password restoring etc.',
`rank_main` mediumint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'Main rank of the user.',
`user_colour` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Additional name colour, when empty colour defaults to group colour.',
`register_ip` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'IP used for the creation of this account.',
`last_ip` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Last IP that was used to log into this account.',
`user_title` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT 'Custom user title of the user, when empty reverts to their derault group name.',
`user_registered` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of account creation.',
`user_last_online` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Last time anything was done on this account.',
`user_birthday` date NOT NULL DEFAULT '0000-00-00' COMMENT 'Birthdate of the user.',
`user_country` char(2) COLLATE utf8_bin NOT NULL DEFAULT 'XX' COMMENT 'Contains ISO 3166 country code of user''s registration location.',
`user_avatar` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the avatar in the uploads table.',
`user_background` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the background in the uploads table.',
`user_header` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the profile header in the uploads table.',
`user_page` longtext COLLATE utf8_bin COMMENT 'Contents of the userpage.',
`user_signature` text COLLATE utf8_bin COMMENT 'Signature displayed below forum posts.',
`password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `username_clean` (`username_clean`)
) ENGINE=InnoDB AUTO_INCREMENT=481 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_user_optionfields`;
CREATE TABLE `sakura_user_optionfields` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User this field applies to',
`field_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Identifier of the field',
`field_value` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Value of the field'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_user_profilefields`;
CREATE TABLE `sakura_user_profilefields` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User this field applies to',
`field_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Identifier of the field',
`field_value` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Value of the field'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_user_ranks`;
CREATE TABLE `sakura_user_ranks` (
`user_id` bigint(255) unsigned NOT NULL,
`rank_id` bigint(128) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
DROP TABLE IF EXISTS `sakura_warnings`;
CREATE TABLE `sakura_warnings` (
`warning_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of user that was warned.',
`moderator_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that issued the warning.',
`warning_issued` int(16) unsigned NOT NULL COMMENT 'Timestamp of the date the warning was issued.',
`warning_expires` int(16) unsigned NOT NULL COMMENT 'Timstamp when the warning should expire, 0 for a permanent warning.',
`warning_action` tinyint(1) unsigned DEFAULT NULL COMMENT 'Action taken.',
`warning_reason` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT 'Reason for the warning.',
PRIMARY KEY (`warning_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

View file

@ -1,461 +0,0 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 5.7.10-log - MySQL Community Server (GPL)
-- Server OS: Win64
-- HeidiSQL Version: 9.3.0.4984
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Dumping structure for table sakura-development.sakura_actioncodes
CREATE TABLE IF NOT EXISTS `sakura_actioncodes` (
`code_action` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Action identifier so the backend knows what to do.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that would be affected by this action',
`action_code` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The URL key for using this code.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_comments
CREATE TABLE IF NOT EXISTS `sakura_comments` (
`comment_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`comment_category` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'Comment category.',
`comment_timestamp` int(11) unsigned NOT NULL COMMENT 'Timestamp of when this comment was posted.',
`comment_poster` bigint(255) unsigned NOT NULL COMMENT 'User ID of the poster.',
`comment_reply_to` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the comment this comment is a reply to',
`comment_text` text COLLATE utf8_bin NOT NULL COMMENT 'Content of the comment.',
PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_comment_votes
CREATE TABLE IF NOT EXISTS `sakura_comment_votes` (
`vote_comment` bigint(255) unsigned NOT NULL COMMENT 'ID of the comment that was voted on.',
`vote_user` bigint(255) unsigned NOT NULL COMMENT 'ID of the voter.',
`vote_state` tinyint(1) unsigned NOT NULL COMMENT '0 = dislike, 1 = like.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_config
CREATE TABLE IF NOT EXISTS `sakura_config` (
`config_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Array key for configuration value',
`config_value` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The value, obviously.',
UNIQUE KEY `config_name` (`config_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_emoticons
CREATE TABLE IF NOT EXISTS `sakura_emoticons` (
`emote_string` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'String to catch and replace',
`emote_path` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Path to the image file relative to the content domain.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_error_log
CREATE TABLE IF NOT EXISTS `sakura_error_log` (
`error_id` varchar(32) COLLATE utf8_bin NOT NULL COMMENT 'An ID that is created when an error occurs.',
`error_timestamp` varchar(128) COLLATE utf8_bin NOT NULL COMMENT 'A datestring from when the error occurred.',
`error_revision` int(16) unsigned NOT NULL COMMENT 'Sakura Revision number.',
`error_type` int(16) unsigned NOT NULL COMMENT 'The PHP error type of this error.',
`error_line` int(32) unsigned NOT NULL COMMENT 'The line that caused this error.',
`error_string` varchar(512) COLLATE utf8_bin NOT NULL COMMENT 'PHP''s description of this error.',
`error_file` varchar(512) COLLATE utf8_bin NOT NULL COMMENT 'The file in which this error occurred.',
`error_backtrace` text COLLATE utf8_bin NOT NULL COMMENT 'A full base64 and json encoded backtrace containing all environment data.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_faq
CREATE TABLE IF NOT EXISTS `sakura_faq` (
`faq_id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`faq_shorthand` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Used for linking directly to a question.',
`faq_question` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The question.',
`faq_answer` text COLLATE utf8_bin NOT NULL COMMENT 'The answer.',
PRIMARY KEY (`faq_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_forums
CREATE TABLE IF NOT EXISTS `sakura_forums` (
`forum_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`forum_order` bigint(255) unsigned NOT NULL COMMENT 'Forum sorting order.',
`forum_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display name of the forum.',
`forum_desc` text COLLATE utf8_bin NOT NULL COMMENT 'Description of the forum.',
`forum_link` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'If set forum will display as a link.',
`forum_category` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the category this forum falls under.',
`forum_type` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'Forum type, 0 for regular board, 1 for category and 2 for link.',
`forum_icon` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display icon for the forum.',
PRIMARY KEY (`forum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_forum_permissions
CREATE TABLE IF NOT EXISTS `sakura_forum_permissions` (
`forum_id` bigint(255) unsigned NOT NULL COMMENT 'Forum ID',
`rank_id` bigint(128) unsigned NOT NULL COMMENT 'Rank ID, leave 0 for a user',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User ID, leave 0 for a rank',
`forum_perms` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Forum action permission string'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_friends
CREATE TABLE IF NOT EXISTS `sakura_friends` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that added the friend.',
`friend_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that was added as a friend.',
`friend_timestamp` int(11) unsigned NOT NULL COMMENT 'Timestamp of action.',
KEY `uid` (`user_id`),
KEY `fid` (`friend_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_infopages
CREATE TABLE IF NOT EXISTS `sakura_infopages` (
`page_shorthand` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Name used for calling this page up in the /r/URL',
`page_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title displayed on the top of the page',
`page_content` text COLLATE utf8_bin NOT NULL COMMENT 'Content of the page'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_login_attempts
CREATE TABLE IF NOT EXISTS `sakura_login_attempts` (
`attempt_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`attempt_success` tinyint(1) unsigned NOT NULL COMMENT 'Success boolean.',
`attempt_timestamp` int(11) unsigned NOT NULL COMMENT 'Unix timestamp of the event.',
`attempt_ip` varbinary(50) NOT NULL COMMENT 'IP that made this attempt.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that was attempted to log in to.',
PRIMARY KEY (`attempt_id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_news
CREATE TABLE IF NOT EXISTS `sakura_news` (
`news_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`news_category` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Category ID.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of user who posted this news message.',
`news_timestamp` int(11) unsigned NOT NULL COMMENT 'News post timestamp.',
`news_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the post.',
`news_content` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the post',
PRIMARY KEY (`news_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_notifications
CREATE TABLE IF NOT EXISTS `sakura_notifications` (
`alert_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`user_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'User ID this notification is intended for.',
`alert_timestamp` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp when this notification was created.',
`alert_read` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Toggle for unread and read.',
`alert_sound` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Toggle if a sound should be played upon receiving the notification.',
`alert_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title displayed on the notification.',
`alert_text` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Text displayed.',
`alert_link` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Link (empty for no link).',
`alert_img` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Image path, prefix with font: to use a font class instead of an image.',
`alert_timeout` int(16) unsigned NOT NULL DEFAULT '0' COMMENT 'How long the notification should stay on screen in milliseconds, 0 for forever.',
PRIMARY KEY (`alert_id`),
KEY `uid` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_optionfields
CREATE TABLE IF NOT EXISTS `sakura_optionfields` (
`option_id` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Unique identifier for accessing this option.',
`option_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Description of the field in a proper way.',
`option_description` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Longer description of the option.',
`option_type` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Type attribute in the input element.',
`option_permission` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The minimum permission level this option requires.',
UNIQUE KEY `id` (`option_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_permissions
CREATE TABLE IF NOT EXISTS `sakura_permissions` (
`rank_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the rank this permissions set is used for.',
`user_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the user this permissions set is used for.',
`permissions_site` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '0' COMMENT 'Site permissions.',
`permissions_manage` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '0' COMMENT 'Site management permissions'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_posts
CREATE TABLE IF NOT EXISTS `sakura_posts` (
`post_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`topic_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of topic this post is a part of.',
`forum_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of forum this was posted in.',
`poster_id` bigint(255) unsigned DEFAULT '0' COMMENT 'ID of poster of this post.',
`poster_ip` varchar(40) COLLATE utf8_bin NOT NULL COMMENT 'IP of poster.',
`post_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Time this post was made.',
`post_subject` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Subject of the post.',
`post_text` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the post.',
`post_edit_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Time this post was last edited.',
`post_edit_reason` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Reason this was edited.',
`post_edit_user` int(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of user that edited.',
PRIMARY KEY (`post_id`),
KEY `topic_id` (`topic_id`),
KEY `forum_id` (`forum_id`),
KEY `poster_id` (`poster_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_premium
CREATE TABLE IF NOT EXISTS `sakura_premium` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that purchased Tenshi.',
`premium_start` int(11) unsigned NOT NULL COMMENT 'Timestamp of first purchase.',
`premium_expire` int(11) unsigned NOT NULL COMMENT 'Expiration timestamp.',
UNIQUE KEY `uid` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_premium_log
CREATE TABLE IF NOT EXISTS `sakura_premium_log` (
`transaction_id` int(16) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User ID of purchaser',
`transaction_amount` float NOT NULL COMMENT 'Amount that was transferred.',
`transaction_date` int(11) unsigned NOT NULL COMMENT 'Date when the purchase was made.',
`transaction_comment` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A short description of the action taken.',
PRIMARY KEY (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_profilefields
CREATE TABLE IF NOT EXISTS `sakura_profilefields` (
`field_id` int(64) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID used for ordering on the userpage.',
`field_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Name of the field.',
`field_type` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Type attribute in the input element.',
`field_link` tinyint(1) unsigned NOT NULL COMMENT 'Set if this value should be put in a href.',
`field_linkformat` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'If the form is a link how should it be formatted? {{ VAL }} gets replace with the value.',
`field_description` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Description of the field displayed in the control panel.',
`field_additional` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Undocumented JSON array containing special options if needed (probably only going to be used for the YouTube field).',
PRIMARY KEY (`field_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_ranks
CREATE TABLE IF NOT EXISTS `sakura_ranks` (
`rank_id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`rank_hierarchy` int(11) unsigned NOT NULL COMMENT 'Rank hierarchy.',
`rank_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display name of the rank.',
`rank_multiple` varchar(10) COLLATE utf8_bin DEFAULT NULL COMMENT 'Used when addressing this rank as a multiple',
`rank_hidden` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Don''t show any public links to this rank.',
`rank_colour` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Colour used for the username of a member of this rank.',
`rank_description` text COLLATE utf8_bin NOT NULL COMMENT 'A description of what a user of this rank can do/is supposed to do.',
`rank_title` varchar(64) COLLATE utf8_bin NOT NULL COMMENT 'Default user title if user has none set.',
PRIMARY KEY (`rank_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_reports
CREATE TABLE IF NOT EXISTS `sakura_reports` (
`id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`type` int(32) unsigned NOT NULL COMMENT 'Report type, entirely handled on the script side.',
`issuer` bigint(255) unsigned NOT NULL COMMENT 'ID of the person who issued this report.',
`subject` bigint(255) unsigned NOT NULL COMMENT 'ID pointing out what was reported (a more accurate description isn''t possible due to the type column).',
`title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A quick description of this report.',
`description` text COLLATE utf8_bin NOT NULL COMMENT 'And a detailed description.',
`reviewed` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the moderator that reviewed this report.',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_sessions
CREATE TABLE IF NOT EXISTS `sakura_sessions` (
`session_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management. ',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user this session is spawned for. ',
`user_ip` varbinary(50) NOT NULL COMMENT 'IP of the user this session is spawned for.',
`user_agent` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'User agent of the user this session is spawned for.',
`session_key` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Session key, allow direct access to the user''s account. ',
`session_start` int(16) unsigned NOT NULL COMMENT 'The timestamp for when the session was started. ',
`session_expire` int(16) unsigned NOT NULL COMMENT 'The timestamp for when this session should end, -1 for permanent. ',
`session_remember` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'If set to 1 session will be extended each time a page is loaded.',
PRIMARY KEY (`session_id`),
KEY `userid` (`user_id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_topics
CREATE TABLE IF NOT EXISTS `sakura_topics` (
`topic_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.',
`forum_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of forum this topic was created in.',
`topic_hidden` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Boolean to set the topic as hidden.',
`topic_title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the topic.',
`topic_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp when the topic was created.',
`topic_time_limit` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'After how long a topic should be locked.',
`topic_views` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'Amount of times the topic has been viewed.',
`topic_status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Status of topic.',
`topic_status_change` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Date the topic status was changed (used for deletion cooldown as well).',
`topic_type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Type of the topic.',
`topic_last_reply` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of when the last reply made to this thread.',
`topic_old_forum` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'Pre-move forum id.',
PRIMARY KEY (`topic_id`),
KEY `forum_id` (`forum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_topics_track
CREATE TABLE IF NOT EXISTS `sakura_topics_track` (
`user_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the user this row applies to.',
`topic_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the thread in question.',
`forum_id` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the forum in question.',
`mark_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of the event.'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_uploads
CREATE TABLE IF NOT EXISTS `sakura_uploads` (
`file_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated value for management',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that uploaded the file',
`file_data` longblob NOT NULL COMMENT 'Contents of the file',
`file_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Name of the file',
`file_mime` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Static mime type of the file',
`file_time` int(11) unsigned NOT NULL COMMENT 'Timestamp of when the file was uploaded',
`file_expire` int(11) unsigned NOT NULL COMMENT 'When should the file be removed, 0 for never',
PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_username_history
CREATE TABLE IF NOT EXISTS `sakura_username_history` (
`change_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier',
`change_time` int(11) unsigned NOT NULL COMMENT 'Timestamp of change',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User ID',
`username_new` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'New username',
`username_new_clean` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Clean new username',
`username_old` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Old username',
`username_old_clean` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Clean old username',
PRIMARY KEY (`change_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_users
CREATE TABLE IF NOT EXISTS `sakura_users` (
`user_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management. ',
`username` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Username set at registration.',
`username_clean` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A more cleaned up version of the username for backend usage.',
`password_hash` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Hashing algo used for the password hash.',
`password_salt` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Salt used for the password hash.',
`password_algo` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Algorithm used for the password hash.',
`password_iter` int(11) unsigned NOT NULL COMMENT 'Password hash iterations.',
`password_chan` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Last time the user changed their password.',
`email` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'E-mail of the user for password restoring etc.',
`rank_main` mediumint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'Main rank of the user.',
`user_colour` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Additional name colour, when empty colour defaults to group colour.',
`register_ip` varbinary(50) NOT NULL COMMENT 'IP used for the creation of this account.',
`last_ip` varbinary(50) NOT NULL COMMENT 'Last IP that was used to log into this account.',
`user_title` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT 'Custom user title of the user, when empty reverts to their derault group name.',
`user_registered` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of account creation.',
`user_last_online` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Last time anything was done on this account.',
`user_birthday` date NOT NULL DEFAULT '0000-00-00' COMMENT 'Birthdate of the user.',
`user_country` char(2) COLLATE utf8_bin NOT NULL DEFAULT 'XX' COMMENT 'Contains ISO 3166 country code of user''s registration location.',
`user_avatar` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the avatar in the uploads table.',
`user_background` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the background in the uploads table.',
`user_header` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the profile header in the uploads table.',
`user_page` longtext COLLATE utf8_bin COMMENT 'Contents of the userpage.',
`user_signature` text COLLATE utf8_bin COMMENT 'Signature displayed below forum posts.',
PRIMARY KEY (`user_id`),
UNIQUE KEY `username_clean` (`username_clean`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_user_optionfields
CREATE TABLE IF NOT EXISTS `sakura_user_optionfields` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User this field applies to',
`field_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Identifier of the field',
`field_value` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Value of the field'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_user_profilefields
CREATE TABLE IF NOT EXISTS `sakura_user_profilefields` (
`user_id` bigint(255) unsigned NOT NULL COMMENT 'User this field applies to',
`field_name` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Identifier of the field',
`field_value` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Value of the field'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_user_ranks
CREATE TABLE IF NOT EXISTS `sakura_user_ranks` (
`user_id` bigint(255) unsigned NOT NULL,
`rank_id` bigint(128) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
-- Dumping structure for table sakura-development.sakura_warnings
CREATE TABLE IF NOT EXISTS `sakura_warnings` (
`warning_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.',
`user_id` bigint(255) unsigned NOT NULL COMMENT 'ID of user that was warned.',
`moderator_id` bigint(255) unsigned NOT NULL COMMENT 'ID of the user that issued the warning.',
`warning_issued` int(16) unsigned NOT NULL COMMENT 'Timestamp of the date the warning was issued.',
`warning_expires` int(16) unsigned NOT NULL COMMENT 'Timstamp when the warning should expire, 0 for a permanent warning.',
`warning_action` tinyint(1) unsigned DEFAULT NULL COMMENT 'Action taken.',
`warning_reason` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT 'Reason for the warning.',
PRIMARY KEY (`warning_id`),
KEY `uid` (`user_id`),
KEY `iid` (`moderator_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- Data exporting was unselected.
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

View file

@ -566,7 +566,7 @@ a.default:active {
.header .menu .menu-item.avatar {
padding-left: 30px;
background: url('/pixel.png') no-repeat scroll left center / contain transparent;
background: url('/images/pixel.png') no-repeat scroll left center / contain transparent;
}
@media (max-width: 1024px) {
@ -603,7 +603,7 @@ a.default:active {
.header .menu .menu-item.avatar {
padding-left: 50px;
background: url('/pixel.png') no-repeat scroll left center / contain transparent;
background: url('/images/pixel.png') no-repeat scroll left center / contain transparent;
}
}
@ -803,7 +803,7 @@ a.default:active {
.loginPage input[type="text"],
.loginPage input[type="password"] {
width: calc(100% - 16px);
width: calc(100% ~'-' 16px);
}
.loginPage form > div > label {
@ -1620,7 +1620,7 @@ a.default:active {
}
.settings .profile-field > div:nth-child(2) > input {
width: calc(100% - 16px);
width: calc(100% ~'-' 16px);
}
.settings .profile-save {
@ -2258,7 +2258,7 @@ textarea.inputStyling {
}
.posting-subject input {
width: calc(100% - 10px);
width: calc(100% ~'-' 10px);
}
.posting-bbcodes {
@ -2287,8 +2287,8 @@ textarea.inputStyling {
}
.posting-text textarea {
min-width: calc(100% - 10px);
max-width: calc(100% - 10px);
min-width: calc(100% ~'-' 10px);
max-width: calc(100% ~'-' 10px);
min-height: 200px;
}

View file

@ -0,0 +1 @@
# To make sure Git keeps this folder here

View file

@ -14,7 +14,7 @@
<div class="head">Stats</div>
We have <b>{{ stats.userCount }} user{% if stats.userCount != 1 %}s{% endif %}</b>,
<b><a href="{{ route('user.profile', stats.newestUser.id) }}" style="color: {{ stats.newestUser.colour }};" class="default">{{ stats.newestUser.username }}</a></b> is the newest user,
it has been <b>{{ stats.lastRegDate }} day{{ stats.lastRegDate == 1 ? '' : 's' }}</b> since the last user registered and the forum has <b>{{ stats.topicCount }} thread{% if stats.topicCount != 1 %}s{% endif %}</b> and <b>{{ stats.postCount }} post{% if stats.postCount != 1 %}s{% endif %}</b>.
it has been <b>{{ stats.lastRegDate }} day{{ stats.lastRegDate == 1 ? '' : 's' }}</b> since the last user registered and the forum has <b>{{ stats.topicCount }} topic{% if stats.topicCount != 1 %}s{% endif %}</b> and <b>{{ stats.postCount }} post{% if stats.postCount != 1 %}s{% endif %}</b>.
<div class="head">Online Users</div>
{% if stats.onlineUsers %}
All active users in the past 2 minutes

View file

@ -16,13 +16,13 @@
{% endfor %}
</div>
{% if not forum.type and forum.id > 0 %}
{% set threads = forum.threads|batch(25) %}
{% set topics = forum.topics|batch(25) %}
{% set paginationPages = threads %}
{% set paginationPages = topics %}
{% set paginationUrl %}{{ route('forums.forum', forum.id) }}{% endset %}
{% include 'forum/elements/forumBtns.twig' %}
{% if forum.threads %}
{% if forum.topics %}
<table class="topicList">
<thead>
<tr>
@ -43,7 +43,7 @@
</tr>
</tfoot>
<tbody>
{% for thread in threads[get.page|default(1) - 1] %}
{% for topic in topics[get.page|default(1) - 1] %}
{% include 'forum/elements/topicEntry.twig' %}
{% endfor %}
</tbody>

View file

@ -9,12 +9,12 @@
<a href="{{ forumReplyLink }}" class="forumbtn"><span class="fa fa-reply-all"></span> Reply</a>
{% endif %}
{% if forumNewLink %}
<a href="{{ forumNewLink }}" class="forumbtn"><span class="fa fa-pencil-square-o"></span> New Thread</a>
<a href="{{ forumNewLink }}" class="forumbtn"><span class="fa fa-pencil-square-o"></span> New Topic</a>
{% endif %}
{% if forumMarkRead %}
<a href="{{ forumMarkRead }}" class="forumbtn"><span class="fa fa-check-square-o"></span> Mark as Read</a>
{% endif %}
{% if thread.id and showMod %}
{% if topic.id and showMod %}
{% include 'forum/elements/forumMod.twig' %}
{% endif %}
</div>

View file

@ -17,13 +17,13 @@
</div>
{% if forum.type != 2 %}
<div class="forumCount">
<div class="topics" title="Amount of threads in this forum.">{{ forum.threadCount }}</div>
<div class="topics" title="Amount of topics in this forum.">{{ forum.topicCount }}</div>
<div class="posts" title="Amount of posts in this forum.">{{ forum.postCount }}</div>
</div>
<div class="forumLastPost">
<div>
{% if forum.lastPost.id %}
<a href="{{ route('forums.thread', forum.lastPost.thread) }}" 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(config('date_format')) }}</time> by {% if forum.lastPost.poster.id %}<a href="{{ route('user.profile', forum.lastPost.poster.id) }}" class="default" style="color: {{ forum.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if forumlastPost.poster.colour != 'inherit' %}{{ forum.lastPost.poster.colour }}{% else %}#222{% endif %};">{{ forum.lastPost.poster.username }}</a>{% else %}[deleted user]{% endif %} <a href="{{ route('forums.post', forum.lastPost.id) }}" class="default fa fa-tag"></a>
{% else %}
There are no posts in this forum.<br>&nbsp;

View file

@ -1,4 +1,4 @@
<form method="post" action="{{ route('forums.thread.mod', thread.id) }}" style="display: inline-block;">
<form method="post" action="{{ route('forums.topic.mod', topic.id) }}" style="display: inline-block;">
<input type="hidden" name="session" value="{{ session_id() }}">
{% if forumSticky is defined %}
<button class="forumbtn" title="{{ forumSticky ? 'Unsticky' : 'Sticky' }}" name="action" value="sticky"><span class="fa fa-{{ forumSticky ? 'remove' : 'thumb-tack' }}"></span></button>

View file

@ -48,7 +48,7 @@
pForm = document.getElementById('postingForm'),
pStopEdit = document.getElementById('postingStopEditing'),
pMode = document.getElementById('previewMode'),
tTitle = document.getElementById('threadTitle'),
tTitle = document.getElementById('topicTitle'),
rTitle = document.getElementById('previewTitle'),
rText = document.getElementById('previewText'),
lastParsed = Date.now(),
@ -56,8 +56,8 @@
parser = new AJAX(),
postFetch = new AJAX(),
parserActive = false,
op = {{ thread is defined ? thread.firstPost.id : 0 }},
threadName = "{{ thread is defined ? thread.firstPost.subject : '' }}";
op = {{ topic is defined ? topic.firstPost.id : 0 }},
topicName = "{{ topic is defined ? topic.firstPost.subject : '' }}";
parser.setUrl("{{ route('helper.bbcode.parse') }}");
parser.contentType("application/x-www-form-urlencoded");
@ -152,7 +152,7 @@
function editPost(id) {
pText.disabled = true;
pTitleCont.style.display = 'none';
rTitle.innerText = 'Re: ' + threadName;
rTitle.innerText = 'Re: ' + topicName;
url = "{{ route('forums.post.raw', '1') }}".replace('1', id);
@ -165,8 +165,8 @@
pMode.innerText = 'Editing #' + id;
if (id === op) {
pTitleCont.style.display = null;
pTitle.value = threadName;
rTitle.innerText = threadName;
pTitle.value = topicName;
rTitle.innerText = topicName;
}
pText.disabled = false;
pText.focus();

View file

@ -1,27 +1,27 @@
<tr>
<td class="topicIcon{% if thread.unread(user.id) %} unread{% endif %}{% if thread.type == 2 %} topicAnnouncement{% endif %}">
<div class="fa fa-2x fa-{% if thread.type == 1 %}thumb-tack{% elseif thread.type == 2 %}bullhorn{% elseif thread.status == 1 %}lock{% else %}navicon{% endif %}"></div>
<td class="topicIcon{% if topic.unread(user.id) %} unread{% endif %}{% if topic.type == 2 %} topicAnnouncement{% endif %}">
<div class="fa fa-2x fa-{% if topic.type == 1 %}thumb-tack{% elseif topic.type == 2 %}bullhorn{% elseif topic.status == 1 %}lock{% else %}navicon{% endif %}"></div>
</td>
<td class="topicTitle{% if thread.type == 2 %} topicAnnouncement{% endif %}">
<a href="{{ route('forums.thread', thread.id) }}" class="default">{{ thread.title }}</a>
<td class="topicTitle{% if topic.type == 2 %} topicAnnouncement{% endif %}">
<a href="{{ route('forums.topic', topic.id) }}" class="default">{{ topic.title }}</a>
</td>
<td class="topicAuthor{% if thread.type == 2 %} topicAnnouncement{% endif %}">
{% if thread.firstPost.poster.id %}
<a href="{{ route('user.profile', thread.firstPost.poster.id) }}" class="default" style="color: {{ thread.firstPost.poster.colour }}; text-shadow: 0 0 5px {% if thread.firstPost.poster.colour != 'inherit' %}{{ thread.firstPost.poster.colour }}{% else %}#222{% endif %};">{{ thread.firstPost.poster.username }}</a>
<td class="topicAuthor{% if topic.type == 2 %} topicAnnouncement{% endif %}">
{% if topic.firstPost.poster.id %}
<a href="{{ route('user.profile', topic.firstPost.poster.id) }}" class="default" style="color: {{ topic.firstPost.poster.colour }}; text-shadow: 0 0 5px {% if topic.firstPost.poster.colour != 'inherit' %}{{ topic.firstPost.poster.colour }}{% else %}#222{% endif %};">{{ topic.firstPost.poster.username }}</a>
{% else %}
[deleted user]
{% endif %}
</td>
<td class="topicCounts{% if thread.type == 2 %} topicAnnouncement{% endif %}">
<div class="replies" title="Amount of replies to this thread.">{{ thread.replyCount }}</div>
<div class="views" title="Amount of times this thread has been viewed.">{{ thread.views }}</div>
<td class="topicCounts{% if topic.type == 2 %} topicAnnouncement{% endif %}">
<div class="replies" title="Amount of replies to this topic.">{{ topic.replyCount }}</div>
<div class="views" title="Amount of times this topic has been viewed.">{{ topic.views }}</div>
</td>
<td class="topicLast{% if thread.type == 2 %} topicAnnouncement{% endif %}">
{% if thread.lastPost.poster.id %}
<a href="{{ route('user.profile', thread.lastPost.poster.id) }}" class="default" style="color: {{ thread.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if thread.lastPost.poster.colour != 'inherit' %}{{ thread.lastPost.poster.colour }}{% else %}#222{% endif %};">{{ thread.lastPost.poster.username }}</a>
<td class="topicLast{% if topic.type == 2 %} topicAnnouncement{% endif %}">
{% if topic.lastPost.poster.id %}
<a href="{{ route('user.profile', topic.lastPost.poster.id) }}" class="default" style="color: {{ topic.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if topic.lastPost.poster.colour != 'inherit' %}{{ topic.lastPost.poster.colour }}{% else %}#222{% endif %};">{{ topic.lastPost.poster.username }}</a>
{% else %}
[deleted user]
{% endif %} <a href="{{ route('forums.post', thread.lastPost.id) }}" class="default fa fa-tag"></a><br>
<time datetime="{{ thread.lastPost.time|date('r') }}">{{ thread.lastPost.time|date('D Y-m-d H:i:s T') }}</time>
{% 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>
</td>
</tr>

View file

@ -7,17 +7,17 @@
{% block content %}
<div class="content homepage forum">
<div class="content-right content-column">
<div id="forumIndexPopularThreads">
<div class="head">Popular threads</div>
<div id="forumIndexPopularTopics">
<div class="head">Popular topics</div>
<table class="panelTable" style="border-spacing: 0;">
<tr>
<th>Title</th>
<th>Last reply</th>
</tr>
{% for _t in activeThreads %}
{% for _t in activeTopics %}
<tr {% if _t.unread(user.id) %}style="font-weight: bold;"{% endif %}>
<td style="text-align: left; border-bottom: 1px solid #9475b2;">
<a href="{{ route('forums.thread', _t.id) }}" class="default">{{ _t.title }}</a>
<a href="{{ route('forums.topic', _t.id) }}" class="default">{{ _t.title }}</a>
</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>
</tr>

View file

@ -2,12 +2,12 @@
{% set forumBackLink %}{{ route('forums.forum', forum.id) }}{% endset %}
{% block title %}{% if thread is defined %}{{ thread.title }}{% else %}Creating thread in {{ forum.name }}{% endif %}{% endblock %}
{% block title %}{% if topic is defined %}{{ topic.title }}{% else %}Creating topic in {{ forum.name }}{% endif %}{% endblock %}
{% if thread is defined %}
{% if topic is defined %}
{% if forum.permission(constant('Sakura\\Perms\\Forum::REPLY'), user.id)
and (
thread.status != 1
topic.status != 1
or forum.permission(constant('Sakura\\Perms\\Forum::LOCK'), user.id)
) %}
{% set forumReplyLink %}#reply{% endset %}
@ -22,37 +22,37 @@
{% endif %}
{% if forum.permission(constant('Sakura\\Perms\\Forum::STICKY'), user.id) %}
{% set forumSticky = thread.type == 1 ? true : false %}
{% set forumSticky = topic.type == 1 ? true : false %}
{% endif %}
{% if forum.permission(constant('Sakura\\Perms\\Forum::ANNOUNCEMENT'), user.id) %}
{% set forumAnnounce = thread.type == 2 ? true : false %}
{% set forumAnnounce = topic.type == 2 ? true : false %}
{% endif %}
{% if forum.permission(constant('Sakura\\Perms\\Forum::LOCK'), user.id) %}
{% set forumLock = thread.status == 1 ? true : false %}
{% set forumLock = topic.status == 1 ? true : false %}
{% endif %}
{% if forum.permission(constant('Sakura\\Perms\\Forum::MOVE'), user.id) %}
{% if thread.oldForum %}
{% if topic.oldForum %}
{% set forumRestore = true %}
{% endif %}
{% if thread.forum != config('forum_trash_id') %}
{% if topic.forum != config('forum_trash_id') %}
{% set forumTrash = true %}
{% endif %}
{% endif %}
{% if forum.permission(constant('Sakura\\Perms\\Forum::DELETE_ANY'), user.id) %}
{% if thread.forum == config('forum_trash_id') %}
{% if topic.forum == config('forum_trash_id') %}
{% set forumPrune = true %}
{% endif %}
{% endif %}
{% set posts = thread.posts|batch(10) %}
{% set posts = topic.posts|batch(10) %}
{% set paginationPages = posts %}
{% set paginationUrl %}{{ route('forums.thread', thread.id) }}{% endset %}
{% set paginationUrl %}{{ route('forums.topic', topic.id) }}{% endset %}
{% endif %}
{% block css %}
@ -69,12 +69,12 @@
{% block content %}
<div class="content homepage forum viewtopic">
<div class="content-column">
<div class="head">{{ forum.name }} / <span id="threadTitle">{{ thread.title }}</span></div>
<div class="head">{{ forum.name }} / <span id="topicTitle">{{ topic.title }}</span></div>
{% include 'forum/elements/forumBtns.twig' %}
<table class="posts">
{% if thread is defined %}
{% set textCache = session.replyText['t' ~ thread.id] %}
{% set postingAction = route('forums.thread.reply', thread.id) %}
{% if topic is defined %}
{% set textCache = session.replyText['t' ~ topic.id] %}
{% set postingAction = route('forums.topic.reply', topic.id) %}
{% for post in posts[get.page|default(1) - 1] %}
<tr class="post" id="p{{ post.id }}">
@ -86,7 +86,7 @@
{% endif %}
<div class="userdata">
<div class="usertitle">{{ post.poster.title }}</div>
<img src="/images/tenshi.png" alt="Tenshi"{% if not post.poster.isPremium %} style="opacity: 0;"{% endif %}> <img src="/images/flags/{{ post.poster.country|lower }}.png" alt="{{ post.poster.country(true) }}">{% if post.poster.id == (thread.posts|first).poster.id %} <img src="/images/op.png" alt="OP" title="Original Poster">{% endif %}
<img src="/images/tenshi.png" alt="Tenshi"{% if not post.poster.isPremium %} style="opacity: 0;"{% endif %}> <img src="/images/flags/{{ post.poster.country|lower }}.png" alt="{{ post.poster.country(true) }}">{% if post.poster.id == (topic.posts|first).poster.id %} <img src="/images/op.png" alt="OP" title="Original Poster">{% endif %}
{% if user.isActive %}
<div class="actions">
{% if (user.id == post.poster.id and forum.permission(constant('Sakura\\Perms\\Forum::EDIT_OWN'), user.id)) or forum.permission(constant('Sakura\\Perms\\Forum::EDIT_ANY'), user.id) %}
@ -132,19 +132,19 @@
{% set textCache = session.replyText['f' ~ forum.id].text %}
{% set postingAction = route('forums.new', forum.id) %}
{% endif %}
{% if forumReplyLink is defined or thread is not defined %}
{% if forumReplyLink is defined or topic is not defined %}
<tr class="post" id="postingPreview" style="display: none;">
<td class="userpanel">
<a class="default username" href="{{ route('user.profile', user.id) }}" style="color: {{ user.colour }}; text-shadow: 0 0 5px {% if user.colour != 'inherit' %}{{ user.colour }}{% else %}#222{% endif %};" title="Go to {{ user.username }}'s profile">{{ user.username }}</a>
<img src="{{ route('file.avatar', user.id) }}" alt="{{ user.username }}" class="avatar" style="box-shadow: 0 3px 7px #484;">
<div class="userdata">
<div class="usertitle">{{ user.title }}</div>
<img src="/images/tenshi.png" alt="Tenshi"{% if not user.isPremium %} style="opacity: 0;"{% endif %}> <img src="/images/flags/{{ user.country|lower }}.png" alt="{{ user.country(true) }}">{% if user.id == (thread.posts|first).poster.id %} <img src="/images/op.png" alt="OP" title="Original Poster">{% endif %}
<img src="/images/tenshi.png" alt="Tenshi"{% if not user.isPremium %} style="opacity: 0;"{% endif %}> <img src="/images/flags/{{ user.country|lower }}.png" alt="{{ user.country(true) }}">{% if user.id == (topic.posts|first).poster.id %} <img src="/images/op.png" alt="OP" title="Original Poster">{% endif %}
</div>
</td>
<td class="post-content">
<div class="details">
<div class="subject" id="previewTitle">{% if titleCache is not defined %}Re: {{ thread.title }}{% endif %}</div>
<div class="subject" id="previewTitle">{% if titleCache is not defined %}Re: {{ topic.title }}{% endif %}</div>
<div class="date" id="previewMode">Preview</div>
<div class="clear"></div>
</div>
@ -159,7 +159,7 @@
</tr>
{% endif %}
</table>
{% if forumReplyLink is defined or thread is not defined %}
{% if forumReplyLink is defined or topic is not defined %}
{% include 'forum/elements/replyForm.twig' %}
{% endif %}
{% include 'forum/elements/forumBtns.twig' %}

View file

@ -16,7 +16,7 @@
{% if eligible %}
<div class="profile-field">
<div><h2>Username</h2></div>
<div><input type="text" name="username" placeholder="Enter your new username (at least {{ config('username_min_length') }} and at most {{ config('username_max_length') }} characters!)" class="inputStyling"></div>
<div><input type="text" name="username" placeholder="Enter your new username (at least {{ config('user.name_min') }} and at most {{ config('user.name_max') }} characters!)" class="inputStyling"></div>
</div>
<div class="profile-save">
<button value="{{ session_id() }}" name="session" class="inputStyling">Save</button>

View file

@ -3,12 +3,12 @@
{% set mode = 'Avatar' %}
{% block description %}
<p>Maximum image size is {{ config('avatar_max_width') }}x{{ config('avatar_max_height') }}, minimum image size is {{ config('avatar_min_width') }}x{{ config('avatar_min_height') }}, maximum file size is {{ config('avatar_max_fsize')|byte_symbol }}.</p>
<p>Maximum image size is {{ config('file.avatar.max_width') }}x{{ config('file.avatar.max_height') }} and can't be larger than {{ config('file.avatar.max_file_size')|byte_symbol }}.</p>
{% endblock %}
{% block settingsContent %}
<form enctype="multipart/form-data" method="post" action="{{ route('settings.appearance.avatar') }}">
<input type="hidden" name="MAX_FILE_SIZE" value="{{ config('avatar_max_fsize') }}">
<input type="hidden" name="MAX_FILE_SIZE" value="{{ config('file.avatar.max_file_size') }}">
<div style="text-align: center;">
<div>
<img src="{{ route('file.avatar', user.id) }}" alt="Your Avatar" class="default-avatar-setting">

View file

@ -3,12 +3,12 @@
{% set mode = 'Background' %}
{% block description %}
<p>Maximum image size is {{ config('background_max_width') }}x{{ config('background_max_height') }}, minimum image size is {{ config('background_min_width') }}x{{ config('background_min_height') }}, maximum file size is {{ config('background_max_fsize')|byte_symbol }}.</p>
<p>Maximum image size is {{ config('file.background.max_width') }}x{{ config('file.background.max_height') }} and can't be larger than {{ config('file.background.max_file_size')|byte_symbol }}.</p>
{% endblock %}
{% block settingsContent %}
<form enctype="multipart/form-data" method="post" action="{{ route('settings.appearance.background') }}">
<input type="hidden" name="MAX_FILE_SIZE" value="{{ config('background_max_fsize') }}">
<input type="hidden" name="MAX_FILE_SIZE" value="{{ config('file.background.max_file_size') }}">
<div style="text-align: center;">
<div>
<img src="{{ route('file.background', user.id) }}" alt="Your Background" class="default-avatar-setting" style="max-width: 90%; max-height: 90%;">

View file

@ -3,12 +3,12 @@
{% set mode = 'Header' %}
{% block description %}
<p>Maximum image size is {{ config('header_max_width') }}x{{ config('header_max_height') }}, minimum image size is {{ config('header_min_width') }}x{{ config('header_min_height') }}, maximum file size is {{ config('header_max_fsize')|byte_symbol }}.</p>
<p>Maximum image size is {{ config('file.cover.max_width') }}x{{ config('file.cover.max_height') }} and can't be larger than {{ config('file.cover.max_file_size')|byte_symbol }}.</p>
{% endblock %}
{% block settingsContent %}
<form enctype="multipart/form-data" method="post" action="{{ route('settings.appearance.header') }}">
<input type="hidden" name="MAX_FILE_SIZE" value="{{ config('header_max_fsize') }}">
<input type="hidden" name="MAX_FILE_SIZE" value="{{ config('file.cover.max_file_size') }}">
<div style="text-align: center;">
<div>
<img src="{{ route('user.header', user.id) }}" alt="Your Header" class="default-avatar-setting" style="max-width: 90%; max-height: 90%;">

View file

@ -99,7 +99,7 @@
{% for user in users[currPage] %}
<a href="{{ route('user.profile', user.id) }}">{# These comment tags are here to prevent the link extending too far
#}<div class="userBox" id="u{{ user.id }}">{#
#}<img src="/pixel.png" alt="{{ user.username }}" style="background: url('{{ route('file.avatar', user.id) }}') no-repeat center / contain;">{#
#}<img src="/images/pixel.png" alt="{{ user.username }}" style="background: url('{{ route('file.avatar', user.id) }}') no-repeat center / contain;">{#
#}<span class="userBoxUserName" style="color: {{ user.colour }};">{#
#}{{ user.username }}{#
#}</span>{#

View file

@ -102,7 +102,7 @@
{% if not noUserpage %}
<a class="fa fa-file-text-o" title="View {{ profile.username }}'s user page" href="#_userpage" onclick="profileMode('userpage');"></a>
{% endif %}
{#<a class="fa fa-list" title="View {{ profile.username }}'s threads" href="#_threads" onclick="profileMode('threads');"></a>
{#<a class="fa fa-list" title="View {{ profile.username }}'s topics" href="#_topics" onclick="profileMode('topics');"></a>
<a class="fa fa-reply" title="View {{ profile.username }}'s posts" href="#_posts" onclick="profileMode('posts');"></a>#}
<a class="fa fa-star" title="View {{ profile.username }}'s friends" href="#_friends" onclick="profileMode('friends');"></a>
{#<a class="fa fa-users" title="View {{ profile.username }}'s groups" href="#_groups" onclick="profileMode('groups');"></a>#}
@ -135,8 +135,8 @@
<div id="profile-mode-groups" class="hidden">
{% include 'profile/groups.twig' %}
</div>
<div id="profile-mode-threads" class="hidden">
{% include 'profile/threads.twig' %}
<div id="profile-mode-topics" class="hidden">
{% include 'profile/topics.twig' %}
</div>
<div id="profile-mode-posts" class="hidden">
{% include 'profile/posts.twig' %}
@ -148,7 +148,7 @@
<div class="new-profile-data">
<table style="width: 100%;">
<tr>
<td style="text-align: left; font-weight: bold;">Threads</td>
<td style="text-align: left; font-weight: bold;">Topics</td>
<td style="text-align: right;">{{ profile.forumStats.topics }}</td>
</tr>
<tr>

View file

@ -86,11 +86,11 @@ Router::group(['before' => 'maintenance'], function () {
});
});
// Thread
Router::group(['prefix' => 'thread'], function () {
Router::get('/{id:i}', 'ForumController@thread', 'forums.thread');
Router::post('/{id:i}/mod', 'ForumController@threadModerate', 'forums.thread.mod');
Router::post('/{id:i}/reply', 'ForumController@threadReply', 'forums.thread.reply');
// Topic
Router::group(['prefix' => 'topic'], function () {
Router::get('/{id:i}', 'ForumController@topic', 'forums.topic');
Router::post('/{id:i}/mod', 'ForumController@topicModerate', 'forums.topic.mod');
Router::post('/{id:i}/reply', 'ForumController@topicReply', 'forums.topic.reply');
});
// Forum
@ -98,8 +98,8 @@ Router::group(['before' => 'maintenance'], function () {
Router::get('/{id:i}', 'ForumController@forum', 'forums.forum');
Router::group(['before' => 'loginCheck'], function () {
Router::get('/{id:i}/mark', 'ForumController@markForumRead', 'forums.mark');
Router::get('/{id:i}/new', 'ForumController@createThread', 'forums.new');
Router::post('/{id:i}/new', 'ForumController@createThread', 'forums.new');
Router::get('/{id:i}/new', 'ForumController@createTopic', 'forums.new');
Router::post('/{id:i}/new', 'ForumController@createTopic', 'forums.new');
});
});

View file

@ -7,7 +7,7 @@
namespace Sakura;
// Define version and root path
define('SAKURA_VERSION', 20160726);
define('SAKURA_VERSION', 20160730);
define('ROOT', __DIR__ . '/');
// CLI mode
@ -69,6 +69,6 @@ if (!defined('IN_CLI')) {
'post' => $_POST,
'server' => $_SERVER,
'request' => $_REQUEST,
//'session' => $_SESSION,
'session' => $_SESSION,
]);
}