The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Foorum::Controller::Topic;

use strict;
use warnings;
our $VERSION = '1.001000';
use parent 'Catalyst::Controller';
use Foorum::Utils qw/encodeHTML get_page_from_url generate_random_word/;
use Foorum::XUtils qw/theschwartz/;
use List::MoreUtils qw/firstidx/;

sub topic : Regex('^forum/(\w+)/(topic/)?(\d+)$') {
    my ( $self, $c ) = @_;

    my $forum_code = $c->req->snippets->[0];
    my $topic_id   = $c->req->snippets->[2];

    # get the forum information
    my $forum = $c->controller('Get')->forum( $c, $forum_code );
    my $forum_id = $forum->{forum_id};

    my $page = get_page_from_url( $c->req->path );
    $page = 1 unless ( $page and $page =~ /^\d+$/ );
    my $rss
        = ( $c->req->path =~ /\/rss(\/|$)/ ) ? 1 : 0; # /forum/ForumName/1/rss

    my $format = $c->req->param('format');
    if ( $format and 'pdf' eq $format ) {
        unless ( $c->config->{function_on}->{topic_pdf} ) {
            $c->detach( '/print_error', ['Function Disabled'] );
        }

        # Build PDF in backend
        my $random_word = generate_random_word(6);
        my $client      = theschwartz();
        $client->insert(
            'Foorum::TheSchwartz::Worker::Topic_ViewAsPDF',
            [ $forum_id, $topic_id, $random_word ]
        );

        my $url = $c->req->base
            . "upload/pdf/$forum_id-$topic_id-$random_word.pdf";
        $c->stash(
            {   download_url => $url,
                template     => 'topic/pdf_download.html',
            }
        );

        return 1;
    }

    # get the topic
    my $topic = $c->controller('Get')
        ->topic( $c, $topic_id, { forum_id => $forum_id } );

    if ($rss) {
        my @comments = $c->model('DBIC::Comment')
            ->get_all_comments_by_object( 'topic', $topic_id );

        # get last 20 items
        @comments = reverse(@comments);
        @comments = splice( @comments, 0, 20 );

        $c->stash(
            {   comments => \@comments,
                template => 'topic/topic.rss.html'
            }
        );
    } else {
        $topic->{hit} = $c->model('DBIC::Hit')
            ->register( 'topic', $topic_id, $topic->{hit} );
        if ( $c->user_exists ) {
            my $query = {
                user_id     => $c->user->user_id,
                object_type => 'topic',
                object_id   => $topic_id,
            };

            # 'star' status
            $c->stash->{is_starred} = $c->model('DBIC::Star')->count($query);

            # 'share' status
            $c->stash->{is_shared}
                = $c->model('DBIC')->resultset('Share')->count($query);

            # 'visit'
            $c->model('DBIC::Visit')
                ->make_visited( 'topic', $topic_id, $c->user->user_id );
        }

        # get comments
        my ($view_mode)
            = ( $c->req->path =~ /\/view_mode=(thread|flat)(\/|$)/ );
        my ($comment_id) = ( $c->req->path =~ /\/comment_id=(\d+)(\/|$)/ );
        (   $c->stash->{comments},
            $c->stash->{comments_pager},
            $c->stash->{top_comment_id}
            )
            = $c->model('DBIC::Comment')->get_comments_by_object(
            {   object_type => 'topic',
                object_id   => $topic_id,
                page        => $page,
                view_mode   => $view_mode,
                comment_id  => $comment_id,
            }
            );

        # print or normal show
        if ( $c->req->path =~ /\/print(\/|$)/ ) {
            $c->stash->{template} = 'topic/print.html';
        } else {

            # previous / next topic
            my @topic_ids
                = $c->model('DBIC::Topic')->get_topic_id_list($forum_id);
            my $place = firstidx { $_ == $topic_id } @topic_ids;
            if ( $place > 0 and $topic_ids[ $place - 1 ] ) {
                $c->stash->{previous_topic_id} = $topic_ids[ $place - 1 ];
            }
            if ( $place < $#topic_ids and $topic_ids[ $place + 1 ] ) {
                $c->stash->{next_topic_id} = $topic_ids[ $place + 1 ];
            }

            $c->stash->{whos_view_this_page} = 1;
            $c->stash->{template}            = 'topic/index.html';
        }
    }
}

sub create : Regex('^forum/(\w+)/topic/new$') {
    my ( $self, $c ) = @_;

    return $c->res->redirect('/login') unless ( $c->user_exists );

    # check policy
    if ( $c->user->{status} eq 'banned' or $c->user->{status} eq 'blocked' ) {
        $c->detach( '/print_error', ['ERROR_PERMISSION_DENIED'] );
    }

    my $forum_code = $c->req->snippets->[0];
    my $forum      = $c->controller('Get')->forum( $c, $forum_code );
    my $forum_id   = $forum->{forum_id};

    if (    $forum->{settings}->{can_post_threads}
        and $forum->{settings}->{can_post_threads} eq 'N' ) {
        $c->detach( '/print_error', ['ERROR_PERMISSION_DENIED'] );
    }

    $c->stash(
        {   template => 'comment/new.html',
            mode     => 'topic',
            action   => 'create',
        }
    );

    return unless ( $c->req->method eq 'POST' );

    # execute validation.
    $c->controller('Comment')->validate_params($c);

    my $upload    = $c->req->upload('upload');
    my $upload_id = 0;
    if ($upload) {
        $upload_id
            = $c->model('DBIC::Upload')
            ->add_file( $upload,
            { forum_id => $forum_id, user_id => $c->user->user_id } );
        unless ( $upload_id =~ /^\d+$/ ) {
            return $c->set_invalid_form( upload => $upload_id );
        }
    }

    my $title     = $c->req->param('title');
    my $formatter = $c->req->param('formatter');
    my $text      = $c->req->param('text');

    # only admin has HTML rights
    if ( 'html' eq $formatter ) {
        my $is_admin = $c->model('Policy')->is_admin( $c, 'site' );
        $formatter = 'plain' unless ($is_admin);
    }

    # create record
    my $topic_title = encodeHTML($title);
    my $topic       = $c->model('DBIC::Topic')->create_topic(
        {   forum_id         => $forum_id,
            title            => $topic_title,
            author_id        => $c->user->user_id,
            last_updator_id  => $c->user->user_id,
            last_update_date => time(),
            hit              => 0,
        }
    );

    # clear visit
    $c->model('DBIC::Visit')
        ->make_un_visited( 'topic', $topic->topic_id, $c->user->user_id );

    my $comment = $c->model('DBIC::Comment')->create_comment(
        {   object_type => 'topic',
            object_id   => $topic->topic_id,
            forum_id    => $forum_id,
            upload_id   => $upload_id,
            title       => $title,
            text        => $text,
            formatter   => $formatter,
            user_id     => $c->user->user_id,
            post_ip     => $c->req->address,
            lang        => $c->stash->{lang},
        }
    );

    $c->res->redirect( $forum->{forum_url} . '/topic/' . $topic->topic_id );
}

1;
__END__

=pod

=head1 AUTHOR

Fayland Lam <fayland at gmail.com>

=cut