package CF::Controller::Posts; use Mojo::Base 'Mojolicious::Controller'; use Mojo::Pg::PubSub; use feature 'signatures'; no warnings 'experimental::signatures'; # TODO: do modelu use constant STATUS_ANNOUNCEMENTS => { 1 => 2, # prijatelny n.p. 2 => 1, # schvaleny n.p. 4 => 0, # zamitnuty n.p. }; sub create ($c) { $c->openapi->valid_input or return; my $args = $c->req->json; # Navrh postupu muze predlozit jenom clen if ( $args->{type} == 0 && ! $c->user_roles->{member} ) { return $c->error(403, 'Insufficient permissions'); } my $program_entry = $c->schema->resultset('ProgramEntry')->search({ is_live => 1, })->first; # Neni zadny aktivni bod rozpravy if ( ! ( $program_entry && $program_entry->discussion_opened )) { return $c->error(403, 'Debate closed'); } # limit poctu prispevku jedneho uzivatele k jednemu bodu my $limit = $c->schema->resultset('Post')->count({ program_entry_id => $program_entry->id, user_id => $c->user->{id}, }); if ( $limit > $c->cfg->{limit_post_count}) { return $c->error(429, 'Too many post from user'); } # limit poctu prispevku za minutu $limit = $c->schema->resultset('Post')->count({ user_id => $c->user->{id}, datetime => { '>' => \"now()-'1 min'::interval" }, }); if ( $limit >= $c->cfg->{limit_post_add_rate}) { return $c->error(429, 'Too many posts per minute'); } my $post = $program_entry->add_to_posts({ user_id => $c->user->{id}, type => $args->{type}, content => $args->{content}, }); my $pubsub = Mojo::Pg::PubSub->new(pg => $c->pg); $pubsub->json('notify')->notify( notify => { event => 'post_created', payload => $post->view->format(), }); $c->render( status => 201, openapi => { id => $post->id }, ); }; sub get ($c) { $c->openapi->valid_input or return; my $post = $c->schema->resultset('Post_view')->find($c->stash->{id}); return $c->error(404, 'Post not found') if ! $post; my $formatted = $post->format(); if ( $c->user ) { if (my $my_vote = $post->rankings({ user_id => $c->user->{id} })->first) { $formatted->{ranking}{my_vote} = $my_vote->ranking; } } foreach my $history ( $post->history() ) { push @{ $formatted->{history_log} }, { attribute => 'content', value => $history->content, datetime => $history->datetime, originator => '', } } $c->render(openapi => $c->spec_filter($formatted, 'Post')); } sub list ($c) { $c->openapi->valid_input or return; my $args = $c->validation->output; my ($cond, $attrs) = $c->search_parametrs( $args ); $cond->{deleted} = undef; # Vzdy jen k jednemu programovemu bodu - parametr nebo aktualni if ( $args->{program_entry_id} ) { $cond->{program_entry_id} = $args->{program_entry_id}; } else { my $program_entry = $c->schema->resultset('ProgramEntry')->search({ is_live => 1, })->first; # Neni zadny aktivni bod rozpravy if ( ! $program_entry ) { $c->render(json => { data => [], total => 0, }); return } $cond->{program_entry_id} = $program_entry->id; } if ( exists $args->{archived} && defined $args->{archived}) { $cond->{is_archived} = $args->{archived}; } # omezeni zobrazovani nepotvrzenych navrhu postupu if ( $args->{type} ) { $cond->{type} = $args->{type}; if ( $args->{type} == 0 && ! $c->user_roles->{chairman} ) { $cond->{state} = {'-in' => [1,2,3,4]} } } elsif (! $c->user_roles->{chairman}) { $cond->{'-or'} = { type => 1, state => { '-in' => [1,2,3,4] }, }; } # hodnoceni aktualniho uzivatele my $my_vote = {}; if ( $c->user ) { my $rankings = $c->schema->resultset('PostRanking')->search({ user_id => $c->user->{id} }); while ( my $record = $rankings->next() ) { $my_vote->{ $record->post_id } = $record->ranking; } } my @posts = (); my $count = $c->schema->resultset('Post_view')->count($cond); if ( $count ) { my $posts = $c->schema->resultset('Post_view')->search($cond, $attrs); POST: while ( my $post = $posts->next() ) { my $formatted = $post->format(); $formatted->{ranking}{my_vote} = $my_vote->{ $post->id } // 0; push @posts, $c->spec_filter($formatted, 'Post'); } } $c->render(json => { data => \@posts, total => $count, }); } sub update ($c) { $c->openapi->valid_input or return; my $args = $c->req->json; my $post = $c->schema->resultset('Post')->find($c->stash->{id}); return $c->error(404, 'Post not found') if ! $post; # limit poctu prispevku za minutu my $limit = $c->schema->resultset('PostHistory')->count({ user_id => $c->user->{id}, post_id => $post->id, datetime => { '>' => \"now()-'1 min'::interval" }, }); if ( $limit >= $c->cfg->{limit_post_edit_rate}) { return $c->error(429, 'Too many posts changes per minute'); } if ( ! $c->user_roles->{chairman} ) { if ( $post->user_id != $c->user->{id} ) { return $c->error(403, 'Access deined'); } else { delete $args->{is_archived}; delete $args->{state}; } } my $update = $c->prepare_update_data( $post, $c->req->json ); my $pubsub = Mojo::Pg::PubSub->new(pg => $c->pg); my $guard = $c->schema->txn_scope_guard; if ( $update->{state} && $post->state != $update->{state} ) { my $announcement_type = STATUS_ANNOUNCEMENTS->{ $args->{state} }; if ( $announcement_type ) { #TODO: do modelu my $msg = $c->schema->resultset('Announcement')->from_template( $announcement_type, $post->user->name, $post->content, ); my $announcement = $c->schema->resultset('Announcement')->create({ user_id => $c->user->{id}, type => $announcement_type, content => $msg, }); # potrebujeme kvuli datumu $announcement = $c->schema->resultset('Announcement')->find({ id => $announcement->id }); $pubsub->json('notify')->notify( notify => { event => 'announcement_created', payload => $announcement->format(), }); } } $post->add_to_history({ user_id => $c->user->{id}, datetime => $post->changed // $post->datetime, content => $post->content, }); $post->update({ %{ $update }, changed => \'now()', }); $pubsub->json('notify')->notify( notify => { event => 'post_changed', payload => { id => $post->id, %{ $update }, } }); $guard->commit; $c->render(status => 204, text => ''); } sub delete ($c) { $c->openapi->valid_input or return; my $post = $c->schema->resultset('Post')->find($c->stash->{id}); return $c->error(404, 'Post not found') if ! $post; my $pubsub = Mojo::Pg::PubSub->new(pg => $c->pg); my $guard = $c->schema->txn_scope_guard; $post->update({ deleted => \'now()', }); $pubsub->json('notify')->notify( notify => { event => 'post_deleted', payload => { id => $post->id, } }); $guard->commit; $c->render(status => 204, text => ''); } sub ranking ($c) { $c->openapi->valid_input or return; my $args = $c->validation->output; my $post = $c->schema->resultset('Post')->find($c->stash->{id}); return $c->error(404, 'Post not found') if ! $post; if ( $post->type == 0 and ! $c->user_roles->{member} ) { $c->render(status => 403, text => ''); return; } my $user_ranking = $post->rankings({ user_id => $c->user->{id}, })->first; my $update = { ranking_likes => $post->ranking_likes, ranking_dislikes => $post->ranking_dislikes, }; my $user_ranking_update; if ($user_ranking && $user_ranking->ranking == $args->{ranking} ) { $user_ranking_update = 0; } else { $user_ranking_update = $args->{ranking}; } if ($user_ranking && $user_ranking->ranking == 1 ) { $update->{ranking_likes}--; $update->{ranking_dislikes}++ if $args->{ranking} == -1; } elsif ($user_ranking && $user_ranking->ranking == -1 ) { $update->{ranking_dislikes}--; $update->{ranking_likes}++ if $args->{ranking} == 1; } else { $update->{ranking_likes}++ if $args->{ranking} == 1; $update->{ranking_dislikes}++ if $args->{ranking} == -1; } my $pubsub = Mojo::Pg::PubSub->new(pg => $c->pg); my $guard = $c->schema->txn_scope_guard; $post->update( $update ); if ( $user_ranking ) { $user_ranking->update( { ranking => $user_ranking_update } ); } else { $post->add_to_rankings({ user_id => $c->user->{id}, ranking => $user_ranking_update, }); } $pubsub->json('notify')->notify(notify => { event => 'post_ranked', payload => { id => $post->id, %{ $update }, } }); $guard->commit; $c->render(status => 204, text => ''); } 1;