summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2020-08-24 15:16:34 +0200
committerYorhel <git@yorhel.nl>2020-08-24 15:18:59 +0200
commitdda6647d207ea26800c5dbf3b326c88eccaa2c66 (patch)
tree72a4ca59beff201286363f1c6c3ae346c1a34ffb
parent9bc568ac157590267b099b422c8a49b031ef7c2a (diff)
reviews: Disallow voting on competing reviews + only use Elm when necessary
i.e. no need to spawn Elm when the user can't vote anyway.
-rw-r--r--elm/Reviews/Vote.elm9
-rw-r--r--lib/VNWeb/Reviews/Elm.pm1
-rw-r--r--lib/VNWeb/Reviews/Lib.pm20
-rw-r--r--lib/VNWeb/Reviews/List.pm3
-rw-r--r--lib/VNWeb/Reviews/Page.pm12
-rw-r--r--lib/VNWeb/Reviews/VNTab.pm8
-rw-r--r--sql/func.sql3
7 files changed, 35 insertions, 21 deletions
diff --git a/elm/Reviews/Vote.elm b/elm/Reviews/Vote.elm
index cf63fe71..717539c1 100644
--- a/elm/Reviews/Vote.elm
+++ b/elm/Reviews/Vote.elm
@@ -23,7 +23,6 @@ type alias Model =
{ state : Api.State
, id : String
, my : Maybe Bool
- , can : Bool
, up : Int
, down : Int
}
@@ -33,7 +32,6 @@ init d =
{ state = Api.Normal
, id = d.id
, my = d.my
- , can = d.can
, up = d.up
, down = d.down
}
@@ -62,16 +60,13 @@ update msg model =
view : Model -> Html Msg
view model =
- let but opt lbl =
- if not model.can
- then span [] [ text lbl ]
- else a [ href "#", onClickD (Vote opt), classList [("votebut", True), ("myvote", model.my == Just opt)] ] [ text lbl ]
+ let but opt lbl = a [ href "#", onClickD (Vote opt), classList [("votebut", True), ("myvote", model.my == Just opt)] ] [ text lbl ]
in
span []
[ case model.state of
Api.Loading -> span [ class "spinner" ] []
Api.Error e -> b [ class "standout" ] [ text (Api.showResponse e) ]
- Api.Normal -> if model.can && model.my == Nothing then text "Was this review helpful? " else text ""
+ Api.Normal -> if model.my == Nothing then text "Was this review helpful? " else text ""
, but True ("๐Ÿ‘ " ++ String.fromInt model.up)
, text " "
, but False ("๐Ÿ‘Ž " ++ String.fromInt model.down)
diff --git a/lib/VNWeb/Reviews/Elm.pm b/lib/VNWeb/Reviews/Elm.pm
index 527da239..428da4dc 100644
--- a/lib/VNWeb/Reviews/Elm.pm
+++ b/lib/VNWeb/Reviews/Elm.pm
@@ -5,7 +5,6 @@ use VNWeb::Prelude;
my $VOTE = {
id => { vndbid => 'w' },
my => { required => 0, jsonbool => 1 },
- can => { _when => 'out', anybool => 1 },
up => { _when => 'out', uint => 1 },
down => { _when => 'out', uint => 1 },
};
diff --git a/lib/VNWeb/Reviews/Lib.pm b/lib/VNWeb/Reviews/Lib.pm
new file mode 100644
index 00000000..3564464a
--- /dev/null
+++ b/lib/VNWeb/Reviews/Lib.pm
@@ -0,0 +1,20 @@
+package VNWeb::Reviews::Lib;
+
+use VNWeb::Prelude;
+use Exporter 'import';
+
+our @EXPORT = qw/review_vote_/;
+
+
+# Display the up/down vote counts for a review, optionally with the option for the user to vote.
+# Takes an object with the following fields: id, c_up, c_down, my, can
+sub review_vote_ {
+ my($w) = @_;
+ my sub plain_ {
+ span_ sprintf '๐Ÿ‘ %d ๐Ÿ‘Ž %d', $w->{c_up}, $w->{c_down};
+ };
+ return plain_ if !auth || !$w->{can};
+ elm_ 'Reviews.Vote' => $VNWeb::Reviews::Elm::VOTE_OUT, { id => $w->{id}, up => $w->{c_up}, down => $w->{c_down}, my => $w->{my} }, \&plain_;
+}
+
+1;
diff --git a/lib/VNWeb/Reviews/List.pm b/lib/VNWeb/Reviews/List.pm
index fcd0ed03..04f932bd 100644
--- a/lib/VNWeb/Reviews/List.pm
+++ b/lib/VNWeb/Reviews/List.pm
@@ -1,6 +1,7 @@
package VNWeb::Reviews::List;
use VNWeb::Prelude;
+use VNWeb::Reviews::Lib;
sub tablebox_ {
@@ -25,7 +26,7 @@ sub tablebox_ {
td_ class => 'tc2', sub { user_ $_ };
td_ class => 'tc3', sub { a_ href => "/$_->{id}", $_->{title} };
td_ class => 'tc4', fmtvote $_->{vote};
- td_ class => 'tc5', sprintf '๐Ÿ‘ %d ๐Ÿ‘Ž %d', $_->{c_up}, $_->{c_down};
+ td_ class => 'tc5', sub { review_vote_ $_ };
td_ class => 'tc6', $_->{c_count};
td_ class => 'tc7', $_->{c_lastnum} ? sub {
user_ $_, 'lu_';
diff --git a/lib/VNWeb/Reviews/Page.pm b/lib/VNWeb/Reviews/Page.pm
index 5f2671ac..23c62cf1 100644
--- a/lib/VNWeb/Reviews/Page.pm
+++ b/lib/VNWeb/Reviews/Page.pm
@@ -2,6 +2,7 @@ package VNWeb::Reviews::Page;
use VNWeb::Prelude;
use VNWeb::Releases::Lib;
+use VNWeb::Reviews::Lib;
my $COMMENT = form_compile any => {
@@ -64,11 +65,7 @@ sub review_ {
} if length $w->{text};
tr_ sub {
td_ '';
- td_ style => 'text-align: right', sub {
- elm_ 'Reviews.Vote' => $VNWeb::Reviews::Elm::VOTE_OUT, { %$w, can => auth && $w->{user_id} != auth->uid }, sub {
- span_ sprintf '๐Ÿ‘ %d ๐Ÿ‘Ž %d', $w->{c_up}, $w->{c_down};
- };
- }
+ td_ style => 'text-align: right', sub { review_vote_ $w };
};
}
}
@@ -78,7 +75,7 @@ TUWF::get qr{/$RE{wid}(?:(?<sep>[\./])$RE{num})?}, sub {
return tuwf->resNotFound if !auth->permReview; #XXX:While in beta
my($id, $sep, $num) = (tuwf->capture('id'), tuwf->capture('sep')||'', tuwf->capture('num'));
my $w = tuwf->dbRowi(
- 'SELECT r.id, r.vid, r.rid, r.summary, r.text, r.spoiler, COALESCE(c.count,0) AS count, r.c_up, r.c_down, uv.vote
+ 'SELECT r.id, r.vid, r.rid, r.summary, r.text, r.spoiler, COALESCE(c.count,0) AS count, r.c_up, r.c_down, uv.vote, r2.id IS NULL AS can
, rel.title AS rtitle, rel.original AS roriginal, rel.type AS rtype, rv.vote AS my
, ', sql_user(), ',', sql_totime('r.date'), 'AS date,', sql_totime('r.lastmod'), 'AS lastmod
FROM reviews r
@@ -87,6 +84,7 @@ TUWF::get qr{/$RE{wid}(?:(?<sep>[\./])$RE{num})?}, sub {
LEFT JOIN ulist_vns uv ON uv.uid = r.uid AND uv.vid = r.vid
LEFT JOIN (SELECT id, COUNT(*) FROM reviews_posts GROUP BY id) AS c(id,count) ON c.id = r.id
LEFT JOIN reviews_votes rv ON rv.id = r.id AND rv.uid =', \auth->uid, '
+ LEFT JOIN reviews r2 ON r2.vid = r.vid AND r2.uid =', \auth->uid, '
WHERE r.id =', \$id
);
return tuwf->resNotFound if !$w->{id};
@@ -113,7 +111,7 @@ TUWF::get qr{/$RE{wid}(?:(?<sep>[\./])$RE{num})?}, sub {
VNWeb::VN::Page::enrich_vn($v);
framework_ title => "Review of $v->{title}", index => 1, type => 'v', dbobj => $v, hiddenmsg => 1,
- js => 1, pagevars => {sethash=>$num?$num:$page>1?'threadstart':'review'},
+ pagevars => {sethash=>$num?$num:$page>1?'threadstart':'review'},
sub {
VNWeb::VN::Page::infobox_($v);
VNWeb::VN::Page::tabs_($v, 'reviews');
diff --git a/lib/VNWeb/Reviews/VNTab.pm b/lib/VNWeb/Reviews/VNTab.pm
index 95fc18aa..c2a6dee6 100644
--- a/lib/VNWeb/Reviews/VNTab.pm
+++ b/lib/VNWeb/Reviews/VNTab.pm
@@ -1,6 +1,7 @@
package VNWeb::Reviews::VNTab;
use VNWeb::Prelude;
+use VNWeb::Reviews::Lib;
sub reviews_ {
@@ -10,12 +11,13 @@ sub reviews_ {
# TODO: Order
my $lst = tuwf->dbAlli(
- 'SELECT r.id, r.rid, r.summary, r.text <> \'\' AS isfull, r.spoiler, r.c_up, r.c_down, r.c_count, uv.vote, rv.vote AS my
+ 'SELECT r.id, r.rid, r.summary, r.text <> \'\' AS isfull, r.spoiler, r.c_up, r.c_down, r.c_count, uv.vote, rv.vote AS my, r2.id IS NULL AS can
, ', sql_totime('r.date'), 'AS date, ', sql_user(), '
FROM reviews r
LEFT JOIN users u ON r.uid = u.id
LEFT JOIN ulist_vns uv ON uv.uid = r.uid AND uv.vid = r.vid
LEFT JOIN reviews_votes rv ON rv.uid =', \auth->uid, ' AND rv.id = r.id
+ LEFT JOIN reviews r2 ON r2.vid = r.vid AND r2.uid =', \auth->uid, '
WhERE r.vid =', \$v->{id}
);
@@ -53,9 +55,7 @@ sub reviews_ {
div_ sub {
a_ href => "/$r->{id}#review", 'Full review ยป' if $r->{isfull};
a_ href => "/$r->{id}#threadstart", $r->{c_count} == 1 ? '1 comment' : "$r->{c_count} comments";
- elm_ 'Reviews.Vote' => $VNWeb::Reviews::Elm::VOTE_OUT, { %$r, can => auth && $r->{user_id} != auth->uid }, sub {
- span_ sprintf '๐Ÿ‘ %d ๐Ÿ‘Ž %d', $r->{c_up}, $r->{c_down};
- };
+ review_vote_ $r;
};
} for @$lst;
}
diff --git a/sql/func.sql b/sql/func.sql
index da06450f..215f87c1 100644
--- a/sql/func.sql
+++ b/sql/func.sql
@@ -183,10 +183,11 @@ END; $$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION update_reviews_votes_cache(vndbid) RETURNS void AS $$
BEGIN
WITH stats(id,up,down) AS (
- SELECT r.id, COUNT(*) FILTER(WHERE rv.vote AND NOT u.ign_votes), COUNT(*) FILTER(WHERE NOT rv.vote AND NOT u.ign_votes)
+ SELECT r.id, COUNT(*) FILTER(WHERE rv.vote AND NOT u.ign_votes AND r2.id IS NULL), COUNT(*) FILTER(WHERE NOT rv.vote AND NOT u.ign_votes AND r2.id IS NULL)
FROM reviews r
LEFT JOIN reviews_votes rv ON rv.id = r.id
LEFT JOIN users u ON u.id = rv.uid
+ LEFT JOIN reviews r2 ON r2.vid = r.vid AND r2.uid = rv.uid
WHERE $1 IS NULL OR r.id = $1
GROUP BY r.id
)