From fd585edc80283e2554b17cc5eb323bc5330e93e6 Mon Sep 17 00:00:00 2001 From: ngoomie Date: Tue, 16 May 2023 22:18:25 -0600 Subject: [PATCH] Work a bit on subforum viewing/thread listing --- .vscode/settings.json | 12 +++- charmboard.example.conf | 1 + database.sql | 53 ++--------------- lib/CharmBoard.pm | 70 ++++++++++++++++------- lib/CharmBoard/Controller/Index.pm | 24 ++++---- lib/CharmBoard/Controller/Login.pm | 34 +++++------ lib/CharmBoard/Controller/ViewSubf.pm | 32 +++++++++++ lib/CharmBoard/Schema/Set/Categories.pm | 18 ++++-- lib/CharmBoard/Schema/Set/Subforums.pm | 21 ++++--- lib/CharmBoard/Schema/Set/Threads.pm | 26 +++++++++ lib/CharmBoard/Schema/Source/Threads.pm | 7 +++ script/CharmBoard | 21 ------- templates/index.html.ep | 25 ++++---- templates/layouts/default/_header.html.ep | 2 +- templates/login.html.ep | 2 +- templates/register.html.ep | 2 +- templates/subf.html.ep | 23 ++++++++ 17 files changed, 223 insertions(+), 150 deletions(-) create mode 100644 lib/CharmBoard/Controller/ViewSubf.pm create mode 100644 lib/CharmBoard/Schema/Set/Threads.pm create mode 100644 templates/subf.html.ep diff --git a/.vscode/settings.json b/.vscode/settings.json index 518df7f..a7acb55 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,7 @@ "CharmBoard", "Facepunch", "listsubf", + "origp", "passchk", "passgen", "pgsql", @@ -54,5 +55,14 @@ "perl-toolbox.lint.useProfile": true, "perl-toolbox.syntax.includePaths": [ "$workspaceRoot/libs" - ] + ], + "sqltools.connections": [ + { + "previewLimit": 50, + "driver": "SQLite", + "name": "CharmBoard", + "database": "${workspaceFolder:CharmBoard}/charmboard.db" + } + ], + "sqltools.useNodeRuntime": true } \ No newline at end of file diff --git a/charmboard.example.conf b/charmboard.example.conf index 1a206b3..b95df1c 100644 --- a/charmboard.example.conf +++ b/charmboard.example.conf @@ -1,5 +1,6 @@ { board_name => '', + board_root => '', # this doesn't do anything yet database => { type => '', # 'sqlite' or 'mariadb' diff --git a/database.sql b/database.sql index a1e3720..0727b9b 100644 --- a/database.sql +++ b/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 -- @@ -8,43 +8,14 @@ BEGIN TRANSACTION; -- Table: categories DROP TABLE IF EXISTS categories; - -CREATE TABLE categories ( - cat_id INTEGER NOT NULL ON CONFLICT ROLLBACK - UNIQUE ON CONFLICT ROLLBACK, - cat_name TEXT, - PRIMARY KEY ( - cat_id AUTOINCREMENT - ) -); - +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)); -- Table: 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, - 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, 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)); -- Table: sessions DROP TABLE IF EXISTS sessions; - CREATE TABLE sessions ( session_key TEXT NOT NULL UNIQUE @@ -57,25 +28,12 @@ CREATE TABLE sessions ( bound_ip TEXT ); - -- Table: 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) - UNIQUE ON CONFLICT ROLLBACK - NOT NULL ON CONFLICT ROLLBACK, - subf_name TEXT NOT NULL ON CONFLICT ROLLBACK, - subf_desc -); - +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); -- Table: threads DROP TABLE IF EXISTS threads; - CREATE TABLE threads ( thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK, thread_title TEXT NOT NULL ON CONFLICT ROLLBACK, @@ -85,10 +43,8 @@ CREATE TABLE threads ( ) ); - -- Table: users DROP TABLE IF EXISTS users; - CREATE TABLE users ( user_id INTEGER NOT NULL ON CONFLICT ROLLBACK UNIQUE ON CONFLICT ROLLBACK, @@ -105,6 +61,5 @@ CREATE TABLE users ( ON CONFLICT ABORT ); - COMMIT TRANSACTION; PRAGMA foreign_keys = on; diff --git a/lib/CharmBoard.pm b/lib/CharmBoard.pm index 0f271e2..63694a4 100644 --- a/lib/CharmBoard.pm +++ b/lib/CharmBoard.pm @@ -20,10 +20,10 @@ sub startup { {file => 'charmboard.conf'}); # 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 - if ( $config->{environment} eq 'dev' ) { + if ($config->{environment} eq 'dev') { $self->plugin('Renderer::WithoutCache'); $self->renderer->cache->max_keys(0)}; @@ -31,35 +31,42 @@ sub startup { $self->secrets($config->{secrets}); # import password pepper value - $self->helper(pepper => sub {$config->{pass_crypt}->{pepper}}); + $self->helper( + pepper => sub {$config->{pass_crypt}->{pepper}}); ## database setup # ? this could maybe be a given/when - my ($dsn, $dbUnicode); - if ($self->config->{database}->{type} ~~ 'sqlite') { - $dsn = "dbi:SQLite:" . $config->{database}->{name}; - $dbUnicode = "sqlite_unicode"} + { my ($_dsn, $_unicode); + if ($self->config->{database}->{type} ~~ 'sqlite') { + $_dsn = "dbi:SQLite:" . $config->{database}->{name}; + $_unicode = "sqlite_unicode"} - elsif ($self->config->{database}->{type} ~~ 'mariadb') { - $dsn = "dbi:mysql:" . $config->{database}->{name}; - $dbUnicode = "mysql_enable_utf"} + elsif ($self->config->{database}->{type} ~~ 'mariadb') { + $_dsn = "dbi:mysql:" . $config->{database}->{name}; + $_unicode = "mysql_enable_utf"} - else {die "\nUnknown, unsupported, or empty database type - in charmboard.conf. If you're sure you've set it to - something supported, maybe double check your spelling? - \n\n\t - Valid options: 'sqlite', 'mariadb'"}; + else {die "\nUnknown, unsupported, or empty database type + in charmboard.conf. If you're sure you've set it to + something supported, maybe double check your spelling? + \n\n\t + Valid options: 'sqlite', 'mariadb'"}; - my $schema = CharmBoard::Schema->connect( - $dsn, - $config->{database}->{user}, - $config->{database}->{pass}, - {$dbUnicode => 1}); - $self->helper(schema => sub {$schema}); + our $schema = CharmBoard::Schema->connect( + $_dsn, + $config->{database}->{user}, + $config->{database}->{pass}, + {$_unicode => 1}); + + $self->helper(schema => sub {$schema})} # router my $r = $self->routes; + # view subforum + $r->get('/subforum/:id')->to( + controller => 'Controller::ViewSubf', + action => 'subf_view'); + # controller routes ## index page $r->get('/')->to( @@ -89,5 +96,24 @@ sub startup { } 1; +__END__ -__END__ \ No newline at end of file +=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 diff --git a/lib/CharmBoard/Controller/Index.pm b/lib/CharmBoard/Controller/Index.pm index 5e74458..b6ed5e3 100644 --- a/lib/CharmBoard/Controller/Index.pm +++ b/lib/CharmBoard/Controller/Index.pm @@ -12,34 +12,34 @@ sub index { my $self = shift; # fetch a list of all categories - my @allCat = + my @all_cat = $self->schema->resultset('Categories')->fetch_all; # create a Tree::Simple object that will contain the list # of categories and the subforums that belong to them my $tree = - Tree::Simple->new("ROOT", Tree::Simple->ROOT); + Tree::Simple->new("subf_list", Tree::Simple->ROOT); - my (@fetchSubf, $catBranch); - foreach my $iterCat (@allCat) { - # create branch of ROOT for the current category + my (@fetch_subf, $cat_branch); + foreach my $iter_cat (@all_cat) { + # create branch of subf_list for the current category - $catBranch = - Tree::Simple->new($iterCat, $tree); + $cat_branch = + Tree::Simple->new($iter_cat, $tree); # fetch all subforums that belong to this category - @fetchSubf = + @fetch_subf = $self->schema->resultset('Subforums') - ->fetch_by_cat($iterCat); + ->fetch_by_cat($iter_cat); # add each fetched subforum as children of the branch # for the current category - foreach my $iterSubf (@fetchSubf) { - Tree::Simple->new($iterSubf, $catBranch)}} + foreach my $iter_subf (@fetch_subf) { + Tree::Simple->new($iter_subf, $cat_branch)}} $self->render( template => 'index', - categoryTree => $tree)} + category_tree => $tree)} 1; __END__ \ No newline at end of file diff --git a/lib/CharmBoard/Controller/Login.pm b/lib/CharmBoard/Controller/Login.pm index c9ecdbf..a827e6b 100644 --- a/lib/CharmBoard/Controller/Login.pm +++ b/lib/CharmBoard/Controller/Login.pm @@ -22,54 +22,54 @@ sub login_do { my $username = $self->param('username'); my $password = $self->pepper . ':' . $self->param('password'); - my $catchError; + my $catch_error; # declare vars used through multiple try/catch blocks with # '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 # check to see if user by entered username exists - $userInfo = $self->schema->resultset('Users')->search( + $user_info = $self->schema->resultset('Users')->search( {username => $username}); - $userInfo or die; + $user_info or die; # now check password validity - $passCheck = passchk($userInfo->get_column('salt')->first, - $userInfo->get_column('password')->first, $password); - $passCheck or die;} + $pass_check = passchk($user_info->get_column('salt')->first, + $user_info->get_column('password')->first, $password); + $pass_check or die;} - catch ($catchError) { # redirect to login page on fail - print $catchError; + catch ($catch_error) { # redirect to login page on fail + print $catch_error; $self->flash(error => 'Username or password incorrect.'); $self->redirect_to('login');} try { # now attempt to create session # 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 - $sessionKey = seasoning(16); + $session_key = seasoning(16); # add session to database $self->schema->resultset('Session')->create({ - session_key => $sessionKey, - user_id => $userID, + session_key => $session_key, + user_id => $user_id, session_expiry => time + 604800, is_ip_bound => 0, bound_ip => undef }) or die; # now create session cookie for user $self->session(is_auth => 1); - $self->session(user_id => $userID); - $self->session(session_key => $sessionKey); + $self->session(user_id => $user_id); + $self->session(session_key => $session_key); $self->session(expiration => 604800); # redirect to index upon success $self->redirect_to('/')} - catch ($catchError) { # redirect to login page on fail - print $catchError; + catch ($catch_error) { # redirect to login page on fail + print $catch_error; $self->flash(error => 'Your username and password were correct, but a server error prevented you from logging in. This has been logged so the administrator can fix it.'); diff --git a/lib/CharmBoard/Controller/ViewSubf.pm b/lib/CharmBoard/Controller/ViewSubf.pm new file mode 100644 index 0000000..9693105 --- /dev/null +++ b/lib/CharmBoard/Controller/ViewSubf.pm @@ -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; \ No newline at end of file diff --git a/lib/CharmBoard/Schema/Set/Categories.pm b/lib/CharmBoard/Schema/Set/Categories.pm index e5623b6..a547ceb 100644 --- a/lib/CharmBoard/Schema/Set/Categories.pm +++ b/lib/CharmBoard/Schema/Set/Categories.pm @@ -8,21 +8,29 @@ use experimental qw(try smartmatch); use base 'DBIx::Class::ResultSet'; sub fetch_all { - my $set = shift; + my $_set = shift; my $_fetch = - $set->search({}, + $_set->search({}, {order_by => 'cat_rank'}); return($_fetch->get_column('cat_id')->all)} sub title_from_id { - my $set = shift; + my $_set = shift; return( - $set->search({'cat_id' => $_[0]})-> + $_set->search({'cat_id' => $_[0]})-> get_column('cat_name')->first)} 1; -__END__ \ No newline at end of file +__END__ +=pod +=head1 NAME +CharmBoard::Schema::Set::Categories - DBIC ResultSet for +the categories table + +=head1 SYNOPSIS +=head1 DESCRIPTION +=cut \ No newline at end of file diff --git a/lib/CharmBoard/Schema/Set/Subforums.pm b/lib/CharmBoard/Schema/Set/Subforums.pm index a253704..588b2cb 100644 --- a/lib/CharmBoard/Schema/Set/Subforums.pm +++ b/lib/CharmBoard/Schema/Set/Subforums.pm @@ -8,20 +8,27 @@ use experimental qw(try smartmatch); use base 'DBIx::Class::ResultSet'; sub fetch_by_cat { - my $set = shift; + my $_set = shift; - my $fetch = - $set->search( + my $_fetch = + $_set->search( {'subf_cat' => $_[0] }, {order_by => 'subf_rank'}); - return($fetch->get_column('subf_id')->all)} + return($_fetch->get_column('subf_id')->all)} -sub title_from_id { - my $set = shift; +sub cat_from_id { + my $_set = shift; 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)} 1; diff --git a/lib/CharmBoard/Schema/Set/Threads.pm b/lib/CharmBoard/Schema/Set/Threads.pm new file mode 100644 index 0000000..4099a27 --- /dev/null +++ b/lib/CharmBoard/Schema/Set/Threads.pm @@ -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__ \ No newline at end of file diff --git a/lib/CharmBoard/Schema/Source/Threads.pm b/lib/CharmBoard/Schema/Source/Threads.pm index de5d590..a3b1220 100644 --- a/lib/CharmBoard/Schema/Source/Threads.pm +++ b/lib/CharmBoard/Schema/Source/Threads.pm @@ -16,6 +16,10 @@ __PACKAGE__->add_columns( thread_title => { data_type => 'text', is_nullable => 0, }, + thread_op => { + data_type => 'integer', + is_foreign_key => 1, + is_nullable => 0, }, thread_subf => { data_type => 'integer', is_foreign_key => 1, @@ -27,6 +31,9 @@ __PACKAGE__->belongs_to( thread_subf => 'CharmBoard::Schema::Source::Subforums', {'foreign.subf_id' => 'self.thread_subf'}); +__PACKAGE__->belongs_to( + thread_op => 'CharmBoard::Schema::Source::Posts', + {'foreign.post_id' => 'self.thread_op'}); 1; __END__ \ No newline at end of file diff --git a/script/CharmBoard b/script/CharmBoard index 6e04eca..af7c9a3 100755 --- a/script/CharmBoard +++ b/script/CharmBoard @@ -14,25 +14,4 @@ Mojolicious::Commands->start_app('CharmBoard'); __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 diff --git a/templates/index.html.ep b/templates/index.html.ep index 12c6cf2..3af54c9 100644 --- a/templates/index.html.ep +++ b/templates/index.html.ep @@ -1,31 +1,30 @@ -% layout 'default', title => $self->boardName; +% layout 'default', title => $self->board_name; -<% my $catHeader = begin %> - % my $_catID = shift; my $_name = shift; -
+<% my $cat_header = begin %> + % my $_cat_id = shift; my $_name = shift; +
<%= $_name %>
<% end %> -<% my $subfItem = begin %> - % my $_subfID = shift; my $_catID = shift; +<% my $subf_item = begin %> + % my $_subf_id = shift; my $_cat_id = shift; % my $_name = shift;
<%= $_name %>
+ subforum-item subforum-<%= $_subf_id %> + category-<%= $_cat_id %> + "><%= $_name %>
<% end %> <% -foreach my $category ($categoryTree->getAllChildren) { %> - <%= $catHeader->( +foreach my $category ($category_tree->getAllChildren) { %> + <%= $cat_header->( $category->getNodeValue, $self->schema->resultset('Categories')-> title_from_id($category->getNodeValue)) %> - <% say ('$category: ' . $category); %> <% foreach my $subforum ($category->getAllChildren) { %> - <%= $subfItem->( + <%= $subf_item->( $subforum->getNodeValue, $category->getNodeValue, $self->schema->resultset('Subforums')-> diff --git a/templates/layouts/default/_header.html.ep b/templates/layouts/default/_header.html.ep index 79e5897..570a847 100644 --- a/templates/layouts/default/_header.html.ep +++ b/templates/layouts/default/_header.html.ep @@ -10,5 +10,5 @@ else { "login | register"}; %> -

<%== $self->boardName %>

+

<%== $self->board_name %>

<%== $userControls %>

\ No newline at end of file diff --git a/templates/login.html.ep b/templates/login.html.ep index f40e11e..2d2b495 100644 --- a/templates/login.html.ep +++ b/templates/login.html.ep @@ -1,4 +1,4 @@ -% layout 'default', title => $self->boardName . ' - Login'; +% layout 'default', title => $self->board_name . ' - Login'; % if ($error) {

<%= $error %>

%}; diff --git a/templates/register.html.ep b/templates/register.html.ep index 64b0d3e..4694940 100644 --- a/templates/register.html.ep +++ b/templates/register.html.ep @@ -1,4 +1,4 @@ -% layout 'default', title => $self->boardName . ' - Registration'; +% layout 'default', title => $self->board_name . ' - Registration'; % if ($error) {

<%= $error %>

%}; diff --git a/templates/subf.html.ep b/templates/subf.html.ep new file mode 100644 index 0000000..ca2ebf3 --- /dev/null +++ b/templates/subf.html.ep @@ -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; +
+ +
+<% end %> + +<%= $self->board_name %> » <%= $cat_title %> » <%= $subf_title %> +

+ +<% if (! @thread_list) { %> +Oops! Looks like there's no threads here yet. Maybe you'd +like to make one? +<% } else { + foreach my $thread_id (@thread_list) { %> +<%= $thread_item->( + $thread_id, + $self->schema->resultset('Threads')-> + title_from_id($thread_id)) %> +<% }} %> \ No newline at end of file