Work a bit on subforum viewing/thread listing
This commit is contained in:
parent
45343a87fd
commit
fd585edc80
|
@ -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
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
board_name => '',
|
||||
board_root => '', # this doesn't do anything yet
|
||||
|
||||
database => {
|
||||
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
|
||||
--
|
||||
|
@ -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;
|
||||
|
|
|
@ -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,18 +31,19 @@ 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);
|
||||
{ my ($_dsn, $_unicode);
|
||||
if ($self->config->{database}->{type} ~~ 'sqlite') {
|
||||
$dsn = "dbi:SQLite:" . $config->{database}->{name};
|
||||
$dbUnicode = "sqlite_unicode"}
|
||||
$_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"}
|
||||
$_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
|
||||
|
@ -50,16 +51,22 @@ sub startup {
|
|||
\n\n\t
|
||||
Valid options: 'sqlite', 'mariadb'"};
|
||||
|
||||
my $schema = CharmBoard::Schema->connect(
|
||||
$dsn,
|
||||
our $schema = CharmBoard::Schema->connect(
|
||||
$_dsn,
|
||||
$config->{database}->{user},
|
||||
$config->{database}->{pass},
|
||||
{$dbUnicode => 1});
|
||||
$self->helper(schema => sub {$schema});
|
||||
{$_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__
|
||||
|
||||
=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;
|
||||
|
||||
# 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__
|
|
@ -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.');
|
||||
|
|
|
@ -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';
|
||||
|
||||
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__
|
||||
=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';
|
||||
|
||||
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;
|
||||
|
|
|
@ -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 => {
|
||||
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__
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
% layout 'default', title => $self->boardName;
|
||||
% layout 'default', title => $self->board_name;
|
||||
|
||||
<% my $catHeader = begin %>
|
||||
% my $_catID = shift; my $_name = shift;
|
||||
<div class="category-header category-<%= $_catID %>">
|
||||
<% my $cat_header = begin %>
|
||||
% my $_cat_id = shift; my $_name = shift;
|
||||
<div class="category-header category-<%= $_cat_id %>">
|
||||
<b><%= $_name %></b>
|
||||
</div>
|
||||
<% 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;
|
||||
<div class="
|
||||
subforum-item subforum-<%= $_subfID %>
|
||||
category-<%= $_catID %>
|
||||
"><%= $_name %></div>
|
||||
subforum-item subforum-<%= $_subf_id %>
|
||||
category-<%= $_cat_id %>
|
||||
"><a href="/subforum/<%= $_subf_id %>"><%= $_name %></a></div>
|
||||
<% 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')->
|
||||
|
|
|
@ -10,5 +10,5 @@ else {
|
|||
"<a href=\"/login\">login</a> |
|
||||
<a href=\"/register\">register</a>"};
|
||||
%>
|
||||
<a href="/"><h2><%== $self->boardName %></h2></a>
|
||||
<a href="/"><h2><%== $self->board_name %></h2></a>
|
||||
<%== $userControls %><br /><br />
|
|
@ -1,4 +1,4 @@
|
|||
% layout 'default', title => $self->boardName . ' - Login';
|
||||
% layout 'default', title => $self->board_name . ' - Login';
|
||||
% if ($error) {
|
||||
<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) {
|
||||
<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