interpretation voting

This commit is contained in:
SvyatoslavArtymovych 2023-05-09 17:56:29 +03:00
parent 706c9463be
commit cdbd530f38
8 changed files with 197 additions and 5 deletions

19
.vscode/settings.json vendored
View File

@ -2,7 +2,7 @@
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"python.formatting.provider": "none",
"python.terminal.activateEnvironment": true,
"files.watcherExclude": {
"**/.git/objects/**": true,
@ -25,8 +25,19 @@
"wsgi",
"wtforms"
],
"python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "*test.py"],
"python.testing.unittestArgs": [
"-v",
"-s",
"./tests",
"-p",
"*test.py"
],
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestArgs": ["tests"]
}
"python.testing.pytestArgs": [
"tests"
],
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
}
}

View File

@ -15,7 +15,6 @@ migration = Migrate()
def create_app(environment="development"):
from config import config
from app.views import (
main_blueprint,
@ -24,6 +23,7 @@ def create_app(environment="development"):
book_blueprint,
home_blueprint,
section_blueprint,
vote_blueprint,
)
from app.models import (
User,
@ -52,6 +52,7 @@ def create_app(environment="development"):
app.register_blueprint(book_blueprint)
app.register_blueprint(home_blueprint)
app.register_blueprint(section_blueprint)
app.register_blueprint(vote_blueprint)
# Set up flask login.
@login_manager.user_loader

View File

@ -11,3 +11,4 @@ from .collection import CreateCollectionForm, EditCollectionForm
from .section import CreateSectionForm, EditSectionForm
from .interpretation import CreateInterpretationForm, EditInterpretationForm
from .comment import CreateCommentForm
from .vote import VoteForm

6
app/forms/vote.py Normal file
View File

@ -0,0 +1,6 @@
from flask_wtf import FlaskForm
from wtforms import BooleanField
class VoteForm(FlaskForm):
positive = BooleanField("Positive")

View File

@ -27,5 +27,17 @@ class Interpretation(BaseModel):
back_populates="interpretations",
)
@property
def vote_count(self):
count = 0
for vote in self.votes:
if vote.positive:
count += 1
else:
count -= 1
return count
def __repr__(self):
return f"<{self.id}: {self.label}>"

View File

@ -5,3 +5,4 @@ from .user import bp as user_blueprint
from .book import bp as book_blueprint
from .home import bp as home_blueprint
from .section import bp as section_blueprint
from .vote import bp as vote_blueprint

67
app/views/vote.py Normal file
View File

@ -0,0 +1,67 @@
from flask import (
Blueprint,
jsonify,
)
from flask_login import login_required, current_user
from app import models as m, db, forms as f
from app.logger import log
bp = Blueprint("vote", __name__, url_prefix="/vote")
@bp.route(
"/interpretation/<int:interpretation_id>",
methods=["POST"],
)
@login_required
def vote_interpretation(interpretation_id: int):
interpretation: m.Interpretation = db.session.get(
m.Interpretation, interpretation_id
)
if not interpretation:
log(log.WARNING, "Interpretation with id [%s] not found", interpretation_id)
return jsonify({"message": "Interpretation not found"}), 404
form = f.VoteForm()
if form.validate_on_submit():
vote: m.InterpretationVote = m.InterpretationVote.query.filter_by(
user_id=current_user.id, interpretation_id=interpretation_id
).first()
if vote:
db.session.delete(vote)
positive = form.positive.data and "True" in form.positive.raw_data
if not vote or vote.positive != positive:
vote: m.InterpretationVote = m.InterpretationVote(
user_id=current_user.id,
interpretation_id=interpretation_id,
positive=positive,
)
log(
log.INFO,
"User [%s]. [%s] vote interpretation: [%s]",
current_user,
"Positive" if positive else "Negative",
interpretation,
)
vote.save(False)
else:
log(
log.INFO,
"User [%s]. Remove [%s] vote for interpretation: [%s]",
current_user,
"positive" if positive else "negative",
interpretation,
)
db.session.commit()
return jsonify({"vote_count": interpretation.vote_count})
log(
log.CRITICAL,
"Unexpected error: User [%s]. Vote for interpretation: [%s]",
current_user,
interpretation,
)
return jsonify({"message": "Unexpected error"}), 400

93
tests/test_upvote.py Normal file
View File

@ -0,0 +1,93 @@
from flask import current_app as Response
from flask.testing import FlaskClient
from app import models as m
from tests.utils import login
def test_upvote(client: FlaskClient):
_, user = login(client)
response: Response = client.post(
"/vote/interpretation/999",
data=dict(
positive=True,
),
follow_redirects=True,
)
assert response
assert response.status_code == 404
assert response.json["message"] == "Interpretation not found"
interpretation = m.Interpretation(
label="Test Interpretation 1 Label",
text="Test Interpretation 1 Text",
user_id=user.id,
).save()
assert interpretation.vote_count == 0
response: Response = client.post(
f"/vote/interpretation/{interpretation.id}",
data=dict(
positive=True,
),
follow_redirects=True,
)
assert response
assert response.status_code == 200
json = response.json
assert json
assert "vote_count" in json
assert json["vote_count"] == 1
assert interpretation.vote_count == 1
response: Response = client.post(
f"/vote/interpretation/{interpretation.id}",
data=dict(
positive=True,
),
follow_redirects=True,
)
assert response
assert response.status_code == 200
json = response.json
assert json
assert "vote_count" in json
assert json["vote_count"] == 0
assert interpretation.vote_count == 0
response: Response = client.post(
f"/vote/interpretation/{interpretation.id}",
data=dict(
positive=False,
),
follow_redirects=True,
)
assert response
assert response.status_code == 200
json = response.json
assert json
assert "vote_count" in json
assert json["vote_count"] == -1
assert interpretation.vote_count == -1
response: Response = client.post(
f"/vote/interpretation/{interpretation.id}",
data=dict(
# positive=False,
),
follow_redirects=True,
)
assert response
assert response.status_code == 200
json = response.json
assert json
assert "vote_count" in json
assert json["vote_count"] == 0
assert interpretation.vote_count == 0