From 0c6298c72e87cd3633beceb55b14f43bfe59ab25 Mon Sep 17 00:00:00 2001 From: hylom Date: Fri, 23 Jun 2017 20:03:07 +0900 Subject: [PATCH] * Model::Polls: implement vote() --- src/newslash_web/lib/Newslash/Model/Polls.pm | 104 ++++++++++++++++++++- .../lib/Newslash/Model/Polls/Voters.pm | 6 +- src/newslash_web/t/models/polls.t | 45 +++++++-- 3 files changed, 139 insertions(+), 16 deletions(-) diff --git a/src/newslash_web/lib/Newslash/Model/Polls.pm b/src/newslash_web/lib/Newslash/Model/Polls.pm index a659b001..020432f2 100644 --- a/src/newslash_web/lib/Newslash/Model/Polls.pm +++ b/src/newslash_web/lib/Newslash/Model/Polls.pm @@ -1,6 +1,8 @@ package Newslash::Model::Polls; use Newslash::Model::Base -base; +use Newslash::Model::Polls::Voters; + use Newslash::Util::Formatters qw(format_datetime); sub answers { @@ -98,9 +100,9 @@ sub create { my $sql = <<"EOSQL"; INSERT INTO pollquestions - (question, topic, date, uid, primaryskid) + (question, voters, topic, date, uid, primaryskid) VALUES - (?, ?, NOW(), ?, ?) + (?, 0, ?, NOW(), ?, ?) EOSQL my $dbh = $self->start_transaction; @@ -142,10 +144,95 @@ EOSQL } sub vote { - my ($self, $uid, $qid, $aid) = @_; + my ($self, $user, $qid, $aid) = @_; + my $uid = $user ? $user->{uid} : 0; + + if (!$uid) { + $self->set_error("invalid user"); + return; + } + my $poll = $self->select(qid => $qid || 0); + if (!$poll) { + $self->set_error("poll not found"); + return; + } + + my $is_valid_answer = 0; + if ($aid) { + for my $answer (@{$poll->{answers}}) { + if ($aid == $answer->{aid}) { + $is_valid_answer = 1; + last; + } + } + } + if (!$is_valid_answer) { + $self->set_error("invalid answer"); + return; + } + + # already voted? + if ($user->{is_login}) { + my $voters = $self->voters; + my $votes = $voters->select(qid => $qid, uid => $uid); + if (!$votes) { + $self->set_error("select voters failed", $voters->last_errorno); + return; + } + if (@$votes > 0) { + $self->set_error("already voted"); + return; + } + } + + # update tables + my $sql = <<"EOSQL"; +UPDATE pollanswers SET votes = votes + 1 WHERE qid = ? AND aid = ? +EOSQL + + my $dbh = $self->start_transaction; + my $rs = $dbh->do($sql, undef, $qid, $aid); + if (!$rs) { + $dbh->rollback; + $self->set_error("update pollanswers failed", $dbh->{mysql_errorno}); + $self->disconnect_db; + return; + } + + $sql = <<"EOSQL"; +UPDATE pollquestions SET voters = voters + 1 WHERE qid = ? +EOSQL + + $rs = $dbh->do($sql, undef, $qid); + if (!$rs) { + $dbh->rollback; + $self->set_error("update pollquestions failed", $dbh->{mysql_errorno}); + $self->disconnect_db; + return; + } + + $sql = <<"EOSQL"; +INSERT INTO pollvoters + (qid, id, time, uid) + VALUES + (?, ?, NOW(), ?) +EOSQL + + my $net_id = $user->{ipid} || ""; + + $rs = $dbh->do($sql, undef, $qid, $net_id, $uid); + if (!$rs) { + $dbh->rollback; + $self->set_error("insert into pollvoters failed", $dbh->{mysql_errorno}); + $self->disconnect_db; + return; + } + + $self->commit; + return 1; } -sub delete { +sub hard_delete { my ($self, $qid) = @_; return if !$qid; @@ -169,6 +256,15 @@ sub delete { return; } + $sql = "DELETE FROM pollvoters WHERE qid = ?"; + $rs = $dbh->do($sql, undef, $qid); + if (!$rs) { + $dbh->rollback; + $self->set_error("hard-delete voters failed", $dbh->{mysql_errorno}); + $self->disconnect_db; + return; + } + $self->commit; return 1; } diff --git a/src/newslash_web/lib/Newslash/Model/Polls/Voters.pm b/src/newslash_web/lib/Newslash/Model/Polls/Voters.pm index 56a2434c..13e7f9ce 100644 --- a/src/newslash_web/lib/Newslash/Model/Polls/Voters.pm +++ b/src/newslash_web/lib/Newslash/Model/Polls/Voters.pm @@ -28,14 +28,14 @@ EOSQL my $dbh = $self->connect_db; my $sth = $dbh->prepare($sql); $sth->execute(@query_param); - my $polls = $sth->fetchall_arrayref(+{}); - if (!$polls) { + my $voters = $sth->fetchall_arrayref(+{}); + if (!$voters) { $self->disconnect_db(); return; } $self->disconnect_db(); - return $polls; + return $voters; } diff --git a/src/newslash_web/t/models/polls.t b/src/newslash_web/t/models/polls.t index 2ab94ca2..88992f75 100644 --- a/src/newslash_web/t/models/polls.t +++ b/src/newslash_web/t/models/polls.t @@ -6,23 +6,20 @@ use Test::More; use Test::Mojo; use Data::Dumper; -use Newslash::Util::Test qw(create_user delete_user - create_story delete_story - create_comments - create_admin_user - create_users - get_anonymous_user - ); +use Newslash::Util::TestMan; my $t = Test::Mojo->new('Newslash::Web'); my $polls; my ($admin, $user); +my $test_man = Newslash::Util::TestMan->new($t); # prepare for test if ($t->app->mode eq 'test') { - $admin = create_admin_user($t->app, "mmtest_admin"); + $admin = $test_man->create_admin("polltestadmin"); ok($admin, "create admin user"); + $user = $test_man->create_user("polltest"); + ok($user, "create test user"); } subtest 'get polls object' => sub { @@ -33,6 +30,7 @@ subtest 'get polls object' => sub { subtest 'create/select/update/delete polls' => sub { plan skip_all => "mode is not 'test'" if ($t->app->mode ne 'test'); + # create question my $answers = ["item1", "item2", "item3"]; my $params = { question => "投票テスト", @@ -46,6 +44,8 @@ subtest 'create/select/update/delete polls' => sub { ok($poll, 'select polls by qid'); is($poll->{question}, $params->{question}, "valid question"); is(@{$poll->{answers}}, @$answers, "check answers number"); + #warn(Dumper($poll)); + is($poll->{voters}, 0, "valid voters"); my $index = 0; for my $answer (@$answers) { is($poll->{answers}->[$index]->{answer}, $answer, "check answer $answer"); @@ -53,9 +53,36 @@ subtest 'create/select/update/delete polls' => sub { $index++; } - ok($polls->delete($qid), 'delete box'); + + # vote + ok(!$polls->vote($user, $qid, 0), "vote to invalid answer"); + ok($polls->vote($user, $qid, 1), "do vote"); + ok(!$polls->vote($user, $qid, 2), "duplicate vote not allowed"); + + # select + my $votes = $polls->voters->select(uid => $user->{uid}, qid => $qid); + ok($votes, "voters->select"); + ok(@$votes, "vote accepted"); + + $poll = $polls->select(qid => $qid); + ok($poll, 'select polls by qid (2)'); + is($poll->{question}, $params->{question}, "valid question"); + is(@{$poll->{answers}}, @$answers, "check answers number"); + is($poll->{voters}, 1, "voters updated"); + for my $answer (@{$poll->{answers}}) { + if ($answer->{aid} == 1) { + is($answer->{votes}, 1, "votes updated $answer->{answer}"); + } + else { + is($answer->{votes}, 0, "votes not updated $answer->{answer}"); + } + } + + ok($polls->hard_delete($qid), 'delete box'); my $deleted_poll = $polls->select(qid => $qid); ok(!defined $deleted_poll, 'delete succeed'); }; +$test_man->cleanup; + done_testing(); -- 2.11.0