Work a bit on subforum viewing/thread listing
This commit is contained in:
parent
45343a87fd
commit
fd585edc80
|
@ -10,6 +10,7 @@
|
||||||
"CharmBoard",
|
"CharmBoard",
|
||||||
"Facepunch",
|
"Facepunch",
|
||||||
"listsubf",
|
"listsubf",
|
||||||
|
"origp",
|
||||||
"passchk",
|
"passchk",
|
||||||
"passgen",
|
"passgen",
|
||||||
"pgsql",
|
"pgsql",
|
||||||
|
@ -54,5 +55,14 @@
|
||||||
"perl-toolbox.lint.useProfile": true,
|
"perl-toolbox.lint.useProfile": true,
|
||||||
"perl-toolbox.syntax.includePaths": [
|
"perl-toolbox.syntax.includePaths": [
|
||||||
"$workspaceRoot/libs"
|
"$workspaceRoot/libs"
|
||||||
]
|
],
|
||||||
|
"sqltools.connections": [
|
||||||
|
{
|
||||||
|
"previewLimit": 50,
|
||||||
|
"driver": "SQLite",
|
||||||
|
"name": "CharmBoard",
|
||||||
|
"database": "${workspaceFolder:CharmBoard}/charmboard.db"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sqltools.useNodeRuntime": true
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
board_name => '',
|
board_name => '',
|
||||||
|
board_root => '', # this doesn't do anything yet
|
||||||
|
|
||||||
database => {
|
database => {
|
||||||
type => '', # 'sqlite' or 'mariadb'
|
type => '', # 'sqlite' or 'mariadb'
|
||||||
|
|
53
database.sql
53
database.sql
|
@ -1,5 +1,5 @@
|
||||||
--
|
--
|
||||||
-- File generated with SQLiteStudio v3.4.4 on Mon. May 8 03:12:22 2023
|
-- File generated with SQLiteStudio v3.4.4 on Tue. May 16 22:16:54 2023
|
||||||
--
|
--
|
||||||
-- Text encoding used: UTF-8
|
-- Text encoding used: UTF-8
|
||||||
--
|
--
|
||||||
|
@ -8,43 +8,14 @@ BEGIN TRANSACTION;
|
||||||
|
|
||||||
-- Table: categories
|
-- Table: categories
|
||||||
DROP TABLE IF EXISTS categories;
|
DROP TABLE IF EXISTS categories;
|
||||||
|
CREATE TABLE categories (cat_id INTEGER NOT NULL ON CONFLICT ROLLBACK UNIQUE ON CONFLICT ROLLBACK, cat_rank INTEGER NOT NULL, cat_name TEXT, PRIMARY KEY (cat_id AUTOINCREMENT));
|
||||||
CREATE TABLE categories (
|
|
||||||
cat_id INTEGER NOT NULL ON CONFLICT ROLLBACK
|
|
||||||
UNIQUE ON CONFLICT ROLLBACK,
|
|
||||||
cat_name TEXT,
|
|
||||||
PRIMARY KEY (
|
|
||||||
cat_id AUTOINCREMENT
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
-- Table: posts
|
-- Table: posts
|
||||||
DROP TABLE IF EXISTS posts;
|
DROP TABLE IF EXISTS posts;
|
||||||
|
CREATE TABLE posts (post_id INTEGER NOT NULL ON CONFLICT ROLLBACK UNIQUE ON CONFLICT ROLLBACK, user_id INTEGER NOT NULL ON CONFLICT ROLLBACK, thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK, post_date INTEGER NOT NULL ON CONFLICT ROLLBACK, post_body TEXT NOT NULL, PRIMARY KEY (post_id AUTOINCREMENT), FOREIGN KEY (user_id) REFERENCES users (user_id), FOREIGN KEY (thread_id) REFERENCES threads (thread_id));
|
||||||
CREATE TABLE posts (
|
|
||||||
post_id INTEGER NOT NULL ON CONFLICT ROLLBACK
|
|
||||||
UNIQUE ON CONFLICT ROLLBACK,
|
|
||||||
user_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
|
|
||||||
thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
|
|
||||||
post_date INTEGER NOT NULL ON CONFLICT ROLLBACK,
|
|
||||||
PRIMARY KEY (
|
|
||||||
post_id AUTOINCREMENT
|
|
||||||
),
|
|
||||||
FOREIGN KEY (
|
|
||||||
user_id
|
|
||||||
)
|
|
||||||
REFERENCES users (user_id),
|
|
||||||
FOREIGN KEY (
|
|
||||||
thread_id
|
|
||||||
)
|
|
||||||
REFERENCES threads (thread_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
-- Table: sessions
|
-- Table: sessions
|
||||||
DROP TABLE IF EXISTS sessions;
|
DROP TABLE IF EXISTS sessions;
|
||||||
|
|
||||||
CREATE TABLE sessions (
|
CREATE TABLE sessions (
|
||||||
session_key TEXT NOT NULL
|
session_key TEXT NOT NULL
|
||||||
UNIQUE
|
UNIQUE
|
||||||
|
@ -57,25 +28,12 @@ CREATE TABLE sessions (
|
||||||
bound_ip TEXT
|
bound_ip TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
-- Table: subforums
|
-- Table: subforums
|
||||||
DROP TABLE IF EXISTS subforums;
|
DROP TABLE IF EXISTS subforums;
|
||||||
|
CREATE TABLE subforums (subf_id INTEGER PRIMARY KEY UNIQUE ON CONFLICT ROLLBACK NOT NULL ON CONFLICT ROLLBACK, subf_cat INTEGER REFERENCES categories (cat_id) NOT NULL, subf_rank INTEGER NOT NULL, subf_name TEXT NOT NULL ON CONFLICT ROLLBACK, subf_desc TEXT);
|
||||||
CREATE TABLE subforums (
|
|
||||||
subf_id INTEGER PRIMARY KEY
|
|
||||||
UNIQUE ON CONFLICT ROLLBACK
|
|
||||||
NOT NULL ON CONFLICT ROLLBACK,
|
|
||||||
subf_cat INTEGER REFERENCES categories (cat_id)
|
|
||||||
UNIQUE ON CONFLICT ROLLBACK
|
|
||||||
NOT NULL ON CONFLICT ROLLBACK,
|
|
||||||
subf_name TEXT NOT NULL ON CONFLICT ROLLBACK,
|
|
||||||
subf_desc
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
-- Table: threads
|
-- Table: threads
|
||||||
DROP TABLE IF EXISTS threads;
|
DROP TABLE IF EXISTS threads;
|
||||||
|
|
||||||
CREATE TABLE threads (
|
CREATE TABLE threads (
|
||||||
thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
|
thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
|
||||||
thread_title TEXT NOT NULL ON CONFLICT ROLLBACK,
|
thread_title TEXT NOT NULL ON CONFLICT ROLLBACK,
|
||||||
|
@ -85,10 +43,8 @@ CREATE TABLE threads (
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
-- Table: users
|
-- Table: users
|
||||||
DROP TABLE IF EXISTS users;
|
DROP TABLE IF EXISTS users;
|
||||||
|
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
user_id INTEGER NOT NULL ON CONFLICT ROLLBACK
|
user_id INTEGER NOT NULL ON CONFLICT ROLLBACK
|
||||||
UNIQUE ON CONFLICT ROLLBACK,
|
UNIQUE ON CONFLICT ROLLBACK,
|
||||||
|
@ -105,6 +61,5 @@ CREATE TABLE users (
|
||||||
ON CONFLICT ABORT
|
ON CONFLICT ABORT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
COMMIT TRANSACTION;
|
COMMIT TRANSACTION;
|
||||||
PRAGMA foreign_keys = on;
|
PRAGMA foreign_keys = on;
|
||||||
|
|
|
@ -20,10 +20,10 @@ sub startup {
|
||||||
{file => 'charmboard.conf'});
|
{file => 'charmboard.conf'});
|
||||||
|
|
||||||
# set this specific forum's name
|
# set this specific forum's name
|
||||||
$self->helper(boardName => sub {$config->{board_name}});
|
$self->helper(board_name => sub {$config->{board_name}});
|
||||||
|
|
||||||
# load dev env only stuff, if applicable
|
# load dev env only stuff, if applicable
|
||||||
if ( $config->{environment} eq 'dev' ) {
|
if ($config->{environment} eq 'dev') {
|
||||||
$self->plugin('Renderer::WithoutCache');
|
$self->plugin('Renderer::WithoutCache');
|
||||||
$self->renderer->cache->max_keys(0)};
|
$self->renderer->cache->max_keys(0)};
|
||||||
|
|
||||||
|
@ -31,18 +31,19 @@ sub startup {
|
||||||
$self->secrets($config->{secrets});
|
$self->secrets($config->{secrets});
|
||||||
|
|
||||||
# import password pepper value
|
# import password pepper value
|
||||||
$self->helper(pepper => sub {$config->{pass_crypt}->{pepper}});
|
$self->helper(
|
||||||
|
pepper => sub {$config->{pass_crypt}->{pepper}});
|
||||||
|
|
||||||
## database setup
|
## database setup
|
||||||
# ? this could maybe be a given/when
|
# ? this could maybe be a given/when
|
||||||
my ($dsn, $dbUnicode);
|
{ my ($_dsn, $_unicode);
|
||||||
if ($self->config->{database}->{type} ~~ 'sqlite') {
|
if ($self->config->{database}->{type} ~~ 'sqlite') {
|
||||||
$dsn = "dbi:SQLite:" . $config->{database}->{name};
|
$_dsn = "dbi:SQLite:" . $config->{database}->{name};
|
||||||
$dbUnicode = "sqlite_unicode"}
|
$_unicode = "sqlite_unicode"}
|
||||||
|
|
||||||
elsif ($self->config->{database}->{type} ~~ 'mariadb') {
|
elsif ($self->config->{database}->{type} ~~ 'mariadb') {
|
||||||
$dsn = "dbi:mysql:" . $config->{database}->{name};
|
$_dsn = "dbi:mysql:" . $config->{database}->{name};
|
||||||
$dbUnicode = "mysql_enable_utf"}
|
$_unicode = "mysql_enable_utf"}
|
||||||
|
|
||||||
else {die "\nUnknown, unsupported, or empty database type
|
else {die "\nUnknown, unsupported, or empty database type
|
||||||
in charmboard.conf. If you're sure you've set it to
|
in charmboard.conf. If you're sure you've set it to
|
||||||
|
@ -50,16 +51,22 @@ sub startup {
|
||||||
\n\n\t
|
\n\n\t
|
||||||
Valid options: 'sqlite', 'mariadb'"};
|
Valid options: 'sqlite', 'mariadb'"};
|
||||||
|
|
||||||
my $schema = CharmBoard::Schema->connect(
|
our $schema = CharmBoard::Schema->connect(
|
||||||
$dsn,
|
$_dsn,
|
||||||
$config->{database}->{user},
|
$config->{database}->{user},
|
||||||
$config->{database}->{pass},
|
$config->{database}->{pass},
|
||||||
{$dbUnicode => 1});
|
{$_unicode => 1});
|
||||||
$self->helper(schema => sub {$schema});
|
|
||||||
|
$self->helper(schema => sub {$schema})}
|
||||||
|
|
||||||
# router
|
# router
|
||||||
my $r = $self->routes;
|
my $r = $self->routes;
|
||||||
|
|
||||||
|
# view subforum
|
||||||
|
$r->get('/subforum/:id')->to(
|
||||||
|
controller => 'Controller::ViewSubf',
|
||||||
|
action => 'subf_view');
|
||||||
|
|
||||||
# controller routes
|
# controller routes
|
||||||
## index page
|
## index page
|
||||||
$r->get('/')->to(
|
$r->get('/')->to(
|
||||||
|
@ -89,5 +96,24 @@ sub startup {
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=head1 NAME
|
||||||
|
CharmBoard - revive the fun posting experience!
|
||||||
|
|
||||||
|
=head1 NOTES
|
||||||
|
This documentation is intended for prospective code
|
||||||
|
contributors. If you're looking to set CharmBoard up,
|
||||||
|
look for the Markdown format (.md) documentation instead.
|
||||||
|
|
||||||
|
CharmBoard uses a max line length of 60 chars and a tab
|
||||||
|
size of two spaces.
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
CharmBoard is forum software written in Perl with
|
||||||
|
Mojolicious, intended to be a more fun alternative to the
|
||||||
|
bigger forum suites available today, inspired by older
|
||||||
|
forum software like AcmlmBoard, while also being more
|
||||||
|
modernized in terms of security practices than they are.
|
||||||
|
=cut
|
||||||
|
|
|
@ -12,34 +12,34 @@ sub index {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
# fetch a list of all categories
|
# fetch a list of all categories
|
||||||
my @allCat =
|
my @all_cat =
|
||||||
$self->schema->resultset('Categories')->fetch_all;
|
$self->schema->resultset('Categories')->fetch_all;
|
||||||
|
|
||||||
# create a Tree::Simple object that will contain the list
|
# create a Tree::Simple object that will contain the list
|
||||||
# of categories and the subforums that belong to them
|
# of categories and the subforums that belong to them
|
||||||
my $tree =
|
my $tree =
|
||||||
Tree::Simple->new("ROOT", Tree::Simple->ROOT);
|
Tree::Simple->new("subf_list", Tree::Simple->ROOT);
|
||||||
|
|
||||||
my (@fetchSubf, $catBranch);
|
my (@fetch_subf, $cat_branch);
|
||||||
foreach my $iterCat (@allCat) {
|
foreach my $iter_cat (@all_cat) {
|
||||||
# create branch of ROOT for the current category
|
# create branch of subf_list for the current category
|
||||||
|
|
||||||
$catBranch =
|
$cat_branch =
|
||||||
Tree::Simple->new($iterCat, $tree);
|
Tree::Simple->new($iter_cat, $tree);
|
||||||
|
|
||||||
# fetch all subforums that belong to this category
|
# fetch all subforums that belong to this category
|
||||||
@fetchSubf =
|
@fetch_subf =
|
||||||
$self->schema->resultset('Subforums')
|
$self->schema->resultset('Subforums')
|
||||||
->fetch_by_cat($iterCat);
|
->fetch_by_cat($iter_cat);
|
||||||
|
|
||||||
# add each fetched subforum as children of the branch
|
# add each fetched subforum as children of the branch
|
||||||
# for the current category
|
# for the current category
|
||||||
foreach my $iterSubf (@fetchSubf) {
|
foreach my $iter_subf (@fetch_subf) {
|
||||||
Tree::Simple->new($iterSubf, $catBranch)}}
|
Tree::Simple->new($iter_subf, $cat_branch)}}
|
||||||
|
|
||||||
$self->render(
|
$self->render(
|
||||||
template => 'index',
|
template => 'index',
|
||||||
categoryTree => $tree)}
|
category_tree => $tree)}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
|
@ -22,54 +22,54 @@ sub login_do {
|
||||||
my $username = $self->param('username');
|
my $username = $self->param('username');
|
||||||
my $password = $self->pepper . ':' . $self->param('password');
|
my $password = $self->pepper . ':' . $self->param('password');
|
||||||
|
|
||||||
my $catchError;
|
my $catch_error;
|
||||||
|
|
||||||
# declare vars used through multiple try/catch blocks with
|
# declare vars used through multiple try/catch blocks with
|
||||||
# 'our' so they work throughout the entire subroutine
|
# 'our' so they work throughout the entire subroutine
|
||||||
our ($userInfo, $passCheck, $userID, $sessionKey);
|
our ($user_info, $pass_check, $user_id, $session_key);
|
||||||
|
|
||||||
try { # check user credentials first
|
try { # check user credentials first
|
||||||
# check to see if user by entered username exists
|
# check to see if user by entered username exists
|
||||||
$userInfo = $self->schema->resultset('Users')->search(
|
$user_info = $self->schema->resultset('Users')->search(
|
||||||
{username => $username});
|
{username => $username});
|
||||||
$userInfo or die;
|
$user_info or die;
|
||||||
|
|
||||||
# now check password validity
|
# now check password validity
|
||||||
$passCheck = passchk($userInfo->get_column('salt')->first,
|
$pass_check = passchk($user_info->get_column('salt')->first,
|
||||||
$userInfo->get_column('password')->first, $password);
|
$user_info->get_column('password')->first, $password);
|
||||||
$passCheck or die;}
|
$pass_check or die;}
|
||||||
|
|
||||||
catch ($catchError) { # redirect to login page on fail
|
catch ($catch_error) { # redirect to login page on fail
|
||||||
print $catchError;
|
print $catch_error;
|
||||||
$self->flash(error => 'Username or password incorrect.');
|
$self->flash(error => 'Username or password incorrect.');
|
||||||
$self->redirect_to('login');}
|
$self->redirect_to('login');}
|
||||||
|
|
||||||
try { # now attempt to create session
|
try { # now attempt to create session
|
||||||
# get user ID for session creation
|
# get user ID for session creation
|
||||||
$userID = $userInfo->get_column('user_id')->first;
|
$user_id = $user_info->get_column('user_id')->first;
|
||||||
|
|
||||||
# gen session key
|
# gen session key
|
||||||
$sessionKey = seasoning(16);
|
$session_key = seasoning(16);
|
||||||
|
|
||||||
# add session to database
|
# add session to database
|
||||||
$self->schema->resultset('Session')->create({
|
$self->schema->resultset('Session')->create({
|
||||||
session_key => $sessionKey,
|
session_key => $session_key,
|
||||||
user_id => $userID,
|
user_id => $user_id,
|
||||||
session_expiry => time + 604800,
|
session_expiry => time + 604800,
|
||||||
is_ip_bound => 0,
|
is_ip_bound => 0,
|
||||||
bound_ip => undef }) or die;
|
bound_ip => undef }) or die;
|
||||||
|
|
||||||
# now create session cookie for user
|
# now create session cookie for user
|
||||||
$self->session(is_auth => 1);
|
$self->session(is_auth => 1);
|
||||||
$self->session(user_id => $userID);
|
$self->session(user_id => $user_id);
|
||||||
$self->session(session_key => $sessionKey);
|
$self->session(session_key => $session_key);
|
||||||
$self->session(expiration => 604800);
|
$self->session(expiration => 604800);
|
||||||
|
|
||||||
# redirect to index upon success
|
# redirect to index upon success
|
||||||
$self->redirect_to('/')}
|
$self->redirect_to('/')}
|
||||||
|
|
||||||
catch ($catchError) { # redirect to login page on fail
|
catch ($catch_error) { # redirect to login page on fail
|
||||||
print $catchError;
|
print $catch_error;
|
||||||
$self->flash(error => 'Your username and password were correct,
|
$self->flash(error => 'Your username and password were correct,
|
||||||
but a server error prevented you from logging in. This has been
|
but a server error prevented you from logging in. This has been
|
||||||
logged so the administrator can fix it.');
|
logged so the administrator can fix it.');
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package CharmBoard::Controller::ViewSubf;
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use experimental qw(try smartmatch);
|
||||||
|
|
||||||
|
use Mojo::Base 'Mojolicious::Controller', -signatures;
|
||||||
|
|
||||||
|
sub subf_view {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my $subf_id = $self->param('id');
|
||||||
|
my $subf_cat =
|
||||||
|
$self->schema->resultset('Subforums')->cat_from_id($subf_id);
|
||||||
|
my $cat_title =
|
||||||
|
$self->schema->resultset('Categories')
|
||||||
|
->title_from_id($subf_cat);
|
||||||
|
|
||||||
|
my @thread_list =
|
||||||
|
$self->schema->resultset('Threads')->fetch_by_subf($subf_id);
|
||||||
|
|
||||||
|
$self->render(
|
||||||
|
template => 'subf',
|
||||||
|
subf_id => $subf_id,
|
||||||
|
cat_title => $cat_title,
|
||||||
|
subf_title =>
|
||||||
|
$self->schema->resultset('Subforums')
|
||||||
|
->title_from_id($subf_id),
|
||||||
|
thread_list => \@thread_list)}
|
||||||
|
|
||||||
|
1;
|
|
@ -8,21 +8,29 @@ use experimental qw(try smartmatch);
|
||||||
use base 'DBIx::Class::ResultSet';
|
use base 'DBIx::Class::ResultSet';
|
||||||
|
|
||||||
sub fetch_all {
|
sub fetch_all {
|
||||||
my $set = shift;
|
my $_set = shift;
|
||||||
|
|
||||||
my $_fetch =
|
my $_fetch =
|
||||||
$set->search({},
|
$_set->search({},
|
||||||
{order_by => 'cat_rank'});
|
{order_by => 'cat_rank'});
|
||||||
|
|
||||||
return($_fetch->get_column('cat_id')->all)}
|
return($_fetch->get_column('cat_id')->all)}
|
||||||
|
|
||||||
sub title_from_id {
|
sub title_from_id {
|
||||||
my $set = shift;
|
my $_set = shift;
|
||||||
|
|
||||||
return(
|
return(
|
||||||
$set->search({'cat_id' => $_[0]})->
|
$_set->search({'cat_id' => $_[0]})->
|
||||||
get_column('cat_name')->first)}
|
get_column('cat_name')->first)}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
=pod
|
||||||
|
=head1 NAME
|
||||||
|
CharmBoard::Schema::Set::Categories - DBIC ResultSet for
|
||||||
|
the categories table
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
=cut
|
|
@ -8,20 +8,27 @@ use experimental qw(try smartmatch);
|
||||||
use base 'DBIx::Class::ResultSet';
|
use base 'DBIx::Class::ResultSet';
|
||||||
|
|
||||||
sub fetch_by_cat {
|
sub fetch_by_cat {
|
||||||
my $set = shift;
|
my $_set = shift;
|
||||||
|
|
||||||
my $fetch =
|
my $_fetch =
|
||||||
$set->search(
|
$_set->search(
|
||||||
{'subf_cat' => $_[0] },
|
{'subf_cat' => $_[0] },
|
||||||
{order_by => 'subf_rank'});
|
{order_by => 'subf_rank'});
|
||||||
|
|
||||||
return($fetch->get_column('subf_id')->all)}
|
return($_fetch->get_column('subf_id')->all)}
|
||||||
|
|
||||||
sub title_from_id {
|
sub cat_from_id {
|
||||||
my $set = shift;
|
my $_set = shift;
|
||||||
|
|
||||||
return(
|
return(
|
||||||
$set->search({'subf_id' => $_[0]})->
|
$_set->search({'subf_id' => $_[0]})->
|
||||||
|
get_column('subf_cat')->first)}
|
||||||
|
|
||||||
|
sub title_from_id {
|
||||||
|
my $_set = shift;
|
||||||
|
|
||||||
|
return(
|
||||||
|
$_set->search({'subf_id' => $_[0]})->
|
||||||
get_column('subf_name')->first)}
|
get_column('subf_name')->first)}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package CharmBoard::Schema::Set::Threads;
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use experimental qw(try smartmatch);
|
||||||
|
|
||||||
|
use base 'DBIx::Class::ResultSet';
|
||||||
|
|
||||||
|
sub fetch_by_subf {
|
||||||
|
my $_set = shift;
|
||||||
|
|
||||||
|
my $_fetch =
|
||||||
|
$_set->search({'thread_subf' => $_[0]});
|
||||||
|
|
||||||
|
return($_fetch->get_column('thread_id')->all)}
|
||||||
|
|
||||||
|
sub title_from_id {
|
||||||
|
my $_set = shift;
|
||||||
|
|
||||||
|
return(
|
||||||
|
$_set->search({'thread_id' => $_[0]})->
|
||||||
|
get_column('thread_title')->first)}
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
|
@ -16,6 +16,10 @@ __PACKAGE__->add_columns(
|
||||||
thread_title => {
|
thread_title => {
|
||||||
data_type => 'text',
|
data_type => 'text',
|
||||||
is_nullable => 0, },
|
is_nullable => 0, },
|
||||||
|
thread_op => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_foreign_key => 1,
|
||||||
|
is_nullable => 0, },
|
||||||
thread_subf => {
|
thread_subf => {
|
||||||
data_type => 'integer',
|
data_type => 'integer',
|
||||||
is_foreign_key => 1,
|
is_foreign_key => 1,
|
||||||
|
@ -27,6 +31,9 @@ __PACKAGE__->belongs_to(
|
||||||
thread_subf =>
|
thread_subf =>
|
||||||
'CharmBoard::Schema::Source::Subforums',
|
'CharmBoard::Schema::Source::Subforums',
|
||||||
{'foreign.subf_id' => 'self.thread_subf'});
|
{'foreign.subf_id' => 'self.thread_subf'});
|
||||||
|
__PACKAGE__->belongs_to(
|
||||||
|
thread_op => 'CharmBoard::Schema::Source::Posts',
|
||||||
|
{'foreign.post_id' => 'self.thread_op'});
|
||||||
|
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
|
@ -14,25 +14,4 @@ Mojolicious::Commands->start_app('CharmBoard');
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
=pod
|
|
||||||
=head1 NAME
|
|
||||||
CharmBoard - revive the fun posting experience!
|
|
||||||
|
|
||||||
=head1 NOTES
|
|
||||||
This documentation is intended for prospective code
|
|
||||||
contributors. If you're looking to set CharmBoard up,
|
|
||||||
look for the Markdown format (.md) documentation instead.
|
|
||||||
|
|
||||||
CharmBoard uses a max line length of 60 chars and a tab
|
|
||||||
size of two spaces.
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
CharmBoard is forum software written in Perl with
|
|
||||||
Mojolicious, intended to be a more fun alternative to the
|
|
||||||
bigger forum suites available today, inspired by older
|
|
||||||
forum software like AcmlmBoard, while also being more
|
|
||||||
modernized in terms of security practices than they are.
|
|
||||||
Customization ability is another important goal next to
|
|
||||||
making software that feels fun for the end user to use.
|
|
||||||
=cut
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,30 @@
|
||||||
% layout 'default', title => $self->boardName;
|
% layout 'default', title => $self->board_name;
|
||||||
|
|
||||||
<% my $catHeader = begin %>
|
<% my $cat_header = begin %>
|
||||||
% my $_catID = shift; my $_name = shift;
|
% my $_cat_id = shift; my $_name = shift;
|
||||||
<div class="category-header category-<%= $_catID %>">
|
<div class="category-header category-<%= $_cat_id %>">
|
||||||
<b><%= $_name %></b>
|
<b><%= $_name %></b>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% my $subfItem = begin %>
|
<% my $subf_item = begin %>
|
||||||
% my $_subfID = shift; my $_catID = shift;
|
% my $_subf_id = shift; my $_cat_id = shift;
|
||||||
% my $_name = shift;
|
% my $_name = shift;
|
||||||
<div class="
|
<div class="
|
||||||
subforum-item subforum-<%= $_subfID %>
|
subforum-item subforum-<%= $_subf_id %>
|
||||||
category-<%= $_catID %>
|
category-<%= $_cat_id %>
|
||||||
"><%= $_name %></div>
|
"><a href="/subforum/<%= $_subf_id %>"><%= $_name %></a></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%
|
<%
|
||||||
foreach my $category ($categoryTree->getAllChildren) { %>
|
foreach my $category ($category_tree->getAllChildren) { %>
|
||||||
<%= $catHeader->(
|
<%= $cat_header->(
|
||||||
$category->getNodeValue,
|
$category->getNodeValue,
|
||||||
$self->schema->resultset('Categories')->
|
$self->schema->resultset('Categories')->
|
||||||
title_from_id($category->getNodeValue)) %>
|
title_from_id($category->getNodeValue)) %>
|
||||||
<% say ('$category: ' . $category); %>
|
|
||||||
<%
|
<%
|
||||||
foreach my $subforum ($category->getAllChildren) { %>
|
foreach my $subforum ($category->getAllChildren) { %>
|
||||||
<%= $subfItem->(
|
<%= $subf_item->(
|
||||||
$subforum->getNodeValue,
|
$subforum->getNodeValue,
|
||||||
$category->getNodeValue,
|
$category->getNodeValue,
|
||||||
$self->schema->resultset('Subforums')->
|
$self->schema->resultset('Subforums')->
|
||||||
|
|
|
@ -10,5 +10,5 @@ else {
|
||||||
"<a href=\"/login\">login</a> |
|
"<a href=\"/login\">login</a> |
|
||||||
<a href=\"/register\">register</a>"};
|
<a href=\"/register\">register</a>"};
|
||||||
%>
|
%>
|
||||||
<a href="/"><h2><%== $self->boardName %></h2></a>
|
<a href="/"><h2><%== $self->board_name %></h2></a>
|
||||||
<%== $userControls %><br /><br />
|
<%== $userControls %><br /><br />
|
|
@ -1,4 +1,4 @@
|
||||||
% layout 'default', title => $self->boardName . ' - Login';
|
% layout 'default', title => $self->board_name . ' - Login';
|
||||||
% if ($error) {
|
% if ($error) {
|
||||||
<p style="color: red"><%= $error %></p>
|
<p style="color: red"><%= $error %></p>
|
||||||
%};
|
%};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
% layout 'default', title => $self->boardName . ' - Registration';
|
% layout 'default', title => $self->board_name . ' - Registration';
|
||||||
% if ($error) {
|
% if ($error) {
|
||||||
<p style="color: red"><%= $error %></p>
|
<p style="color: red"><%= $error %></p>
|
||||||
%};
|
%};
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
% layout 'default', title => $subf_title . ' - ' . $self->board_name;
|
||||||
|
% my @thread_list = @{stash('thread_list')};
|
||||||
|
|
||||||
|
<% my $thread_item = begin %>
|
||||||
|
% my $_thread_id = shift; my $_thread_title = shift;
|
||||||
|
<div class=" thread-item thread-<%= $_thread_id %>">
|
||||||
|
<a href="/thread/<%= $_thread_id %>"></a>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<a href="/"><%= $self->board_name %></a> » <%= $cat_title %> » <%= $subf_title %>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
<% if (! @thread_list) { %>
|
||||||
|
Oops! Looks like there's no threads here yet. Maybe you'd
|
||||||
|
like to <a href="/thread/new/<%= $subf_id %>">make one?</a>
|
||||||
|
<% } else {
|
||||||
|
foreach my $thread_id (@thread_list) { %>
|
||||||
|
<%= $thread_item->(
|
||||||
|
$thread_id,
|
||||||
|
$self->schema->resultset('Threads')->
|
||||||
|
title_from_id($thread_id)) %>
|
||||||
|
<% }} %>
|
Loading…
Reference in New Issue