mirror of
https://github.com/minetest/contentdb.git
synced 2024-12-23 06:22:24 +01:00
Add review votes page
This commit is contained in:
parent
e346587111
commit
8f4e214c52
@ -13,6 +13,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
from . import bp
|
from . import bp
|
||||||
|
|
||||||
@ -21,8 +22,8 @@ from flask_login import current_user, login_required
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import *
|
from wtforms import *
|
||||||
from wtforms.validators import *
|
from wtforms.validators import *
|
||||||
from app.models import db, PackageReview, Thread, ThreadReply, NotificationType, PackageReviewVote, Package
|
from app.models import db, PackageReview, Thread, ThreadReply, NotificationType, PackageReviewVote, Package, UserRank
|
||||||
from app.utils import is_package_page, addNotification, get_int_or_abort, isYes, is_safe_url
|
from app.utils import is_package_page, addNotification, get_int_or_abort, isYes, is_safe_url, rank_required
|
||||||
from app.tasks.webhooktasks import post_discord_webhook
|
from app.tasks.webhooktasks import post_discord_webhook
|
||||||
|
|
||||||
|
|
||||||
@ -190,3 +191,34 @@ def review_vote(package, review_id):
|
|||||||
return redirect(next_url)
|
return redirect(next_url)
|
||||||
else:
|
else:
|
||||||
return redirect(review.thread.getViewURL())
|
return redirect(review.thread.getViewURL())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/packages/<author>/<name>/review-votes/")
|
||||||
|
@rank_required(UserRank.ADMIN)
|
||||||
|
@is_package_page
|
||||||
|
def review_votes(package):
|
||||||
|
user_biases = {}
|
||||||
|
for review in package.reviews:
|
||||||
|
review_sign = 1 if review.recommends else -1
|
||||||
|
for vote in review.votes:
|
||||||
|
user_biases[vote.user.username] = user_biases.get(vote.user.username, [0, 0])
|
||||||
|
vote_sign = 1 if vote.is_positive else -1
|
||||||
|
vote_bias = review_sign * vote_sign
|
||||||
|
if vote_bias == 1:
|
||||||
|
user_biases[vote.user.username][0] += 1
|
||||||
|
else:
|
||||||
|
user_biases[vote.user.username][1] += 1
|
||||||
|
|
||||||
|
BiasInfo = namedtuple("BiasInfo", "username balance with_ against no_vote perc_with")
|
||||||
|
user_biases_info = []
|
||||||
|
for username, bias in user_biases.items():
|
||||||
|
total_votes = bias[0] + bias[1]
|
||||||
|
balance = bias[0] - bias[1]
|
||||||
|
perc_with = round((100 * bias[0]) / total_votes)
|
||||||
|
user_biases_info.append(BiasInfo(username, balance, bias[0], bias[1], len(package.reviews) - total_votes, perc_with))
|
||||||
|
|
||||||
|
user_biases_info.sort(key=lambda x: -abs(x.balance))
|
||||||
|
|
||||||
|
return render_template("packages/review_votes.html", form=form, package=package, reviews=package.reviews,
|
||||||
|
user_biases=user_biases_info)
|
89
app/templates/packages/review_votes.html
Normal file
89
app/templates/packages/review_votes.html
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{{ _("Review Votes") }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block link %}
|
||||||
|
<a href="{{ package.getURL("packages.view") }}">{{ package.title }}</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ _("Review votes on %(title)s by %(author)s", title=self.link(), author=package.author.display_name) }}</h1>
|
||||||
|
|
||||||
|
<h2>Helpful Biases</h2>
|
||||||
|
{% set total_reviews = reviews | length %}
|
||||||
|
<p>
|
||||||
|
This section shows whether users tend vote in a way that agrees or disagrees with a package.
|
||||||
|
Total reviews: {{ total_reviews }}.
|
||||||
|
</p>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Balance</th>
|
||||||
|
<th>With Pkg</th>
|
||||||
|
<th>Against Pkg</th>
|
||||||
|
<th>No Vote</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for info in user_biases %}
|
||||||
|
{% set total_votes = info.with_ + info.against %}
|
||||||
|
<tr
|
||||||
|
{% if total_votes > 3 and total_votes > total_reviews * 0.5 and ((info.balance / total_votes) | abs) > 0.8 %}
|
||||||
|
style="color: #e74c3c;"
|
||||||
|
{% elif total_votes > 3 and ((info.balance / total_votes) | abs) > 0.9 %}
|
||||||
|
style="color: #f39c12;"
|
||||||
|
{% endif %}>
|
||||||
|
<td>{{ info.username }}</td>
|
||||||
|
<td>{{ info.balance }}</td>
|
||||||
|
<td>{{ info.with_ }} ({{ info.perc_with }}%)</td>
|
||||||
|
<td>{{ info.against }} ({{ 100 - info.perc_with }}%)</td>
|
||||||
|
<td>{{ info.no_vote }}</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr><td colspan=3><i>No votes</i></td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Reviews</h2>
|
||||||
|
<table class="table">
|
||||||
|
{% for review in reviews %}
|
||||||
|
<tr>
|
||||||
|
<th colspan="2">
|
||||||
|
{% if review.recommends %}
|
||||||
|
<i class="fas fa-thumbs-up text-success mr-2"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="fas fa-thumbs-down text-danger mr-2"></i>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ review.thread.getViewURL() }}">
|
||||||
|
{{ review.thread.title }}
|
||||||
|
</a> by {{ review.author.display_name }}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{% for vote in review.votes %}
|
||||||
|
{% if vote.is_positive %}
|
||||||
|
<a href="{{ url_for('users.profile', username=vote.user.username) }}" class="badge badge-secondary">
|
||||||
|
{{ vote.user.username }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% for vote in review.votes %}
|
||||||
|
{% if not vote.is_positive %}
|
||||||
|
<a href="{{ url_for('users.profile', username=vote.user.username) }}" class="badge badge-secondary">
|
||||||
|
{{ vote.user.username }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
@ -283,6 +283,11 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{{ render_review_preview(package) }}
|
{{ render_review_preview(package) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if current_user.is_authenticated and current_user.rank.atLeast(current_user.rank.ADMIN) %}
|
||||||
|
<a href="{{ package.getURL('packages.review_votes') }}" class="btn btn-secondary">Review Votes</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{{ render_reviews(package.reviews, current_user) }}
|
{{ render_reviews(package.reviews, current_user) }}
|
||||||
|
|
||||||
{% if packages_uses %}
|
{% if packages_uses %}
|
||||||
|
Loading…
Reference in New Issue
Block a user