[odrs-web] Blacken the codebase
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [odrs-web] Blacken the codebase
- Date: Thu, 17 Mar 2022 13:04:50 +0000 (UTC)
commit d2d8a89638e16223cfed24f9c5215d611a217740
Author: Richard Hughes <richard hughsie com>
Date: Wed Mar 16 20:19:46 2022 +0000
Blacken the codebase
app_data/Makefile | 18 +
app_data/migrations/env.py | 39 +-
app_data/migrations/versions/036f0cd034e5_.py | 10 +-
app_data/migrations/versions/19526c284b29_.py | 47 +-
app_data/migrations/versions/1b966aab67a1_.py | 21 +-
app_data/migrations/versions/64751cf97429_.py | 6 +-
app_data/migrations/versions/6f54fde07d02_.py | 26 +-
app_data/migrations/versions/7c3432c40267_.py | 13 +-
app_data/migrations/versions/84deb10331db_.py | 27 +-
app_data/migrations/versions/a22c286d8094_.py | 9 +-
app_data/migrations/versions/b2d75ba212ed_.py | 9 +-
app_data/migrations/versions/b63a028c3346_.py | 22 +-
app_data/migrations/versions/b8243269e9cf_.py | 31 +-
app_data/migrations/versions/bbbcd54c69ac_.py | 109 ++--
app_data/migrations/versions/e37c745e3097_.py | 29 +-
app_data/migrations/versions/e6fa15874247_.py | 41 +-
app_data/migrations/versions/ef03b3a98056_.py | 230 +++----
app_data/migrations/versions/f32bd8265c3b_.py | 21 +-
app_data/odrs/__init__.py | 38 +-
app_data/odrs/dbutils.py | 21 +-
app_data/odrs/models.py | 214 ++++---
app_data/odrs/tests/odrs_test.py | 670 +++++++++++---------
app_data/odrs/tests/util_test.py | 49 +-
app_data/odrs/util.py | 140 +++--
app_data/odrs/views.py | 112 ++--
app_data/odrs/views_admin.py | 863 +++++++++++++++-----------
app_data/odrs/views_api.py | 486 +++++++++------
27 files changed, 1933 insertions(+), 1368 deletions(-)
---
diff --git a/app_data/Makefile b/app_data/Makefile
index 9526480..423355e 100644
--- a/app_data/Makefile
+++ b/app_data/Makefile
@@ -42,3 +42,21 @@ check: $(PYTEST)
--cov=odrs \
--cov-report=html
$(PYTHON) ./pylint_test.py
+
+blacken:
+ find migrations odrs -name '*.py' -exec ./env/bin/black {} \;
+
+codespell: $(CODESPELL)
+ $(CODESPELL) --write-changes --builtin en-GB_to_en-US --skip \
+ .git,\
+ .mypy_cache,\
+ .coverage,\
+ *.pyc,\
+ *.png,\
+ *.jpg,\
+ *.js,\
+ *.doctree,\
+ *.pdf,\
+ *.gz,\
+ *.ico,\
+ env
diff --git a/app_data/migrations/env.py b/app_data/migrations/env.py
index 5eeddd3..148c7ff 100644
--- a/app_data/migrations/env.py
+++ b/app_data/migrations/env.py
@@ -11,16 +11,18 @@ config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
-logger = logging.getLogger('alembic.env')
+logger = logging.getLogger("alembic.env")
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
-config.set_main_option('sqlalchemy.url',
- current_app.config.get('SQLALCHEMY_DATABASE_URI'))
-target_metadata = current_app.extensions['migrate'].db.metadata
+
+config.set_main_option(
+ "sqlalchemy.url", current_app.config.get("SQLALCHEMY_DATABASE_URI")
+)
+target_metadata = current_app.extensions["migrate"].db.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
@@ -30,6 +32,7 @@ target_metadata = current_app.extensions['migrate'].db.metadata
# set to True to detect type changes in a better way (with false positives)
COMPARE_TYPES = False
+
def run_migrations_offline():
"""Run migrations in 'offline' mode.
@@ -43,8 +46,7 @@ def run_migrations_offline():
"""
url = config.get_main_option("sqlalchemy.url")
- context.configure(compare_type=COMPARE_TYPES,
- url=url)
+ context.configure(compare_type=COMPARE_TYPES, url=url)
with context.begin_transaction():
context.run_migrations()
@@ -62,22 +64,26 @@ def run_migrations_online():
# when there are no changes to the schema
# reference: http://alembic.readthedocs.org/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
- if getattr(config.cmd_opts, 'autogenerate', False):
+ if getattr(config.cmd_opts, "autogenerate", False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
- logger.info('No changes in schema detected.')
+ logger.info("No changes in schema detected.")
- engine = engine_from_config(config.get_section(config.config_ini_section),
- prefix='sqlalchemy.',
- poolclass=pool.NullPool)
+ engine = engine_from_config(
+ config.get_section(config.config_ini_section),
+ prefix="sqlalchemy.",
+ poolclass=pool.NullPool,
+ )
connection = engine.connect()
- context.configure(connection=connection,
- compare_type=COMPARE_TYPES,
- target_metadata=target_metadata,
- process_revision_directives=process_revision_directives,
- **current_app.extensions['migrate'].configure_args)
+ context.configure(
+ connection=connection,
+ compare_type=COMPARE_TYPES,
+ target_metadata=target_metadata,
+ process_revision_directives=process_revision_directives,
+ **current_app.extensions["migrate"].configure_args
+ )
try:
with context.begin_transaction():
@@ -85,6 +91,7 @@ def run_migrations_online():
finally:
connection.close()
+
if context.is_offline_mode():
run_migrations_offline()
else:
diff --git a/app_data/migrations/versions/036f0cd034e5_.py b/app_data/migrations/versions/036f0cd034e5_.py
index 020e9f3..e775d87 100644
--- a/app_data/migrations/versions/036f0cd034e5_.py
+++ b/app_data/migrations/versions/036f0cd034e5_.py
@@ -7,15 +7,17 @@ Create Date: 2019-07-03 11:39:22.323579
"""
# revision identifiers, used by Alembic.
-revision = '036f0cd034e5'
-down_revision = 'b63a028c3346'
+revision = "036f0cd034e5"
+down_revision = "b63a028c3346"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.create_foreign_key(None, 'votes', 'reviews', ['review_id'], ['review_id'])
+ op.create_foreign_key(None, "votes", "reviews", ["review_id"], ["review_id"])
+
def downgrade():
- op.drop_constraint(None, 'votes', type_='foreignkey')
+ op.drop_constraint(None, "votes", type_="foreignkey")
diff --git a/app_data/migrations/versions/19526c284b29_.py b/app_data/migrations/versions/19526c284b29_.py
index 55cdc8a..8df85cf 100644
--- a/app_data/migrations/versions/19526c284b29_.py
+++ b/app_data/migrations/versions/19526c284b29_.py
@@ -7,8 +7,8 @@ Create Date: 2019-07-02 10:51:23.952062
"""
# revision identifiers, used by Alembic.
-revision = '19526c284b29'
-down_revision = '84deb10331db'
+revision = "19526c284b29"
+down_revision = "84deb10331db"
from alembic import op
import sqlalchemy as sa
@@ -18,60 +18,63 @@ from sqlalchemy.exc import InternalError
from odrs import db
from odrs.models import User, Moderator, Event, Review, Vote
+
def _hash_to_id(user_hash):
user = db.session.query(User).filter(User.user_hash == user_hash).first()
if not user:
return None
return user.user_id
+
def upgrade():
try:
- op.add_column('eventlog', sa.Column('user_id', sa.Integer(), nullable=True))
- op.create_foreign_key(None, 'eventlog', 'users', ['user_id'], ['user_id'])
+ op.add_column("eventlog", sa.Column("user_id", sa.Integer(), nullable=True))
+ op.create_foreign_key(None, "eventlog", "users", ["user_id"], ["user_id"])
except InternalError as _:
pass
try:
- op.add_column('moderators', sa.Column('user_id', sa.Integer(), nullable=True))
- op.create_foreign_key(None, 'moderators', 'users', ['user_id'], ['user_id'])
+ op.add_column("moderators", sa.Column("user_id", sa.Integer(), nullable=True))
+ op.create_foreign_key(None, "moderators", "users", ["user_id"], ["user_id"])
except InternalError as _:
pass
try:
- op.add_column('reviews', sa.Column('user_id', sa.Integer(), nullable=True))
- op.create_foreign_key(None, 'reviews', 'users', ['user_id'], ['user_id'])
+ op.add_column("reviews", sa.Column("user_id", sa.Integer(), nullable=True))
+ op.create_foreign_key(None, "reviews", "users", ["user_id"], ["user_id"])
except InternalError as _:
pass
try:
- op.add_column('votes', sa.Column('user_id', sa.Integer(), nullable=True))
- op.create_foreign_key(None, 'votes', 'users', ['user_id'], ['user_id'])
+ op.add_column("votes", sa.Column("user_id", sa.Integer(), nullable=True))
+ op.create_foreign_key(None, "votes", "users", ["user_id"], ["user_id"])
except InternalError as _:
pass
- print('CONVERTING Event')
+ print("CONVERTING Event")
for val in db.session.query(Event).all():
val.user_id = _hash_to_id(val.user_hash)
db.session.commit()
- print('CONVERTING Moderator')
+ print("CONVERTING Moderator")
for val in db.session.query(Moderator).all():
val.user_id = _hash_to_id(val.user_hash)
db.session.commit()
- print('CONVERTING Review')
+ print("CONVERTING Review")
for val in db.session.query(Review).all():
val.user_id = _hash_to_id(val.user_hash)
db.session.commit()
- print('CONVERTING Vote')
+ print("CONVERTING Vote")
for val in db.session.query(Vote).all():
val.user_id = _hash_to_id(val.user_hash)
db.session.commit()
+
def downgrade():
- op.drop_constraint(None, 'votes', type_='foreignkey')
- op.drop_constraint(None, 'reviews', type_='foreignkey')
- op.drop_constraint(None, 'moderators', type_='foreignkey')
- op.drop_constraint(None, 'eventlog', type_='foreignkey')
- op.drop_column('votes', 'user_id')
- op.drop_column('reviews', 'user_id')
- op.drop_column('moderators', 'user_id')
- op.drop_column('eventlog', 'user_id')
+ op.drop_constraint(None, "votes", type_="foreignkey")
+ op.drop_constraint(None, "reviews", type_="foreignkey")
+ op.drop_constraint(None, "moderators", type_="foreignkey")
+ op.drop_constraint(None, "eventlog", type_="foreignkey")
+ op.drop_column("votes", "user_id")
+ op.drop_column("reviews", "user_id")
+ op.drop_column("moderators", "user_id")
+ op.drop_column("eventlog", "user_id")
diff --git a/app_data/migrations/versions/1b966aab67a1_.py b/app_data/migrations/versions/1b966aab67a1_.py
index 0e70b76..a03654b 100644
--- a/app_data/migrations/versions/1b966aab67a1_.py
+++ b/app_data/migrations/versions/1b966aab67a1_.py
@@ -7,8 +7,8 @@ Create Date: 2019-07-01 19:44:32.916028
"""
# revision identifiers, used by Alembic.
-revision = '1b966aab67a1'
-down_revision = 'b8243269e9cf'
+revision = "1b966aab67a1"
+down_revision = "b8243269e9cf"
from alembic import op
import sqlalchemy as sa
@@ -16,17 +16,24 @@ from sqlalchemy.dialects import mysql
from odrs import db
+
class OldModerator(db.Model):
- __tablename__ = 'moderators'
- __table_args__ = {'mysql_character_set': 'utf8mb4',
- 'extend_existing': True}
+ __tablename__ = "moderators"
+ __table_args__ = {"mysql_character_set": "utf8mb4", "extend_existing": True}
email = db.Column(db.Text)
+
def upgrade():
for mod in db.session.query(OldModerator).all():
mod.username = mod.email
db.session.commit()
- op.drop_column('moderators', 'email')
+ op.drop_column("moderators", "email")
+
def downgrade():
- op.add_column('moderators', sa.Column('email', mysql.MEDIUMTEXT(collation='utf8mb4_unicode_ci'),
nullable=True))
+ op.add_column(
+ "moderators",
+ sa.Column(
+ "email", mysql.MEDIUMTEXT(collation="utf8mb4_unicode_ci"), nullable=True
+ ),
+ )
diff --git a/app_data/migrations/versions/64751cf97429_.py b/app_data/migrations/versions/64751cf97429_.py
index a67357e..22fad17 100644
--- a/app_data/migrations/versions/64751cf97429_.py
+++ b/app_data/migrations/versions/64751cf97429_.py
@@ -7,17 +7,19 @@ Create Date: 2019-07-03 14:24:53.549481
"""
# revision identifiers, used by Alembic.
-revision = '64751cf97429'
-down_revision = '036f0cd034e5'
+revision = "64751cf97429"
+down_revision = "036f0cd034e5"
from odrs import db
from odrs.models import Review
from odrs.util import _addr_hash
+
def upgrade():
for review in db.session.query(Review).all():
review.user_addr = _addr_hash(review.user_addr_hash)
db.session.commit()
+
def downgrade():
pass
diff --git a/app_data/migrations/versions/6f54fde07d02_.py b/app_data/migrations/versions/6f54fde07d02_.py
index 3a55ae1..ed0c489 100644
--- a/app_data/migrations/versions/6f54fde07d02_.py
+++ b/app_data/migrations/versions/6f54fde07d02_.py
@@ -7,8 +7,8 @@ Create Date: 2019-07-04 11:58:24.685366
"""
# revision identifiers, used by Alembic.
-revision = '6f54fde07d02'
-down_revision = 'e6fa15874247'
+revision = "6f54fde07d02"
+down_revision = "e6fa15874247"
from alembic import op
import sqlalchemy as sa
@@ -18,21 +18,29 @@ from sqlalchemy.exc import InternalError
from odrs import db
from odrs.models import Analytic, Component
+
def upgrade():
try:
- op.add_column('components', sa.Column('fetch_cnt', sa.Integer(), nullable=True))
+ op.add_column("components", sa.Column("fetch_cnt", sa.Integer(), nullable=True))
except InternalError as e:
print(str(e))
- for component in db.session.query(Component).\
- filter(Component.app_id != '').\
- order_by(Component.app_id.asc()).all():
+ for component in (
+ db.session.query(Component)
+ .filter(Component.app_id != "")
+ .order_by(Component.app_id.asc())
+ .all()
+ ):
fetch_cnt = 0
- for val in db.session.query(Analytic.fetch_cnt).\
- filter(Analytic.app_id == component.app_id).all():
+ for val in (
+ db.session.query(Analytic.fetch_cnt)
+ .filter(Analytic.app_id == component.app_id)
+ .all()
+ ):
fetch_cnt += val[0]
component.fetch_cnt = fetch_cnt
print(component.app_id, fetch_cnt)
db.session.commit()
+
def downgrade():
- op.drop_column('components', 'fetch_cnt')
+ op.drop_column("components", "fetch_cnt")
diff --git a/app_data/migrations/versions/7c3432c40267_.py b/app_data/migrations/versions/7c3432c40267_.py
index e0d465d..4a89dc5 100644
--- a/app_data/migrations/versions/7c3432c40267_.py
+++ b/app_data/migrations/versions/7c3432c40267_.py
@@ -7,22 +7,24 @@ Create Date: 2019-07-05 14:29:46.410656
"""
# revision identifiers, used by Alembic.
-revision = '7c3432c40267'
-down_revision = 'ef03b3a98056'
+revision = "7c3432c40267"
+down_revision = "ef03b3a98056"
from odrs import db
from odrs.models import Component
+
def upgrade():
seen = {}
- for component in db.session.query(Component).\
- order_by(Component.review_cnt.asc()).all():
+ for component in (
+ db.session.query(Component).order_by(Component.review_cnt.asc()).all()
+ ):
if component.app_id not in seen:
seen[component.app_id] = component
continue
component_old = seen[component.app_id]
- print('duplicate', component.app_id, component.review_cnt)
+ print("duplicate", component.app_id, component.review_cnt)
if component.review_cnt and component_old.review_cnt:
component_old.review_cnt += component.review_cnt
elif component.review_cnt:
@@ -38,5 +40,6 @@ def upgrade():
db.session.delete(component)
db.session.commit()
+
def downgrade():
pass
diff --git a/app_data/migrations/versions/84deb10331db_.py b/app_data/migrations/versions/84deb10331db_.py
index 3d90ebe..3257fc8 100644
--- a/app_data/migrations/versions/84deb10331db_.py
+++ b/app_data/migrations/versions/84deb10331db_.py
@@ -7,22 +7,29 @@ Create Date: 2019-07-02 10:26:30.036790
"""
# revision identifiers, used by Alembic.
-revision = '84deb10331db'
-down_revision = 'bbbcd54c69ac'
+revision = "84deb10331db"
+down_revision = "bbbcd54c69ac"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.alter_column('users', 'user_hash',
- existing_type=mysql.TEXT(),
- type_=sa.String(length=40),
- existing_nullable=True)
+ op.alter_column(
+ "users",
+ "user_hash",
+ existing_type=mysql.TEXT(),
+ type_=sa.String(length=40),
+ existing_nullable=True,
+ )
def downgrade():
- op.alter_column('users', 'user_hash',
- existing_type=sa.String(length=40),
- type_=mysql.TEXT(),
- existing_nullable=True)
+ op.alter_column(
+ "users",
+ "user_hash",
+ existing_type=sa.String(length=40),
+ type_=mysql.TEXT(),
+ existing_nullable=True,
+ )
diff --git a/app_data/migrations/versions/a22c286d8094_.py b/app_data/migrations/versions/a22c286d8094_.py
index e65e9ba..aa53cbc 100644
--- a/app_data/migrations/versions/a22c286d8094_.py
+++ b/app_data/migrations/versions/a22c286d8094_.py
@@ -7,16 +7,17 @@ Create Date: 2019-07-04 13:50:13.788206
"""
# revision identifiers, used by Alembic.
-revision = 'a22c286d8094'
-down_revision = '6f54fde07d02'
+revision = "a22c286d8094"
+down_revision = "6f54fde07d02"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.drop_column('reviews', 'app_id')
+ op.drop_column("reviews", "app_id")
def downgrade():
- op.add_column('reviews', sa.Column('app_id', mysql.TEXT(), nullable=True))
+ op.add_column("reviews", sa.Column("app_id", mysql.TEXT(), nullable=True))
diff --git a/app_data/migrations/versions/b2d75ba212ed_.py b/app_data/migrations/versions/b2d75ba212ed_.py
index 265cd89..1b79e12 100644
--- a/app_data/migrations/versions/b2d75ba212ed_.py
+++ b/app_data/migrations/versions/b2d75ba212ed_.py
@@ -7,16 +7,17 @@ Create Date: 2019-07-04 09:07:17.032627
"""
# revision identifiers, used by Alembic.
-revision = 'b2d75ba212ed'
-down_revision = 'e37c745e3097'
+revision = "b2d75ba212ed"
+down_revision = "e37c745e3097"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.add_column('taboos', sa.Column('severity', sa.Integer(), nullable=True))
+ op.add_column("taboos", sa.Column("severity", sa.Integer(), nullable=True))
def downgrade():
- op.drop_column('taboos', 'severity')
+ op.drop_column("taboos", "severity")
diff --git a/app_data/migrations/versions/b63a028c3346_.py b/app_data/migrations/versions/b63a028c3346_.py
index 8ed375b..10344e2 100644
--- a/app_data/migrations/versions/b63a028c3346_.py
+++ b/app_data/migrations/versions/b63a028c3346_.py
@@ -7,21 +7,23 @@ Create Date: 2019-07-02 11:13:57.117376
"""
# revision identifiers, used by Alembic.
-revision = 'b63a028c3346'
-down_revision = '19526c284b29'
+revision = "b63a028c3346"
+down_revision = "19526c284b29"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.drop_column('eventlog', 'user_hash')
- op.drop_column('moderators', 'user_hash')
- op.drop_column('reviews', 'user_hash')
- op.drop_column('votes', 'user_hash')
+ op.drop_column("eventlog", "user_hash")
+ op.drop_column("moderators", "user_hash")
+ op.drop_column("reviews", "user_hash")
+ op.drop_column("votes", "user_hash")
+
def downgrade():
- op.add_column('votes', sa.Column('user_hash', mysql.TEXT(), nullable=True))
- op.add_column('reviews', sa.Column('user_hash', mysql.TEXT(), nullable=True))
- op.add_column('moderators', sa.Column('user_hash', mysql.TEXT(), nullable=True))
- op.add_column('eventlog', sa.Column('user_hash', mysql.TEXT(), nullable=True))
+ op.add_column("votes", sa.Column("user_hash", mysql.TEXT(), nullable=True))
+ op.add_column("reviews", sa.Column("user_hash", mysql.TEXT(), nullable=True))
+ op.add_column("moderators", sa.Column("user_hash", mysql.TEXT(), nullable=True))
+ op.add_column("eventlog", sa.Column("user_hash", mysql.TEXT(), nullable=True))
diff --git a/app_data/migrations/versions/b8243269e9cf_.py b/app_data/migrations/versions/b8243269e9cf_.py
index 1d31760..1dc1255 100644
--- a/app_data/migrations/versions/b8243269e9cf_.py
+++ b/app_data/migrations/versions/b8243269e9cf_.py
@@ -7,7 +7,7 @@ Create Date: 2019-06-28 12:39:37.287224
"""
# revision identifiers, used by Alembic.
-revision = 'b8243269e9cf'
+revision = "b8243269e9cf"
down_revision = None
from alembic import op
@@ -18,23 +18,30 @@ from sqlalchemy.dialects import mysql
from odrs import db
from odrs.models import Review
+
def upgrade():
- op.alter_column('reviews', 'date_deleted',
- existing_type=mysql.TIMESTAMP(),
- nullable=True,
- existing_server_default=sa.text("'0000-00-00 00:00:00'"))
+ op.alter_column(
+ "reviews",
+ "date_deleted",
+ existing_type=mysql.TIMESTAMP(),
+ nullable=True,
+ existing_server_default=sa.text("'0000-00-00 00:00:00'"),
+ )
since = datetime.datetime.utcnow() - datetime.timedelta(hours=3)
for review in db.session.query(Review).all():
- if review.date_deleted == '0000-00-00 00:00:00':
- review.date_deleted = None
+ if review.date_deleted == "0000-00-00 00:00:00":
+ review.date_deleted = None
if review.date_deleted and review.date_deleted > since:
- review.date_deleted = None
+ review.date_deleted = None
db.session.commit()
def downgrade():
- op.alter_column('reviews', 'date_deleted',
- existing_type=mysql.TIMESTAMP(),
- nullable=False,
- existing_server_default=sa.text("'0000-00-00 00:00:00'"))
+ op.alter_column(
+ "reviews",
+ "date_deleted",
+ existing_type=mysql.TIMESTAMP(),
+ nullable=False,
+ existing_server_default=sa.text("'0000-00-00 00:00:00'"),
+ )
diff --git a/app_data/migrations/versions/bbbcd54c69ac_.py b/app_data/migrations/versions/bbbcd54c69ac_.py
index 7f4bfd6..6b7d72b 100644
--- a/app_data/migrations/versions/bbbcd54c69ac_.py
+++ b/app_data/migrations/versions/bbbcd54c69ac_.py
@@ -7,54 +7,79 @@ Create Date: 2019-07-02 10:06:20.015220
"""
# revision identifiers, used by Alembic.
-revision = 'bbbcd54c69ac'
-down_revision = '1b966aab67a1'
+revision = "bbbcd54c69ac"
+down_revision = "1b966aab67a1"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.alter_column('eventlog', 'important',
- existing_type=mysql.INTEGER(display_width=11),
- type_=sa.Boolean(),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
- op.alter_column('moderators', 'is_admin',
- existing_type=mysql.TINYINT(display_width=4),
- type_=sa.Boolean(),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
- op.alter_column('moderators', 'is_enabled',
- existing_type=mysql.TINYINT(display_width=4),
- type_=sa.Boolean(),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
- op.alter_column('users', 'is_banned',
- existing_type=mysql.INTEGER(display_width=11),
- type_=sa.Boolean(),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
+ op.alter_column(
+ "eventlog",
+ "important",
+ existing_type=mysql.INTEGER(display_width=11),
+ type_=sa.Boolean(),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
+ op.alter_column(
+ "moderators",
+ "is_admin",
+ existing_type=mysql.TINYINT(display_width=4),
+ type_=sa.Boolean(),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
+ op.alter_column(
+ "moderators",
+ "is_enabled",
+ existing_type=mysql.TINYINT(display_width=4),
+ type_=sa.Boolean(),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
+ op.alter_column(
+ "users",
+ "is_banned",
+ existing_type=mysql.INTEGER(display_width=11),
+ type_=sa.Boolean(),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
def downgrade():
- op.alter_column('users', 'is_banned',
- existing_type=sa.Boolean(),
- type_=mysql.INTEGER(display_width=11),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
- op.alter_column('moderators', 'is_enabled',
- existing_type=sa.Boolean(),
- type_=mysql.TINYINT(display_width=4),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
- op.alter_column('moderators', 'is_admin',
- existing_type=sa.Boolean(),
- type_=mysql.TINYINT(display_width=4),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
- op.alter_column('eventlog', 'important',
- existing_type=sa.Boolean(),
- type_=mysql.INTEGER(display_width=11),
- existing_nullable=True,
- existing_server_default=sa.text('0'))
+ op.alter_column(
+ "users",
+ "is_banned",
+ existing_type=sa.Boolean(),
+ type_=mysql.INTEGER(display_width=11),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
+ op.alter_column(
+ "moderators",
+ "is_enabled",
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=4),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
+ op.alter_column(
+ "moderators",
+ "is_admin",
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=4),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
+ op.alter_column(
+ "eventlog",
+ "important",
+ existing_type=sa.Boolean(),
+ type_=mysql.INTEGER(display_width=11),
+ existing_nullable=True,
+ existing_server_default=sa.text("0"),
+ )
diff --git a/app_data/migrations/versions/e37c745e3097_.py b/app_data/migrations/versions/e37c745e3097_.py
index a8bce80..99a611b 100644
--- a/app_data/migrations/versions/e37c745e3097_.py
+++ b/app_data/migrations/versions/e37c745e3097_.py
@@ -7,25 +7,28 @@ Create Date: 2019-07-03 19:54:01.718718
"""
# revision identifiers, used by Alembic.
-revision = 'e37c745e3097'
-down_revision = '64751cf97429'
+revision = "e37c745e3097"
+down_revision = "64751cf97429"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.create_table('taboos',
- sa.Column('taboo_id', sa.Integer(), nullable=False),
- sa.Column('locale', sa.String(length=8), nullable=False),
- sa.Column('value', sa.Text(), nullable=False),
- sa.Column('description', sa.Text(), nullable=True),
- sa.PrimaryKeyConstraint('taboo_id'),
- sa.UniqueConstraint('taboo_id'),
- mysql_character_set='utf8mb4'
+ op.create_table(
+ "taboos",
+ sa.Column("taboo_id", sa.Integer(), nullable=False),
+ sa.Column("locale", sa.String(length=8), nullable=False),
+ sa.Column("value", sa.Text(), nullable=False),
+ sa.Column("description", sa.Text(), nullable=True),
+ sa.PrimaryKeyConstraint("taboo_id"),
+ sa.UniqueConstraint("taboo_id"),
+ mysql_character_set="utf8mb4",
)
- op.create_index(op.f('ix_taboos_locale'), 'taboos', ['locale'], unique=False)
+ op.create_index(op.f("ix_taboos_locale"), "taboos", ["locale"], unique=False)
+
def downgrade():
- op.drop_index(op.f('ix_taboos_locale'), table_name='taboos')
- op.drop_table('taboos')
+ op.drop_index(op.f("ix_taboos_locale"), table_name="taboos")
+ op.drop_table("taboos")
diff --git a/app_data/migrations/versions/e6fa15874247_.py b/app_data/migrations/versions/e6fa15874247_.py
index 927fa91..dd2f317 100644
--- a/app_data/migrations/versions/e6fa15874247_.py
+++ b/app_data/migrations/versions/e6fa15874247_.py
@@ -7,8 +7,8 @@ Create Date: 2019-07-04 10:44:23.739416
"""
# revision identifiers, used by Alembic.
-revision = 'e6fa15874247'
-down_revision = 'b2d75ba212ed'
+revision = "e6fa15874247"
+down_revision = "b2d75ba212ed"
from alembic import op
import sqlalchemy as sa
@@ -18,21 +18,25 @@ from sqlalchemy.exc import InternalError
from odrs import db
from odrs.models import Review, Component
+
def upgrade():
try:
- op.create_table('components',
- sa.Column('component_id', sa.Integer(), nullable=False),
- sa.Column('app_id', sa.Text(), nullable=True),
- sa.Column('review_cnt', sa.Integer(), nullable=True),
- sa.PrimaryKeyConstraint('component_id'),
- sa.UniqueConstraint('component_id'),
- mysql_character_set='utf8mb4'
+ op.create_table(
+ "components",
+ sa.Column("component_id", sa.Integer(), nullable=False),
+ sa.Column("app_id", sa.Text(), nullable=True),
+ sa.Column("review_cnt", sa.Integer(), nullable=True),
+ sa.PrimaryKeyConstraint("component_id"),
+ sa.UniqueConstraint("component_id"),
+ mysql_character_set="utf8mb4",
)
except InternalError as e:
print(str(e))
try:
- op.add_column('reviews', sa.Column('component_id', sa.Integer(), nullable=False))
+ op.add_column(
+ "reviews", sa.Column("component_id", sa.Integer(), nullable=False)
+ )
except InternalError as e:
print(str(e))
@@ -45,7 +49,7 @@ def upgrade():
reviews = db.session.query(Review).all()
for review in reviews:
if review._app_id not in app_ids:
- print('adding', review._app_id)
+ print("adding", review._app_id)
component = Component(review._app_id)
db.session.add(component)
app_ids[component.app_id] = component
@@ -61,11 +65,18 @@ def upgrade():
# should all be valid now
try:
- op.create_foreign_key('components_ibfk_3', 'reviews', 'components', ['component_id'],
['component_id'])
+ op.create_foreign_key(
+ "components_ibfk_3",
+ "reviews",
+ "components",
+ ["component_id"],
+ ["component_id"],
+ )
except InternalError as e:
print(str(e))
+
def downgrade():
- op.drop_constraint('components_ibfk_3', 'reviews', type_='foreignkey')
- op.drop_column('reviews', 'component_id')
- op.drop_table('components')
+ op.drop_constraint("components_ibfk_3", "reviews", type_="foreignkey")
+ op.drop_column("reviews", "component_id")
+ op.drop_table("components")
diff --git a/app_data/migrations/versions/ef03b3a98056_.py b/app_data/migrations/versions/ef03b3a98056_.py
index a5df523..f8635ea 100644
--- a/app_data/migrations/versions/ef03b3a98056_.py
+++ b/app_data/migrations/versions/ef03b3a98056_.py
@@ -7,127 +7,131 @@ Create Date: 2019-07-05 12:53:17.236904
"""
# revision identifiers, used by Alembic.
-revision = 'ef03b3a98056'
-down_revision = 'f32bd8265c3b'
+revision = "ef03b3a98056"
+down_revision = "f32bd8265c3b"
from odrs import db
from odrs.models import Component
+
def upgrade():
# get all existing components
components = {}
- for component in db.session.query(Component).\
- filter(Component.app_id != '').\
- order_by(Component.app_id.asc()).all():
+ for component in (
+ db.session.query(Component)
+ .filter(Component.app_id != "")
+ .order_by(Component.app_id.asc())
+ .all()
+ ):
components[component.app_id] = component
# from appstream-glib
mapping = {
- 'baobab.desktop': 'org.gnome.baobab.desktop',
- 'bijiben.desktop': 'org.gnome.bijiben.desktop',
- 'cheese.desktop': 'org.gnome.Cheese.desktop',
- 'devhelp.desktop': 'org.gnome.Devhelp.desktop',
- 'epiphany.desktop': 'org.gnome.Epiphany.desktop',
- 'file-roller.desktop': 'org.gnome.FileRoller.desktop',
- 'font-manager.desktop': 'org.gnome.FontManager.desktop',
- 'gcalctool.desktop': 'gnome-calculator.desktop',
- 'gcm-viewer.desktop': 'org.gnome.ColorProfileViewer.desktop',
- 'geary.desktop': 'org.gnome.Geary.desktop',
- 'gedit.desktop': 'org.gnome.gedit.desktop',
- 'glchess.desktop': 'gnome-chess.desktop',
- 'glines.desktop': 'five-or-more.desktop',
- 'gnect.desktop': 'four-in-a-row.desktop',
- 'gnibbles.desktop': 'gnome-nibbles.desktop',
- 'gnobots2.desktop': 'gnome-robots.desktop',
- 'gnome-2048.desktop': 'org.gnome.gnome-2048.desktop',
- 'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
- 'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
- 'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
- 'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
- 'gnome-dictionary.desktop': 'org.gnome.Dictionary.desktop',
- 'gnome-disks.desktop': 'org.gnome.DiskUtility.desktop',
- 'gnome-documents.desktop': 'org.gnome.Documents.desktop',
- 'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
- 'gnome-maps.desktop': 'org.gnome.Maps.desktop',
- 'gnome-nibbles.desktop': 'org.gnome.Nibbles.desktop',
- 'gnome-photos.desktop': 'org.gnome.Photos.desktop',
- 'gnome-power-statistics.desktop': 'org.gnome.PowerStats.desktop',
- 'gnome-screenshot.desktop': 'org.gnome.Screenshot.desktop',
- 'gnome-software.desktop': 'org.gnome.Software.desktop',
- 'gnome-sound-recorder.desktop': 'org.gnome.SoundRecorder.desktop',
- 'gnome-terminal.desktop': 'org.gnome.Terminal.desktop',
- 'gnome-weather.desktop': 'org.gnome.Weather.Application.desktop',
- 'gnomine.desktop': 'gnome-mines.desktop',
- 'gnotravex.desktop': 'gnome-tetravex.desktop',
- 'gnotski.desktop': 'gnome-klotski.desktop',
- 'gtali.desktop': 'tali.desktop',
- 'hitori.desktop': 'org.gnome.Hitori.desktop',
- 'latexila.desktop': 'org.gnome.latexila.desktop',
- 'lollypop.desktop': 'org.gnome.Lollypop.desktop',
- 'nautilus.desktop': 'org.gnome.Nautilus.desktop',
- 'polari.desktop': 'org.gnome.Polari.desktop',
- 'sound-juicer.desktop': 'org.gnome.SoundJuicer.desktop',
- 'totem.desktop': 'org.gnome.Totem.desktop',
- 'akregator.desktop': 'org.kde.akregator.desktop',
- 'apper.desktop': 'org.kde.apper.desktop',
- 'ark.desktop': 'org.kde.ark.desktop',
- 'blinken.desktop': 'org.kde.blinken.desktop',
- 'cantor.desktop': 'org.kde.cantor.desktop',
- 'digikam.desktop': 'org.kde.digikam.desktop',
- 'dolphin.desktop': 'org.kde.dolphin.desktop',
- 'dragonplayer.desktop': 'org.kde.dragonplayer.desktop',
- 'filelight.desktop': 'org.kde.filelight.desktop',
- 'gwenview.desktop': 'org.kde.gwenview.desktop',
- 'juk.desktop': 'org.kde.juk.desktop',
- 'kajongg.desktop': 'org.kde.kajongg.desktop',
- 'kalgebra.desktop': 'org.kde.kalgebra.desktop',
- 'kalzium.desktop': 'org.kde.kalzium.desktop',
- 'kamoso.desktop': 'org.kde.kamoso.desktop',
- 'kanagram.desktop': 'org.kde.kanagram.desktop',
- 'kapman.desktop': 'org.kde.kapman.desktop',
- 'kapptemplate.desktop': 'org.kde.kapptemplate.desktop',
- 'kbruch.desktop': 'org.kde.kbruch.desktop',
- 'kdevelop.desktop': 'org.kde.kdevelop.desktop',
- 'kfind.desktop': 'org.kde.kfind.desktop',
- 'kgeography.desktop': 'org.kde.kgeography.desktop',
- 'kgpg.desktop': 'org.kde.kgpg.desktop',
- 'khangman.desktop': 'org.kde.khangman.desktop',
- 'kig.desktop': 'org.kde.kig.desktop',
- 'kiriki.desktop': 'org.kde.kiriki.desktop',
- 'kiten.desktop': 'org.kde.kiten.desktop',
- 'klettres.desktop': 'org.kde.klettres.desktop',
- 'klipper.desktop': 'org.kde.klipper.desktop',
- 'KMail2.desktop': 'org.kde.kmail.desktop',
- 'kmplot.desktop': 'org.kde.kmplot.desktop',
- 'kollision.desktop': 'org.kde.kollision.desktop',
- 'kolourpaint.desktop': 'org.kde.kolourpaint.desktop',
- 'konsole.desktop': 'org.kde.konsole.desktop',
- 'Kontact.desktop': 'org.kde.kontact.desktop',
- 'korganizer.desktop': 'org.kde.korganizer.desktop',
- 'krita.desktop': 'org.kde.krita.desktop',
- 'kshisen.desktop': 'org.kde.kshisen.desktop',
- 'kstars.desktop': 'org.kde.kstars.desktop',
- 'ksudoku.desktop': 'org.kde.ksudoku.desktop',
- 'ktouch.desktop': 'org.kde.ktouch.desktop',
- 'ktp-log-viewer.desktop': 'org.kde.ktplogviewer.desktop',
- 'kturtle.desktop': 'org.kde.kturtle.desktop',
- 'kwordquiz.desktop': 'org.kde.kwordquiz.desktop',
- 'marble.desktop': 'org.kde.marble.desktop',
- 'okteta.desktop': 'org.kde.okteta.desktop',
- 'parley.desktop': 'org.kde.parley.desktop',
- 'partitionmanager.desktop': 'org.kde.PartitionManager.desktop',
- 'picmi.desktop': 'org.kde.picmi.desktop',
- 'rocs.desktop': 'org.kde.rocs.desktop',
- 'showfoto.desktop': 'org.kde.showfoto.desktop',
- 'skrooge.desktop': 'org.kde.skrooge.desktop',
- 'step.desktop': 'org.kde.step.desktop',
- 'yakuake.desktop': 'org.kde.yakuake.desktop',
- 'colorhug-ccmx.desktop': 'com.hughski.ColorHug.CcmxLoader.desktop',
- 'colorhug-flash.desktop': 'com.hughski.ColorHug.FlashLoader.desktop',
- 'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
- 'feedreader.desktop': 'org.gnome.FeedReader.desktop',
- 'qtcreator.desktop': 'org.qt-project.qtcreator.desktop',
+ "baobab.desktop": "org.gnome.baobab.desktop",
+ "bijiben.desktop": "org.gnome.bijiben.desktop",
+ "cheese.desktop": "org.gnome.Cheese.desktop",
+ "devhelp.desktop": "org.gnome.Devhelp.desktop",
+ "epiphany.desktop": "org.gnome.Epiphany.desktop",
+ "file-roller.desktop": "org.gnome.FileRoller.desktop",
+ "font-manager.desktop": "org.gnome.FontManager.desktop",
+ "gcalctool.desktop": "gnome-calculator.desktop",
+ "gcm-viewer.desktop": "org.gnome.ColorProfileViewer.desktop",
+ "geary.desktop": "org.gnome.Geary.desktop",
+ "gedit.desktop": "org.gnome.gedit.desktop",
+ "glchess.desktop": "gnome-chess.desktop",
+ "glines.desktop": "five-or-more.desktop",
+ "gnect.desktop": "four-in-a-row.desktop",
+ "gnibbles.desktop": "gnome-nibbles.desktop",
+ "gnobots2.desktop": "gnome-robots.desktop",
+ "gnome-2048.desktop": "org.gnome.gnome-2048.desktop",
+ "gnome-boxes.desktop": "org.gnome.Boxes.desktop",
+ "gnome-calculator.desktop": "org.gnome.Calculator.desktop",
+ "gnome-clocks.desktop": "org.gnome.clocks.desktop",
+ "gnome-contacts.desktop": "org.gnome.Contacts.desktop",
+ "gnome-dictionary.desktop": "org.gnome.Dictionary.desktop",
+ "gnome-disks.desktop": "org.gnome.DiskUtility.desktop",
+ "gnome-documents.desktop": "org.gnome.Documents.desktop",
+ "gnome-font-viewer.desktop": "org.gnome.font-viewer.desktop",
+ "gnome-maps.desktop": "org.gnome.Maps.desktop",
+ "gnome-nibbles.desktop": "org.gnome.Nibbles.desktop",
+ "gnome-photos.desktop": "org.gnome.Photos.desktop",
+ "gnome-power-statistics.desktop": "org.gnome.PowerStats.desktop",
+ "gnome-screenshot.desktop": "org.gnome.Screenshot.desktop",
+ "gnome-software.desktop": "org.gnome.Software.desktop",
+ "gnome-sound-recorder.desktop": "org.gnome.SoundRecorder.desktop",
+ "gnome-terminal.desktop": "org.gnome.Terminal.desktop",
+ "gnome-weather.desktop": "org.gnome.Weather.Application.desktop",
+ "gnomine.desktop": "gnome-mines.desktop",
+ "gnotravex.desktop": "gnome-tetravex.desktop",
+ "gnotski.desktop": "gnome-klotski.desktop",
+ "gtali.desktop": "tali.desktop",
+ "hitori.desktop": "org.gnome.Hitori.desktop",
+ "latexila.desktop": "org.gnome.latexila.desktop",
+ "lollypop.desktop": "org.gnome.Lollypop.desktop",
+ "nautilus.desktop": "org.gnome.Nautilus.desktop",
+ "polari.desktop": "org.gnome.Polari.desktop",
+ "sound-juicer.desktop": "org.gnome.SoundJuicer.desktop",
+ "totem.desktop": "org.gnome.Totem.desktop",
+ "akregator.desktop": "org.kde.akregator.desktop",
+ "apper.desktop": "org.kde.apper.desktop",
+ "ark.desktop": "org.kde.ark.desktop",
+ "blinken.desktop": "org.kde.blinken.desktop",
+ "cantor.desktop": "org.kde.cantor.desktop",
+ "digikam.desktop": "org.kde.digikam.desktop",
+ "dolphin.desktop": "org.kde.dolphin.desktop",
+ "dragonplayer.desktop": "org.kde.dragonplayer.desktop",
+ "filelight.desktop": "org.kde.filelight.desktop",
+ "gwenview.desktop": "org.kde.gwenview.desktop",
+ "juk.desktop": "org.kde.juk.desktop",
+ "kajongg.desktop": "org.kde.kajongg.desktop",
+ "kalgebra.desktop": "org.kde.kalgebra.desktop",
+ "kalzium.desktop": "org.kde.kalzium.desktop",
+ "kamoso.desktop": "org.kde.kamoso.desktop",
+ "kanagram.desktop": "org.kde.kanagram.desktop",
+ "kapman.desktop": "org.kde.kapman.desktop",
+ "kapptemplate.desktop": "org.kde.kapptemplate.desktop",
+ "kbruch.desktop": "org.kde.kbruch.desktop",
+ "kdevelop.desktop": "org.kde.kdevelop.desktop",
+ "kfind.desktop": "org.kde.kfind.desktop",
+ "kgeography.desktop": "org.kde.kgeography.desktop",
+ "kgpg.desktop": "org.kde.kgpg.desktop",
+ "khangman.desktop": "org.kde.khangman.desktop",
+ "kig.desktop": "org.kde.kig.desktop",
+ "kiriki.desktop": "org.kde.kiriki.desktop",
+ "kiten.desktop": "org.kde.kiten.desktop",
+ "klettres.desktop": "org.kde.klettres.desktop",
+ "klipper.desktop": "org.kde.klipper.desktop",
+ "KMail2.desktop": "org.kde.kmail.desktop",
+ "kmplot.desktop": "org.kde.kmplot.desktop",
+ "kollision.desktop": "org.kde.kollision.desktop",
+ "kolourpaint.desktop": "org.kde.kolourpaint.desktop",
+ "konsole.desktop": "org.kde.konsole.desktop",
+ "Kontact.desktop": "org.kde.kontact.desktop",
+ "korganizer.desktop": "org.kde.korganizer.desktop",
+ "krita.desktop": "org.kde.krita.desktop",
+ "kshisen.desktop": "org.kde.kshisen.desktop",
+ "kstars.desktop": "org.kde.kstars.desktop",
+ "ksudoku.desktop": "org.kde.ksudoku.desktop",
+ "ktouch.desktop": "org.kde.ktouch.desktop",
+ "ktp-log-viewer.desktop": "org.kde.ktplogviewer.desktop",
+ "kturtle.desktop": "org.kde.kturtle.desktop",
+ "kwordquiz.desktop": "org.kde.kwordquiz.desktop",
+ "marble.desktop": "org.kde.marble.desktop",
+ "okteta.desktop": "org.kde.okteta.desktop",
+ "parley.desktop": "org.kde.parley.desktop",
+ "partitionmanager.desktop": "org.kde.PartitionManager.desktop",
+ "picmi.desktop": "org.kde.picmi.desktop",
+ "rocs.desktop": "org.kde.rocs.desktop",
+ "showfoto.desktop": "org.kde.showfoto.desktop",
+ "skrooge.desktop": "org.kde.skrooge.desktop",
+ "step.desktop": "org.kde.step.desktop",
+ "yakuake.desktop": "org.kde.yakuake.desktop",
+ "colorhug-ccmx.desktop": "com.hughski.ColorHug.CcmxLoader.desktop",
+ "colorhug-flash.desktop": "com.hughski.ColorHug.FlashLoader.desktop",
+ "dconf-editor.desktop": "ca.desrt.dconf-editor.desktop",
+ "feedreader.desktop": "org.gnome.FeedReader.desktop",
+ "qtcreator.desktop": "org.qt-project.qtcreator.desktop",
}
for app_id in mapping:
if not app_id in components:
@@ -137,12 +141,16 @@ def upgrade():
continue
if components[app_id].component_id_parent:
continue
- print('adding legacy parent for {} -> {}'.format(components[app_id].app_id,
- components[app_id_new].app_id))
+ print(
+ "adding legacy parent for {} -> {}".format(
+ components[app_id].app_id, components[app_id_new].app_id
+ )
+ )
components[app_id_new].adopt(components[app_id])
# done
db.session.commit()
+
def downgrade():
pass
diff --git a/app_data/migrations/versions/f32bd8265c3b_.py b/app_data/migrations/versions/f32bd8265c3b_.py
index 3e8725e..1236d5d 100644
--- a/app_data/migrations/versions/f32bd8265c3b_.py
+++ b/app_data/migrations/versions/f32bd8265c3b_.py
@@ -7,18 +7,27 @@ Create Date: 2019-07-04 16:35:39.673744
"""
# revision identifiers, used by Alembic.
-revision = 'f32bd8265c3b'
-down_revision = 'a22c286d8094'
+revision = "f32bd8265c3b"
+down_revision = "a22c286d8094"
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
+
def upgrade():
- op.add_column('components', sa.Column('component_id_parent', sa.Integer(), nullable=True))
- op.create_foreign_key('components_ibfk_4', 'components', 'components', ['component_id_parent'],
['component_id'])
+ op.add_column(
+ "components", sa.Column("component_id_parent", sa.Integer(), nullable=True)
+ )
+ op.create_foreign_key(
+ "components_ibfk_4",
+ "components",
+ "components",
+ ["component_id_parent"],
+ ["component_id"],
+ )
def downgrade():
- op.drop_constraint('components_ibfk_4', 'components', type_='foreignkey')
- op.drop_column('components', 'component_id_parent')
+ op.drop_constraint("components_ibfk_4", "components", type_="foreignkey")
+ op.drop_column("components", "component_id_parent")
diff --git a/app_data/odrs/__init__.py b/app_data/odrs/__init__.py
index 05009ee..06f514a 100644
--- a/app_data/odrs/__init__.py
+++ b/app_data/odrs/__init__.py
@@ -21,12 +21,11 @@ from .dbutils import drop_db, init_db
app = Flask(__name__)
app.config.from_object(__name__)
-if 'ODRS_CONFIG' in os.environ:
- app.config.from_envvar('ODRS_CONFIG')
-if 'ODRS_REVIEWS_SECRET' in os.environ:
- app.secret_key = os.environ['ODRS_REVIEWS_SECRET']
-for key in ['SQLALCHEMY_DATABASE_URI',
- 'SQLALCHEMY_TRACK_MODIFICATIONS']:
+if "ODRS_CONFIG" in os.environ:
+ app.config.from_envvar("ODRS_CONFIG")
+if "ODRS_REVIEWS_SECRET" in os.environ:
+ app.secret_key = os.environ["ODRS_REVIEWS_SECRET"]
+for key in ["SQLALCHEMY_DATABASE_URI", "SQLALCHEMY_TRACK_MODIFICATIONS"]:
if key in os.environ:
app.config[key] = os.environ[key]
@@ -36,37 +35,48 @@ migrate = Migrate(app, db)
csrf = CSRFProtect(app)
-@app.cli.command('initdb')
+
+@app.cli.command("initdb")
def initdb_command():
init_db(db)
-@app.cli.command('dropdb')
+
+@app.cli.command("dropdb")
def dropdb_command():
drop_db(db)
+
lm = LoginManager(app)
-lm.login_view = 'odrs_login'
+lm.login_view = "odrs_login"
+
@app.teardown_appcontext
def shutdown_session(unused_exception=None):
db.session.remove()
+
@lm.user_loader
def load_user(user_id):
from .models import Moderator
- g.user = db.session.query(Moderator).filter(Moderator.moderator_id == user_id).first()
+
+ g.user = (
+ db.session.query(Moderator).filter(Moderator.moderator_id == user_id).first()
+ )
return g.user
+
@app.errorhandler(404)
def error_page_not_found(msg=None):
- """ Error handler: File not found """
+ """Error handler: File not found"""
flash(msg)
- return render_template('error.html'), 404
+ return render_template("error.html"), 404
+
@app.errorhandler(CSRFError)
def error_csrf(e):
- flash(str(e), 'danger')
- return redirect(url_for('.odrs_index'))
+ flash(str(e), "danger")
+ return redirect(url_for(".odrs_index"))
+
from odrs import views
from odrs import views_api
diff --git a/app_data/odrs/dbutils.py b/app_data/odrs/dbutils.py
index 6e3934e..d608d6d 100644
--- a/app_data/odrs/dbutils.py
+++ b/app_data/odrs/dbutils.py
@@ -7,6 +7,7 @@
#
# SPDX-License-Identifier: GPL-3.0+
+
def init_db(db):
# ensure all tables exist
@@ -14,18 +15,28 @@ def init_db(db):
# ensure admin user exists
from .models import Moderator, User
- user = db.session.query(User).filter(User.user_hash ==
'deadbeef348c0f88529f3bfd937ec1a5d90aefc7').first()
+
+ user = (
+ db.session.query(User)
+ .filter(User.user_hash == "deadbeef348c0f88529f3bfd937ec1a5d90aefc7")
+ .first()
+ )
if not user:
- user = User('deadbeef348c0f88529f3bfd937ec1a5d90aefc7')
+ user = User("deadbeef348c0f88529f3bfd937ec1a5d90aefc7")
db.session.add(user)
db.session.commit()
- if not db.session.query(Moderator).filter(Moderator.username == 'admin test com').first():
- mod = Moderator(username='admin test com')
- mod.password = 'Pa$$w0rd'
+ if (
+ not db.session.query(Moderator)
+ .filter(Moderator.username == "admin test com")
+ .first()
+ ):
+ mod = Moderator(username="admin test com")
+ mod.password = "Pa$$w0rd"
mod.is_admin = True
mod.user_id = user.user_id
db.session.add(mod)
db.session.commit()
+
def drop_db(db):
db.metadata.drop_all(bind=db.engine)
diff --git a/app_data/odrs/models.py b/app_data/odrs/models.py
index 10662bf..edbfb50 100644
--- a/app_data/odrs/models.py
+++ b/app_data/odrs/models.py
@@ -12,27 +12,41 @@ import re
from werkzeug.security import generate_password_hash, check_password_hash
-from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Index, ForeignKey
+from sqlalchemy import (
+ Column,
+ Integer,
+ String,
+ Text,
+ DateTime,
+ Boolean,
+ Index,
+ ForeignKey,
+)
from sqlalchemy.orm import relationship
from odrs import db
from .util import _password_hash, _get_user_key, _addr_hash
+
def _vote_exists(review_id, user_id):
- """ Checks to see if a vote exists for the review+user """
- return db.session.query(Vote).\
- filter(Vote.review_id == review_id).\
- filter(Vote.user_id == user_id).\
- first()
+ """Checks to see if a vote exists for the review+user"""
+ return (
+ db.session.query(Vote)
+ .filter(Vote.review_id == review_id)
+ .filter(Vote.user_id == user_id)
+ .first()
+ )
+
class Analytic(db.Model):
# sqlalchemy metadata
- __tablename__ = 'analytics'
- __table_args__ = (Index('datestr', 'datestr', 'app_id', unique=True),
- {'mysql_character_set': 'utf8mb4'}
- )
+ __tablename__ = "analytics"
+ __table_args__ = (
+ Index("datestr", "datestr", "app_id", unique=True),
+ {"mysql_character_set": "utf8mb4"},
+ )
datestr = Column(Integer, default=0, primary_key=True)
app_id = Column(String(128), primary_key=True)
@@ -42,13 +56,14 @@ class Analytic(db.Model):
self.datestr = None
def __repr__(self):
- return 'Analytic object %s' % self.analytic_id
+ return "Analytic object %s" % self.analytic_id
+
class Taboo(db.Model):
# sqlalchemy metadata
- __tablename__ = 'taboos'
- __table_args__ = {'mysql_character_set': 'utf8mb4'}
+ __tablename__ = "taboos"
+ __table_args__ = {"mysql_character_set": "utf8mb4"}
taboo_id = Column(Integer, primary_key=True, nullable=False, unique=True)
locale = Column(String(8), nullable=False, index=True)
@@ -63,38 +78,39 @@ class Taboo(db.Model):
self.severity = severity
def asdict(self):
- item = {'value': self.value}
+ item = {"value": self.value}
if self.severity:
- item['severity'] = self.severity
+ item["severity"] = self.severity
if self.description:
- item['description'] = self.description
+ item["description"] = self.description
return item
@property
def color(self):
if self.severity == 3:
- return 'danger'
+ return "danger"
if self.severity == 2:
- return 'warning'
- return 'info'
+ return "warning"
+ return "info"
def __repr__(self):
- return 'Taboo object %s' % self.taboo_id
+ return "Taboo object %s" % self.taboo_id
+
class Vote(db.Model):
# sqlalchemy metadata
- __tablename__ = 'votes'
- __table_args__ = {'mysql_character_set': 'utf8mb4'}
+ __tablename__ = "votes"
+ __table_args__ = {"mysql_character_set": "utf8mb4"}
vote_id = Column(Integer, primary_key=True, nullable=False, unique=True)
date_created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
- review_id = Column(Integer, ForeignKey('reviews.review_id'), nullable=True)
- user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
+ review_id = Column(Integer, ForeignKey("reviews.review_id"), nullable=True)
+ user_id = Column(Integer, ForeignKey("users.user_id"), nullable=True)
val = Column(Integer, default=0)
- user = relationship('User')
- review = relationship('Review')
+ user = relationship("User")
+ review = relationship("Review")
def __init__(self, user_id, val, review_id=0):
self.review_id = review_id
@@ -102,16 +118,18 @@ class Vote(db.Model):
self.val = val
def __repr__(self):
- return 'Vote object %s' % self.vote_id
+ return "Vote object %s" % self.vote_id
+
class User(db.Model):
# sqlalchemy metadata
- __tablename__ = 'users'
- __table_args__ = {'mysql_character_set': 'utf8mb4'}
- __table_args__ = (Index('users_hash_idx', 'user_hash'),
- {'mysql_character_set': 'utf8mb4'}
- )
+ __tablename__ = "users"
+ __table_args__ = {"mysql_character_set": "utf8mb4"}
+ __table_args__ = (
+ Index("users_hash_idx", "user_hash"),
+ {"mysql_character_set": "utf8mb4"},
+ )
user_id = Column(Integer, primary_key=True, nullable=False, unique=True)
date_created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
@@ -119,9 +137,7 @@ class User(db.Model):
karma = Column(Integer, default=0)
is_banned = Column(Boolean, default=False)
- reviews = relationship('Review',
- back_populates='user',
- cascade='all,delete-orphan')
+ reviews = relationship("Review", back_populates="user", cascade="all,delete-orphan")
def __init__(self, user_hash=None):
self.user_hash = user_hash
@@ -129,31 +145,35 @@ class User(db.Model):
self.is_banned = False
def __repr__(self):
- return 'User object %s' % self.user_id
+ return "User object %s" % self.user_id
+
def _tokenize(val):
return [token.lower() for token in re.findall(r"[\w']+", val)]
+
class Component(db.Model):
# sqlalchemy metadata
- __tablename__ = 'components'
- __table_args__ = {'mysql_character_set': 'utf8mb4'}
+ __tablename__ = "components"
+ __table_args__ = {"mysql_character_set": "utf8mb4"}
component_id = Column(Integer, primary_key=True, nullable=False, unique=True)
- component_id_parent = Column(Integer, ForeignKey('components.component_id'))
+ component_id_parent = Column(Integer, ForeignKey("components.component_id"))
app_id = Column(Text)
fetch_cnt = Column(Integer, default=0)
review_cnt = Column(Integer, default=1)
- reviews = relationship('Review',
- back_populates='component',
- cascade='all,delete-orphan')
- parent = relationship('Component',
- uselist=False,
- remote_side='Component.component_id',
- backref='children',
- lazy='joined')
+ reviews = relationship(
+ "Review", back_populates="component", cascade="all,delete-orphan"
+ )
+ parent = relationship(
+ "Component",
+ uselist=False,
+ remote_side="Component.component_id",
+ backref="children",
+ lazy="joined",
+ )
def __init__(self, app_id):
self.app_id = app_id
@@ -185,23 +205,26 @@ class Component(db.Model):
return app_ids
def __repr__(self):
- return 'Component object %s' % self.component_id
+ return "Component object %s" % self.component_id
+
class Review(db.Model):
# sqlalchemy metadata
- __tablename__ = 'reviews'
- __table_args__ = {'mysql_character_set': 'utf8mb4'}
+ __tablename__ = "reviews"
+ __table_args__ = {"mysql_character_set": "utf8mb4"}
review_id = Column(Integer, primary_key=True, nullable=False, unique=True)
date_created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
date_deleted = Column(DateTime)
- component_id = Column(Integer, ForeignKey('components.component_id'), nullable=False)
+ component_id = Column(
+ Integer, ForeignKey("components.component_id"), nullable=False
+ )
locale = Column(Text)
summary = Column(Text)
description = Column(Text)
- user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
- user_addr_hash = Column('user_addr', Text)
+ user_id = Column(Integer, ForeignKey("users.user_id"), nullable=True)
+ user_addr_hash = Column("user_addr", Text)
user_display = Column(Text)
version = Column(Text)
distro = Column(Text)
@@ -210,13 +233,13 @@ class Review(db.Model):
karma_down = Column(Integer, default=0)
reported = Column(Integer, default=0)
- user = relationship('User', back_populates='reviews')
- component = relationship('Component', # the one used for submit()
- back_populates='reviews',
- lazy='joined')
- votes = relationship('Vote',
- back_populates='review',
- cascade='all,delete-orphan')
+ user = relationship("User", back_populates="reviews")
+ component = relationship(
+ "Component", # the one used for submit()
+ back_populates="reviews",
+ lazy="joined",
+ )
+ votes = relationship("Vote", back_populates="review", cascade="all,delete-orphan")
def __init__(self):
self.locale = None
@@ -266,7 +289,7 @@ class Review(db.Model):
@property
def user_addr(self):
- raise AttributeError('user_addr is not a readable attribute')
+ raise AttributeError("user_addr is not a readable attribute")
@user_addr.setter
def user_addr(self, user_addr):
@@ -274,49 +297,53 @@ class Review(db.Model):
def asdict(self, user_hash=None):
item = {
- 'app_id': self.component.app_id,
- 'date_created': self.date_created.timestamp(),
- 'description': self.description,
- 'distro': self.distro,
- 'karma_down': self.karma_down,
- 'karma_up': self.karma_up,
- 'locale': self.locale,
- 'rating': self.rating,
- 'reported': self.reported,
- 'review_id': self.review_id,
- 'summary': self.summary,
- 'user_display': self.user_display,
- 'version': self.version,
+ "app_id": self.component.app_id,
+ "date_created": self.date_created.timestamp(),
+ "description": self.description,
+ "distro": self.distro,
+ "karma_down": self.karma_down,
+ "karma_up": self.karma_up,
+ "locale": self.locale,
+ "rating": self.rating,
+ "reported": self.reported,
+ "review_id": self.review_id,
+ "summary": self.summary,
+ "user_display": self.user_display,
+ "version": self.version,
}
if self.user:
- item['user_hash'] = self.user.user_hash
+ item["user_hash"] = self.user.user_hash
if user_hash:
- item['user_skey'] = _get_user_key(user_hash, self.component.app_id)
+ item["user_skey"] = _get_user_key(user_hash, self.component.app_id)
return item
def __repr__(self):
- return 'Review object %s' % self.review_id
+ return "Review object %s" % self.review_id
+
class Event(db.Model):
# sqlalchemy metadata
- __tablename__ = 'eventlog'
- __table_args__ = (Index('message_idx', 'message', mysql_length=8),
- Index('date_created_idx', 'date_created'),
- {'mysql_character_set': 'utf8mb4'}
- )
+ __tablename__ = "eventlog"
+ __table_args__ = (
+ Index("message_idx", "message", mysql_length=8),
+ Index("date_created_idx", "date_created"),
+ {"mysql_character_set": "utf8mb4"},
+ )
eventlog_id = Column(Integer, primary_key=True, nullable=False, unique=True)
date_created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
user_addr = Column(Text)
- user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
+ user_id = Column(Integer, ForeignKey("users.user_id"), nullable=True)
message = Column(Text)
app_id = Column(Text)
important = Column(Boolean, default=False)
- user = relationship('User')
+ user = relationship("User")
- def __init__(self, user_addr, user_id=None, app_id=None, message=None, important=False):
+ def __init__(
+ self, user_addr, user_id=None, app_id=None, message=None, important=False
+ ):
self.user_addr = user_addr
self.user_id = user_id
self.message = message
@@ -324,24 +351,25 @@ class Event(db.Model):
self.important = important
def __repr__(self):
- return 'Event object %s' % self.eventlog_id
+ return "Event object %s" % self.eventlog_id
+
class Moderator(db.Model):
# sqlalchemy metadata
- __tablename__ = 'moderators'
- __table_args__ = {'mysql_character_set': 'utf8mb4'}
+ __tablename__ = "moderators"
+ __table_args__ = {"mysql_character_set": "utf8mb4"}
moderator_id = Column(Integer, primary_key=True, nullable=False, unique=True)
username = Column(Text)
- password_hash = Column('password', Text)
+ password_hash = Column("password", Text)
display_name = Column(Text)
is_enabled = Column(Boolean, default=False)
is_admin = Column(Boolean, default=False)
- user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
+ user_id = Column(Integer, ForeignKey("users.user_id"), nullable=True)
locales = Column(Text)
- user = relationship('User')
+ user = relationship("User")
def __init__(self, username=None, password=None, display_name=None):
self.username = username
@@ -354,7 +382,7 @@ class Moderator(db.Model):
@property
def password(self):
- raise AttributeError('password is not a readable attribute')
+ raise AttributeError("password is not a readable attribute")
@password.setter
def password(self, password):
@@ -387,4 +415,4 @@ class Moderator(db.Model):
return str(self.moderator_id)
def __repr__(self):
- return 'Moderator object %s' % self.moderator_id
+ return "Moderator object %s" % self.moderator_id
diff --git a/app_data/odrs/tests/odrs_test.py b/app_data/odrs/tests/odrs_test.py
index 0cafe39..3b96b5b 100644
--- a/app_data/odrs/tests/odrs_test.py
+++ b/app_data/odrs/tests/odrs_test.py
@@ -15,35 +15,40 @@ import unittest
import tempfile
# allows us to run this from the project root
-sys.path.append(os.path.realpath('.'))
+sys.path.append(os.path.realpath("."))
from odrs.util import _get_user_key
-class OdrsTest(unittest.TestCase):
+class OdrsTest(unittest.TestCase):
def setUp(self):
# create new database
self.db_fd, self.db_filename = tempfile.mkstemp()
- self.db_uri = 'sqlite:///' + self.db_filename
- self.user_hash = 'deadbeef348c0f88529f3bfd937ec1a5d90aefc7'
+ self.db_uri = "sqlite:///" + self.db_filename
+ self.user_hash = "deadbeef348c0f88529f3bfd937ec1a5d90aefc7"
# write out custom settings file
self.cfg_fd, self.cfg_filename = tempfile.mkstemp()
- with open(self.cfg_filename, 'w') as cfgfile:
- cfgfile.write('\n'.join([
- "SQLALCHEMY_DATABASE_URI = '%s'" % self.db_uri,
- "SQLALCHEMY_TRACK_MODIFICATIONS = False",
- "SECRET_KEY = 'not-secret4'",
- "ODRS_REVIEWS_SECRET = '1'",
- "WTF_CSRF_CHECK_DEFAULT = False",
- "DEBUG = True",
- ]))
+ with open(self.cfg_filename, "w") as cfgfile:
+ cfgfile.write(
+ "\n".join(
+ [
+ "SQLALCHEMY_DATABASE_URI = '%s'" % self.db_uri,
+ "SQLALCHEMY_TRACK_MODIFICATIONS = False",
+ "SECRET_KEY = 'not-secret4'",
+ "ODRS_REVIEWS_SECRET = '1'",
+ "WTF_CSRF_CHECK_DEFAULT = False",
+ "DEBUG = True",
+ ]
+ )
+ )
# create instance
import odrs
from odrs import db
from odrs.dbutils import init_db
+
self.app = odrs.app.test_client()
odrs.app.config.from_pyfile(self.cfg_filename)
with odrs.app.app_context():
@@ -51,13 +56,17 @@ class OdrsTest(unittest.TestCase):
# assign user_hash to this account
self.login()
- rv = self.app.post('/admin/moderator/1/modify_by_admin', data=dict(
- is_enabled=True,
- is_admin=True,
- locales='en',
- user_hash=self.user_hash,
- ), follow_redirects=True)
- assert b'Updated profile' in rv.data, rv.data
+ rv = self.app.post(
+ "/admin/moderator/1/modify_by_admin",
+ data=dict(
+ is_enabled=True,
+ is_admin=True,
+ locales="en",
+ user_hash=self.user_hash,
+ ),
+ follow_redirects=True,
+ )
+ assert b"Updated profile" in rv.data, rv.data
self.logout()
def tearDown(self):
@@ -66,32 +75,33 @@ class OdrsTest(unittest.TestCase):
os.close(self.cfg_fd)
os.unlink(self.cfg_filename)
- def _login(self, username, password='Pa$$w0rd'):
- return self.app.post('/login', data=dict(
- username=username,
- password=password
- ), follow_redirects=True)
+ def _login(self, username, password="Pa$$w0rd"):
+ return self.app.post(
+ "/login",
+ data=dict(username=username, password=password),
+ follow_redirects=True,
+ )
def _logout(self):
- return self.app.get('/logout', follow_redirects=True)
+ return self.app.get("/logout", follow_redirects=True)
- def login(self, username='admin test com', password='Pa$$w0rd'):
+ def login(self, username="admin test com", password="Pa$$w0rd"):
rv = self._login(username, password)
- assert b'Logged in' in rv.data, rv.data
- assert b'/admin/show/reported' in rv.data, rv.data
- assert b'Incorrect username' not in rv.data, rv.data
+ assert b"Logged in" in rv.data, rv.data
+ assert b"/admin/show/reported" in rv.data, rv.data
+ assert b"Incorrect username" not in rv.data, rv.data
def logout(self):
rv = self._logout()
- assert b'Logged out' in rv.data, rv.data
- assert b'/admin/show/reported' not in rv.data, rv.data
+ assert b"Logged out" in rv.data, rv.data
+ assert b"/admin/show/reported" not in rv.data, rv.data
def test_admin_show_review_for_app(self):
self.review_submit()
self.login()
- rv = self.app.get('/admin/show/app/inkscape.desktop')
- assert b'n essential part of my daily' in rv.data, rv.data
+ rv = self.app.get("/admin/show/app/inkscape.desktop")
+ assert b"n essential part of my daily" in rv.data, rv.data
def test_admin_graphs(self):
@@ -101,18 +111,18 @@ class OdrsTest(unittest.TestCase):
self.review_fetch()
self.login()
- rv = self.app.get('/admin/graph_month')
- assert b'Chart.js' in rv.data, rv.data
- assert b'0, 1' in rv.data, rv.data
+ rv = self.app.get("/admin/graph_month")
+ assert b"Chart.js" in rv.data, rv.data
+ assert b"0, 1" in rv.data, rv.data
- rv = self.app.get('/admin/graph_year')
- assert b'Chart.js' in rv.data, rv.data
- assert b'0, 1' in rv.data, rv.data
+ rv = self.app.get("/admin/graph_year")
+ assert b"Chart.js" in rv.data, rv.data
+ assert b"0, 1" in rv.data, rv.data
- rv = self.app.get('/admin/stats')
- assert b'Chart.js' in rv.data, rv.data
- assert b'Active reviews</td>\n <td>1</td>' in rv.data, rv.data
- assert b'Haters Gonna Hate' in rv.data, rv.data
+ rv = self.app.get("/admin/stats")
+ assert b"Chart.js" in rv.data, rv.data
+ assert b"Active reviews</td>\n <td>1</td>" in rv.data, rv.data
+ assert b"Haters Gonna Hate" in rv.data, rv.data
def test_admin_unreport(self):
@@ -120,186 +130,222 @@ class OdrsTest(unittest.TestCase):
self.review_report()
self.login()
- rv = self.app.get('/admin/unreport/1', follow_redirects=True)
- assert b'Review unreported' in rv.data, rv.data
+ rv = self.app.get("/admin/unreport/1", follow_redirects=True)
+ assert b"Review unreported" in rv.data, rv.data
def test_admin_review(self):
- rv = self._review_submit(locale='in_IN')
+ rv = self._review_submit(locale="in_IN")
assert b'"success": true' in rv.data, rv.data
self.login()
- rv = self.app.get('/admin/review/1')
- assert b'Inkscape has been a essential part of my workflow for many years' in rv.data, rv.data
- assert b'Somebody Important' in rv.data, rv.data
- assert b'Fedora' in rv.data, rv.data
- rv = self.app.post('/admin/modify/1', data=dict(
- distro='Ubuntu',
- ), follow_redirects=True)
- assert b'Inkscape has been a essential part of my workflow for many years' in rv.data, rv.data
- assert b'Ubuntu' in rv.data, rv.data
-
- rv = self.app.get('/admin/englishify/1', follow_redirects=True)
- assert b'en_IN' in rv.data, rv.data
-
- rv = self.app.get('/admin/anonify/1', follow_redirects=True)
- assert b'Somebody Important' not in rv.data, rv.data
-
- rv = self.app.get('/admin/vote/1/down', follow_redirects=True)
- assert b'Recorded vote' in rv.data, rv.data
+ rv = self.app.get("/admin/review/1")
+ assert (
+ b"Inkscape has been a essential part of my workflow for many years"
+ in rv.data
+ ), rv.data
+ assert b"Somebody Important" in rv.data, rv.data
+ assert b"Fedora" in rv.data, rv.data
+ rv = self.app.post(
+ "/admin/modify/1",
+ data=dict(
+ distro="Ubuntu",
+ ),
+ follow_redirects=True,
+ )
+ assert (
+ b"Inkscape has been a essential part of my workflow for many years"
+ in rv.data
+ ), rv.data
+ assert b"Ubuntu" in rv.data, rv.data
+
+ rv = self.app.get("/admin/englishify/1", follow_redirects=True)
+ assert b"en_IN" in rv.data, rv.data
+
+ rv = self.app.get("/admin/anonify/1", follow_redirects=True)
+ assert b"Somebody Important" not in rv.data, rv.data
+
+ rv = self.app.get("/admin/vote/1/down", follow_redirects=True)
+ assert b"Recorded vote" in rv.data, rv.data
# delete
- rv = self.app.get('/admin/delete/1', follow_redirects=True)
- assert b'Confirm Removal?' in rv.data, rv.data
- rv = self.app.get('/admin/delete/1/force', follow_redirects=True)
- assert b'Deleted review' in rv.data, rv.data
- rv = self.app.get('/admin/review/1', follow_redirects=True)
- assert b'No review with that ID' in rv.data, rv.data
-
- def _admin_moderator_add(self, username='dave dave com', password='foobarbaz123.'):
-
- return self.app.post('/admin/moderator/add', data=dict(
- password_new=password,
- username_new=username,
- display_name='Dave',
- ), follow_redirects=True)
+ rv = self.app.get("/admin/delete/1", follow_redirects=True)
+ assert b"Confirm Removal?" in rv.data, rv.data
+ rv = self.app.get("/admin/delete/1/force", follow_redirects=True)
+ assert b"Deleted review" in rv.data, rv.data
+ rv = self.app.get("/admin/review/1", follow_redirects=True)
+ assert b"No review with that ID" in rv.data, rv.data
+
+ def _admin_moderator_add(self, username="dave dave com", password="foobarbaz123."):
+
+ return self.app.post(
+ "/admin/moderator/add",
+ data=dict(
+ password_new=password,
+ username_new=username,
+ display_name="Dave",
+ ),
+ follow_redirects=True,
+ )
def test_admin_add_moderator(self):
self.login()
# bad values
- rv = self._admin_moderator_add(username='1')
- assert b'Username invalid' in rv.data, rv.data
- rv = self._admin_moderator_add(password='foo')
- assert b'The password is too short' in rv.data, rv.data
- rv = self._admin_moderator_add(password='foobarbaz')
- assert b'requires at least one non-alphanumeric' in rv.data, rv.data
- rv = self._admin_moderator_add(username='foo')
- assert b'Invalid email address' in rv.data, rv.data
+ rv = self._admin_moderator_add(username="1")
+ assert b"Username invalid" in rv.data, rv.data
+ rv = self._admin_moderator_add(password="foo")
+ assert b"The password is too short" in rv.data, rv.data
+ rv = self._admin_moderator_add(password="foobarbaz")
+ assert b"requires at least one non-alphanumeric" in rv.data, rv.data
+ rv = self._admin_moderator_add(username="foo")
+ assert b"Invalid email address" in rv.data, rv.data
# good values
rv = self._admin_moderator_add()
- assert b'Added user' in rv.data, rv.data
+ assert b"Added user" in rv.data, rv.data
# duplicate
rv = self._admin_moderator_add()
- assert b'Already a entry with that username' in rv.data, rv.data
+ assert b"Already a entry with that username" in rv.data, rv.data
self.logout()
# test this actually works
- self.login(username='dave dave com', password='foobarbaz123.')
+ self.login(username="dave dave com", password="foobarbaz123.")
self.logout()
# remove
self.login()
- rv = self.app.get('admin/moderator/2/delete', follow_redirects=True)
- assert b'Deleted user' in rv.data, rv.data
+ rv = self.app.get("admin/moderator/2/delete", follow_redirects=True)
+ assert b"Deleted user" in rv.data, rv.data
def test_admin_show_reviews(self):
self.review_submit()
self.login()
- rv = self.app.get('/admin/show/all')
- assert b'An essential ' in rv.data, rv.data
+ rv = self.app.get("/admin/show/all")
+ assert b"An essential " in rv.data, rv.data
- rv = self.app.get('/admin/show/lang/en_US')
- assert b'An essential ' in rv.data, rv.data
- rv = self.app.get('/admin/show/lang/fr_FR')
- assert b'An essential ' not in rv.data, rv.data
+ rv = self.app.get("/admin/show/lang/en_US")
+ assert b"An essential " in rv.data, rv.data
+ rv = self.app.get("/admin/show/lang/fr_FR")
+ assert b"An essential " not in rv.data, rv.data
def test_admin_moderators(self):
self.login()
- rv = self.app.get('/admin/moderators/all')
+ rv = self.app.get("/admin/moderators/all")
assert self.user_hash.encode() in rv.data, rv.data
def test_admin_search(self):
self.review_submit()
self.login()
- rv = self.app.get('/admin/search?value=notgoingtoexist')
- assert b'There are no results for this query' in rv.data, rv.data
- rv = self.app.get('/admin/search?value=inkscape+notgoingtoexist')
- assert b'Somebody Import' in rv.data, rv.data
-
- def _admin_taboo_add(self, locale='en', value='inkscape', description='ola!', severity=0):
- data = {'locale': locale, 'value': value, 'description': description, 'severity': severity}
- return self.app.post('/admin/taboo/add', data=data, follow_redirects=True)
+ rv = self.app.get("/admin/search?value=notgoingtoexist")
+ assert b"There are no results for this query" in rv.data, rv.data
+ rv = self.app.get("/admin/search?value=inkscape+notgoingtoexist")
+ assert b"Somebody Import" in rv.data, rv.data
+
+ def _admin_taboo_add(
+ self, locale="en", value="inkscape", description="ola!", severity=0
+ ):
+ data = {
+ "locale": locale,
+ "value": value,
+ "description": description,
+ "severity": severity,
+ }
+ return self.app.post("/admin/taboo/add", data=data, follow_redirects=True)
def test_admin_components(self):
self.review_submit()
- self.review_submit(app_id='inkscape-ubuntu-lts.desktop')
+ self.review_submit(app_id="inkscape-ubuntu-lts.desktop")
self.login()
- rv = self.app.get('/admin/component/all')
- assert b'inkscape.desktop' in rv.data, rv.data
- assert b'inkscape-ubuntu-lts.desktop' in rv.data, rv.data
-
- rv = self.app.get('/admin/component/join/notgoingtoexist.desktop/inkscape-ubuntu-lts.desktop',
follow_redirects=True)
- assert b'No parent component found' in rv.data, rv.data
- rv = self.app.get('/admin/component/join/inkscape.desktop/notgoingtoexist.desktop',
follow_redirects=True)
- assert b'No child component found' in rv.data, rv.data
- rv = self.app.get('/admin/component/join/inkscape.desktop/inkscape.desktop', follow_redirects=True)
- assert b'Parent and child components were the same' in rv.data, rv.data
- rv = self.app.get('/admin/component/join/inkscape.desktop/inkscape-ubuntu-lts.desktop',
follow_redirects=True)
- assert b'Joined components' in rv.data, rv.data
+ rv = self.app.get("/admin/component/all")
+ assert b"inkscape.desktop" in rv.data, rv.data
+ assert b"inkscape-ubuntu-lts.desktop" in rv.data, rv.data
+
+ rv = self.app.get(
+ "/admin/component/join/notgoingtoexist.desktop/inkscape-ubuntu-lts.desktop",
+ follow_redirects=True,
+ )
+ assert b"No parent component found" in rv.data, rv.data
+ rv = self.app.get(
+ "/admin/component/join/inkscape.desktop/notgoingtoexist.desktop",
+ follow_redirects=True,
+ )
+ assert b"No child component found" in rv.data, rv.data
+ rv = self.app.get(
+ "/admin/component/join/inkscape.desktop/inkscape.desktop",
+ follow_redirects=True,
+ )
+ assert b"Parent and child components were the same" in rv.data, rv.data
+ rv = self.app.get(
+ "/admin/component/join/inkscape.desktop/inkscape-ubuntu-lts.desktop",
+ follow_redirects=True,
+ )
+ assert b"Joined components" in rv.data, rv.data
# again
- rv = self.app.get('/admin/component/join/inkscape.desktop/inkscape-ubuntu-lts.desktop',
follow_redirects=True)
- assert b'Parent and child already set up' in rv.data, rv.data
+ rv = self.app.get(
+ "/admin/component/join/inkscape.desktop/inkscape-ubuntu-lts.desktop",
+ follow_redirects=True,
+ )
+ assert b"Parent and child already set up" in rv.data, rv.data
# delete inkscape.desktop
rv = self._api_review_delete()
- assert b'removed review #1' in rv.data, rv.data
+ assert b"removed review #1" in rv.data, rv.data
# still match for the alternate name
self.review_fetch()
def test_admin_component_delete(self):
self.review_submit()
- self.review_submit(app_id='inkscape-ubuntu-lts.desktop')
+ self.review_submit(app_id="inkscape-ubuntu-lts.desktop")
self.login()
# delete one, causing the review to get deleted too
- rv = self.app.get('/admin/component/delete/99999', follow_redirects=True)
- assert b'Unable to find component' in rv.data, rv.data
- rv = self.app.get('/admin/component/delete/2', follow_redirects=True)
- assert b'Deleted component with 1 reviews' in rv.data, rv.data
+ rv = self.app.get("/admin/component/delete/99999", follow_redirects=True)
+ assert b"Unable to find component" in rv.data, rv.data
+ rv = self.app.get("/admin/component/delete/2", follow_redirects=True)
+ assert b"Deleted component with 1 reviews" in rv.data, rv.data
# still match for the alternate name
self.review_fetch()
- rv = self.app.get('/admin/component/delete/1', follow_redirects=True)
- assert b'Deleted component with 1 reviews' in rv.data, rv.data
+ rv = self.app.get("/admin/component/delete/1", follow_redirects=True)
+ assert b"Deleted component with 1 reviews" in rv.data, rv.data
def test_admin_taboo(self):
self.login()
- rv = self.app.get('/admin/taboo/all')
- assert b'There are no taboos stored' in rv.data, rv.data
+ rv = self.app.get("/admin/taboo/all")
+ assert b"There are no taboos stored" in rv.data, rv.data
# add taboos
rv = self._admin_taboo_add()
- assert b'Added taboo' in rv.data, rv.data
- assert b'inkscape' in rv.data, rv.data
+ assert b"Added taboo" in rv.data, rv.data
+ assert b"inkscape" in rv.data, rv.data
rv = self._admin_taboo_add()
- assert b'Already added that taboo' in rv.data, rv.data
- rv = self._admin_taboo_add(locale='fr_FR')
- assert b'Added taboo' in rv.data, rv.data
+ assert b"Already added that taboo" in rv.data, rv.data
+ rv = self._admin_taboo_add(locale="fr_FR")
+ assert b"Added taboo" in rv.data, rv.data
# submit something, and ensure it's flagged
self.review_submit()
- rv = self.app.get('/admin/review/1')
- assert b'Somebody Important' in rv.data, rv.data
- assert b'Contains taboo' in rv.data, rv.data
+ rv = self.app.get("/admin/review/1")
+ assert b"Somebody Important" in rv.data, rv.data
+ assert b"Contains taboo" in rv.data, rv.data
# delete
- rv = self.app.get('/admin/taboo/1/delete', follow_redirects=True)
- assert b'Deleted taboo' in rv.data, rv.data
- rv = self.app.get('/admin/taboo/1/delete', follow_redirects=True)
- assert b'No taboo with ID' in rv.data, rv.data
+ rv = self.app.get("/admin/taboo/1/delete", follow_redirects=True)
+ assert b"Deleted taboo" in rv.data, rv.data
+ rv = self.app.get("/admin/taboo/1/delete", follow_redirects=True)
+ assert b"No taboo with ID" in rv.data, rv.data
def test_api_submit_when_banned(self):
@@ -308,35 +354,38 @@ class OdrsTest(unittest.TestCase):
# add user to the ban list
self.login()
- rv = self.app.get('/admin/user_ban/{}'.format(self.user_hash), follow_redirects=True)
- assert b'Banned user' in rv.data, rv.data
- assert b'deleted 1 reviews' in rv.data, rv.data
+ rv = self.app.get(
+ "/admin/user_ban/{}".format(self.user_hash), follow_redirects=True
+ )
+ assert b"Banned user" in rv.data, rv.data
+ assert b"deleted 1 reviews" in rv.data, rv.data
self.logout()
# try to submit another review
- rv = self._review_submit(app_id='gimp.desktop')
- assert b'account has been disabled due to abuse' in rv.data, rv.data
+ rv = self._review_submit(app_id="gimp.desktop")
+ assert b"account has been disabled due to abuse" in rv.data, rv.data
def test_login_logout(self):
# test logging in and out
- rv = self._login('admin test com', 'Pa$$w0rd')
- assert b'/admin/show/reported' in rv.data, rv.data
+ rv = self._login("admin test com", "Pa$$w0rd")
+ assert b"/admin/show/reported" in rv.data, rv.data
rv = self._logout()
- rv = self._login('admin test com', 'Pa$$w0rd')
- assert b'/admin/show/reported' in rv.data, rv.data
+ rv = self._login("admin test com", "Pa$$w0rd")
+ assert b"/admin/show/reported" in rv.data, rv.data
rv = self._logout()
- assert b'/admin/show/reported' not in rv.data, rv.data
- rv = self._login('FAILED test com', 'default')
- assert b'Incorrect username' in rv.data, rv.data
- rv = self._login('admin test com', 'defaultx')
- assert b'Incorrect password' in rv.data, rv.data
+ assert b"/admin/show/reported" not in rv.data, rv.data
+ rv = self._login("FAILED test com", "default")
+ assert b"Incorrect username" in rv.data, rv.data
+ rv = self._login("admin test com", "defaultx")
+ assert b"Incorrect password" in rv.data, rv.data
@staticmethod
- def run_cron_regenerate_ratings(fn='test.json'):
+ def run_cron_regenerate_ratings(fn="test.json"):
from odrs import app
from cron import _regenerate_ratings
+
with app.test_request_context():
_regenerate_ratings(fn)
@@ -345,143 +394,165 @@ class OdrsTest(unittest.TestCase):
from odrs import app
from cron import _auto_delete
+
with app.test_request_context():
_auto_delete(0)
def test_nologin_required(self):
# all these are viewable without being logged in
- uris = ['/',
- '/privacy',
- ]
+ uris = [
+ "/",
+ "/privacy",
+ ]
for uri in uris:
rv = self.app.get(uri, follow_redirects=True)
- assert b'favicon.ico' in rv.data, rv.data
- assert b'Error!' not in rv.data, rv.data
-
- def _review_submit(self, app_id=None, locale='en_US', distro='Fedora',
- version='2:1.2.3~dsg',
- summary=' An essential part of my daily workflow',
- user_hash=None, user_skey=None,
- user_display='Somebody Important'):
+ assert b"favicon.ico" in rv.data, rv.data
+ assert b"Error!" not in rv.data, rv.data
+
+ def _review_submit(
+ self,
+ app_id=None,
+ locale="en_US",
+ distro="Fedora",
+ version="2:1.2.3~dsg",
+ summary=" An essential part of my daily workflow",
+ user_hash=None,
+ user_skey=None,
+ user_display="Somebody Important",
+ ):
if not app_id:
- app_id = 'inkscape.desktop'
+ app_id = "inkscape.desktop"
if not user_hash:
user_hash = self.user_hash
if not user_skey:
user_skey = _get_user_key(user_hash, app_id)
# upload a review
- data = {'app_id': app_id,
- 'locale': locale,
- 'summary': summary,
- 'description': 'Inkscape has been a essential part of my workflow for many years now.',
- 'user_hash': user_hash,
- 'user_skey': user_skey,
- 'user_display': user_display,
- 'distro': distro,
- 'rating': 100,
- 'version': version}
- return self.app.post('/1.0/reviews/api/submit', data=json.dumps(data), follow_redirects=True)
+ data = {
+ "app_id": app_id,
+ "locale": locale,
+ "summary": summary,
+ "description": "Inkscape has been a essential part of my workflow for many years now.",
+ "user_hash": user_hash,
+ "user_skey": user_skey,
+ "user_display": user_display,
+ "distro": distro,
+ "rating": 100,
+ "version": version,
+ }
+ return self.app.post(
+ "/1.0/reviews/api/submit", data=json.dumps(data), follow_redirects=True
+ )
def review_submit(self, app_id=None, user_hash=None):
rv = self._review_submit(app_id=app_id, user_hash=user_hash)
assert b'"success": true' in rv.data, rv.data
- def _review_fetch(self,
- app_id='inkscape.desktop',
- user_hash=None,
- locale='en_US',
- distro='Fedora',
- compat_ids=None,
- version='1.2.3'):
+ def _review_fetch(
+ self,
+ app_id="inkscape.desktop",
+ user_hash=None,
+ locale="en_US",
+ distro="Fedora",
+ compat_ids=None,
+ version="1.2.3",
+ ):
if not user_hash:
user_hash = self.user_hash
# fetch some reviews
- data = {'app_id': app_id,
- 'user_hash': user_hash,
- 'locale': locale,
- 'distro': distro,
- 'limit': 5,
- 'version': version}
+ data = {
+ "app_id": app_id,
+ "user_hash": user_hash,
+ "locale": locale,
+ "distro": distro,
+ "limit": 5,
+ "version": version,
+ }
if compat_ids:
- data['compat_ids'] = compat_ids
- return self.app.post('/1.0/reviews/api/fetch', data=json.dumps(data), follow_redirects=True)
+ data["compat_ids"] = compat_ids
+ return self.app.post(
+ "/1.0/reviews/api/fetch", data=json.dumps(data), follow_redirects=True
+ )
def review_fetch(self):
- rv = self._review_fetch(app_id='inkscape.desktop')
- assert b'An essential part of my daily workflow' in rv.data, rv.data
+ rv = self._review_fetch(app_id="inkscape.desktop")
+ assert b"An essential part of my daily workflow" in rv.data, rv.data
def test_api_moderate_locale(self):
- rv = self.app.get('/1.0/reviews/api/moderate/{}/en_GB'.format(self.user_hash))
- assert rv.data == b'[]', rv.data
+ rv = self.app.get("/1.0/reviews/api/moderate/{}/en_GB".format(self.user_hash))
+ assert rv.data == b"[]", rv.data
self.review_submit()
- rv = self.app.get('/1.0/reviews/api/moderate/{}/en_GB'.format(self.user_hash))
- assert b'Somebody Important' in rv.data, rv.data
- rv = self.app.get('/1.0/reviews/api/moderate/{}/fr_FR'.format(self.user_hash))
- assert rv.data == b'[]', rv.data
+ rv = self.app.get("/1.0/reviews/api/moderate/{}/en_GB".format(self.user_hash))
+ assert b"Somebody Important" in rv.data, rv.data
+ rv = self.app.get("/1.0/reviews/api/moderate/{}/fr_FR".format(self.user_hash))
+ assert rv.data == b"[]", rv.data
def test_api_fetch_no_results(self):
# get the skey back for an app with no reviews
- rv = self._review_fetch(app_id='not-going-to-exist.desktop')
- assert b'An essential part of my daily workflow' not in rv.data, rv.data
- assert b'user_skey' in rv.data, rv.data
+ rv = self._review_fetch(app_id="not-going-to-exist.desktop")
+ assert b"An essential part of my daily workflow" not in rv.data, rv.data
+ assert b"user_skey" in rv.data, rv.data
def test_api_fetch_compat_id(self):
self.review_submit()
# get the reviews back for the app using compat IDs
- rv = self._review_fetch(app_id='foo.desktop', compat_ids=['inkscape.desktop'])
- assert b'An essential part of my daily workflow' in rv.data, rv.data
- assert b'user_skey' in rv.data, rv.data
+ rv = self._review_fetch(app_id="foo.desktop", compat_ids=["inkscape.desktop"])
+ assert b"An essential part of my daily workflow" in rv.data, rv.data
+ assert b"user_skey" in rv.data, rv.data
def review_upvote(self, user_hash=None):
if not user_hash:
user_hash = self.user_hash
- data = {'review_id': 1,
- 'app_id': 'inkscape.desktop',
- 'user_hash': user_hash,
- 'user_skey': _get_user_key(user_hash, 'inkscape.desktop')}
- return self.app.post('/1.0/reviews/api/upvote', data=json.dumps(data))
+ data = {
+ "review_id": 1,
+ "app_id": "inkscape.desktop",
+ "user_hash": user_hash,
+ "user_skey": _get_user_key(user_hash, "inkscape.desktop"),
+ }
+ return self.app.post("/1.0/reviews/api/upvote", data=json.dumps(data))
def review_report(self, user_hash=None):
if not user_hash:
user_hash = self.user_hash
- data = {'review_id': 1,
- 'app_id': 'inkscape.desktop',
- 'user_hash': user_hash,
- 'user_skey': _get_user_key(user_hash, 'inkscape.desktop')}
- return self.app.post('/1.0/reviews/api/report', data=json.dumps(data))
+ data = {
+ "review_id": 1,
+ "app_id": "inkscape.desktop",
+ "user_hash": user_hash,
+ "user_skey": _get_user_key(user_hash, "inkscape.desktop"),
+ }
+ return self.app.post("/1.0/reviews/api/report", data=json.dumps(data))
def test_api_upvote(self):
# does not exist
rv = self.review_upvote()
- assert b'invalid review ID' in rv.data, rv.data
+ assert b"invalid review ID" in rv.data, rv.data
# first upvote
self.review_submit()
rv = self.review_upvote()
assert b'success": true' in rv.data, rv.data
- assert b'voted #1 1' in rv.data, rv.data
+ assert b"voted #1 1" in rv.data, rv.data
# duplicate upvote
rv = self.review_upvote()
assert b'success": false' in rv.data, rv.data
- assert b'already voted on this app' in rv.data, rv.data
+ assert b"already voted on this app" in rv.data, rv.data
# check vote_id is set
- rv = self._review_fetch(app_id='inkscape.desktop')
+ rv = self._review_fetch(app_id="inkscape.desktop")
assert b'vote_id": 1' in rv.data, rv.data
# delete review, hopefully deleting vote too
rv = self._api_review_delete()
- assert b'removed review #1' in rv.data, rv.data
+ assert b"removed review #1" in rv.data, rv.data
self.run_cron_auto_delete()
- rv = self._review_fetch(app_id='inkscape.desktop')
- assert b'vote_id' not in rv.data, rv.data
+ rv = self._review_fetch(app_id="inkscape.desktop")
+ assert b"vote_id" not in rv.data, rv.data
def test_api_report(self):
@@ -492,77 +563,85 @@ class OdrsTest(unittest.TestCase):
# should not appear again
rv = self.review_report()
assert b'success": true' in rv.data, rv.data
- assert b'voted #1 -5' in rv.data, rv.data
- rv = self.review_report(user_hash='729342d6a7c477bb1ea0186f8c60804a3d783183')
+ assert b"voted #1 -5" in rv.data, rv.data
+ rv = self.review_report(user_hash="729342d6a7c477bb1ea0186f8c60804a3d783183")
assert b'success": true' in rv.data, rv.data
- assert b'voted #1 -5' in rv.data, rv.data
- rv = self._review_fetch(app_id='inkscape.desktop')
- assert b'An essential part of my daily workflow' not in rv.data, rv.data
+ assert b"voted #1 -5" in rv.data, rv.data
+ rv = self._review_fetch(app_id="inkscape.desktop")
+ assert b"An essential part of my daily workflow" not in rv.data, rv.data
# duplicate upvote
rv = self.review_upvote()
assert b'success": false' in rv.data, rv.data
- assert b'already voted on this app' in rv.data, rv.data
+ assert b"already voted on this app" in rv.data, rv.data
def test_api_app_rating(self):
# nothing
- rv = self.app.get('/1.0/reviews/api/ratings/not-going-to-exist.desktop')
- assert rv.data == b'[]', rv.data
+ rv = self.app.get("/1.0/reviews/api/ratings/not-going-to-exist.desktop")
+ assert rv.data == b"[]", rv.data
# something
self.review_submit()
- rv = self.app.get('/1.0/reviews/api/ratings/inkscape.desktop')
+ rv = self.app.get("/1.0/reviews/api/ratings/inkscape.desktop")
assert b'star1": 0' in rv.data, rv.data
assert b'star5": 1' in rv.data, rv.data
assert b'total": 1' in rv.data, rv.data
# all
- self.review_submit(user_hash='0000000000000000000000000000000000000000')
- rv = self.app.get('/1.0/reviews/api/ratings')
- assert b'inkscape.desktop' in rv.data, rv.data
+ self.review_submit(user_hash="0000000000000000000000000000000000000000")
+ rv = self.app.get("/1.0/reviews/api/ratings")
+ assert b"inkscape.desktop" in rv.data, rv.data
assert b'star1": 0' in rv.data, rv.data
assert b'star5": 2' in rv.data, rv.data
assert b'total": 2' in rv.data, rv.data
def _api_review_delete(self):
- data = {'review_id': 1,
- 'app_id': 'inkscape.desktop',
- 'user_hash': self.user_hash,
- 'user_skey': _get_user_key(self.user_hash, 'inkscape.desktop')}
- return self.app.post('/1.0/reviews/api/remove', data=json.dumps(data))
+ data = {
+ "review_id": 1,
+ "app_id": "inkscape.desktop",
+ "user_hash": self.user_hash,
+ "user_skey": _get_user_key(self.user_hash, "inkscape.desktop"),
+ }
+ return self.app.post("/1.0/reviews/api/remove", data=json.dumps(data))
def test_api_remove(self):
self.review_submit()
# wrong app_id
- data = {'review_id': 1,
- 'app_id': 'dave.desktop',
- 'user_hash': self.user_hash,
- 'user_skey': _get_user_key(self.user_hash, 'dave.desktop')}
- rv = self.app.post('/1.0/reviews/api/remove', data=json.dumps(data))
- assert b'the app_id is invalid' in rv.data, rv.data
+ data = {
+ "review_id": 1,
+ "app_id": "dave.desktop",
+ "user_hash": self.user_hash,
+ "user_skey": _get_user_key(self.user_hash, "dave.desktop"),
+ }
+ rv = self.app.post("/1.0/reviews/api/remove", data=json.dumps(data))
+ assert b"the app_id is invalid" in rv.data, rv.data
# wrong user_hash
- data = {'review_id': 1,
- 'app_id': 'inkscape.desktop',
- 'user_hash': _get_user_key(self.user_hash, 'inkscape.desktop'),
- 'user_skey': _get_user_key(self.user_hash, 'inkscape.desktop')}
- rv = self.app.post('/1.0/reviews/api/remove', data=json.dumps(data))
- assert b'no review' in rv.data, rv.data
+ data = {
+ "review_id": 1,
+ "app_id": "inkscape.desktop",
+ "user_hash": _get_user_key(self.user_hash, "inkscape.desktop"),
+ "user_skey": _get_user_key(self.user_hash, "inkscape.desktop"),
+ }
+ rv = self.app.post("/1.0/reviews/api/remove", data=json.dumps(data))
+ assert b"no review" in rv.data, rv.data
# wrong user_skey
- data = {'review_id': 1,
- 'app_id': 'inkscape.desktop',
- 'user_hash': self.user_hash,
- 'user_skey': self.user_hash}
- rv = self.app.post('/1.0/reviews/api/remove', data=json.dumps(data))
- assert b'invalid user_skey' in rv.data, rv.data
+ data = {
+ "review_id": 1,
+ "app_id": "inkscape.desktop",
+ "user_hash": self.user_hash,
+ "user_skey": self.user_hash,
+ }
+ rv = self.app.post("/1.0/reviews/api/remove", data=json.dumps(data))
+ assert b"invalid user_skey" in rv.data, rv.data
# delete a review
rv = self._api_review_delete()
- assert b'removed review #1' in rv.data, rv.data
+ assert b"removed review #1" in rv.data, rv.data
def test_api_submit(self):
@@ -571,59 +650,64 @@ class OdrsTest(unittest.TestCase):
assert b'"success": true' in rv.data, rv.data
# upload a 2nd report
- rv = self._review_submit(app_id='gimp.desktop')
+ rv = self._review_submit(app_id="gimp.desktop")
assert b'"success": true' in rv.data, rv.data
# upload a duplicate report
rv = self._review_submit()
assert b'success": false' in rv.data, rv.data
- assert b'already reviewed this app' in rv.data, rv.data
+ assert b"already reviewed this app" in rv.data, rv.data
# upload an invalid report
- rv = self._review_submit(summary='<html>foo</html>')
+ rv = self._review_submit(summary="<html>foo</html>")
assert b'success": false' in rv.data, rv.data
- assert b'is not a valid string' in rv.data, rv.data
- rv = self._review_submit(summary='')
+ assert b"is not a valid string" in rv.data, rv.data
+ rv = self._review_submit(summary="")
assert b'success": false' in rv.data, rv.data
- assert b'missing data' in rv.data, rv.data
+ assert b"missing data" in rv.data, rv.data
# get the review back
- rv = self.app.get('/1.0/reviews/api/app/inkscape.desktop')
- assert b'Somebody Important' in rv.data, rv.data
- assert b'An essential part of my daily workflow' in rv.data, rv.data
- assert b'user_skey' not in rv.data, rv.data
+ rv = self.app.get("/1.0/reviews/api/app/inkscape.desktop")
+ assert b"Somebody Important" in rv.data, rv.data
+ assert b"An essential part of my daily workflow" in rv.data, rv.data
+ assert b"user_skey" not in rv.data, rv.data
# get the review back with skey
- rv = self.app.get('/1.0/reviews/api/app/inkscape.desktop/{}'.format(self.user_hash))
- assert b'An essential part of my daily workflow' in rv.data, rv.data
- assert b'user_skey' in rv.data, rv.data
+ rv = self.app.get(
+ "/1.0/reviews/api/app/inkscape.desktop/{}".format(self.user_hash)
+ )
+ assert b"An essential part of my daily workflow" in rv.data, rv.data
+ assert b"user_skey" in rv.data, rv.data
# get the reviews back for the app
- rv = self._review_fetch(distro='Ubuntu', version='1.2.4')
- assert b'An essential part of my daily workflow' in rv.data, rv.data
- assert b'user_skey' in rv.data, rv.data
+ rv = self._review_fetch(distro="Ubuntu", version="1.2.4")
+ assert b"An essential part of my daily workflow" in rv.data, rv.data
+ assert b"user_skey" in rv.data, rv.data
def test_fail_when_login_required(self):
# all these are an error when not logged in
- uris = ['/admin/graph_month',
- '/admin/graph_year',
- '/admin/stats',
- '/admin/user_ban/1',
- '/admin/show/reported',
- '/admin/stats',
- '/admin/moderators/all']
+ uris = [
+ "/admin/graph_month",
+ "/admin/graph_year",
+ "/admin/stats",
+ "/admin/user_ban/1",
+ "/admin/show/reported",
+ "/admin/stats",
+ "/admin/moderators/all",
+ ]
for uri in uris:
rv = self.app.get(uri, follow_redirects=True)
- assert b'favicon.ico' in rv.data, rv.data
- assert b'Please log in to access this page' in rv.data, (uri, rv.data)
+ assert b"favicon.ico" in rv.data, rv.data
+ assert b"Please log in to access this page" in rv.data, (uri, rv.data)
# POST only
- uris = ['/admin/modify/1']
+ uris = ["/admin/modify/1"]
for uri in uris:
rv = self.app.post(uri, follow_redirects=True)
- assert b'favicon.ico' in rv.data, rv.data
- assert b'Please log in to access this page' in rv.data, rv.data
+ assert b"favicon.ico" in rv.data, rv.data
+ assert b"Please log in to access this page" in rv.data, rv.data
+
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/app_data/odrs/tests/util_test.py b/app_data/odrs/tests/util_test.py
index 8187f0c..16bdf48 100644
--- a/app_data/odrs/tests/util_test.py
+++ b/app_data/odrs/tests/util_test.py
@@ -13,43 +13,56 @@ import sys
import unittest
# allows us to run this from the project root
-sys.path.append(os.path.realpath('.'))
+sys.path.append(os.path.realpath("."))
from odrs.util import json_success, json_error, _locale_is_compatible
from odrs.util import _get_user_key, _password_hash
from odrs.util import _sanitised_version, _sanitised_summary, _sanitised_description
-class UtilTest(unittest.TestCase):
+class UtilTest(unittest.TestCase):
def test_sanitise(self):
- self.assertEqual(_sanitised_version('16.12.3'), '16.12.3')
- self.assertEqual(_sanitised_version('0:1.2.3+rh'), '1.2.3')
- self.assertEqual(_sanitised_version('16.11.0~ds0'), '16.11.0')
- self.assertEqual(_sanitised_summary(' not sure why people include. '), 'not sure why people
include')
- self.assertEqual(_sanitised_description(' this is awesome :) !! '), 'this is awesome !!')
+ self.assertEqual(_sanitised_version("16.12.3"), "16.12.3")
+ self.assertEqual(_sanitised_version("0:1.2.3+rh"), "1.2.3")
+ self.assertEqual(_sanitised_version("16.11.0~ds0"), "16.11.0")
+ self.assertEqual(
+ _sanitised_summary(" not sure why people include. "),
+ "not sure why people include",
+ )
+ self.assertEqual(
+ _sanitised_description(" this is awesome :) !! "), "this is awesome !!"
+ )
def test_response(self):
- self.assertEqual(str(json_success('ok')), '<Response 40 bytes [200 OK]>')
- self.assertEqual(str(json_error('nok')), '<Response 42 bytes [400 BAD REQUEST]>')
+ self.assertEqual(str(json_success("ok")), "<Response 40 bytes [200 OK]>")
+ self.assertEqual(
+ str(json_error("nok")), "<Response 42 bytes [400 BAD REQUEST]>"
+ )
def test_locale(self):
- self.assertTrue(_locale_is_compatible('en_GB', 'en_GB'))
- self.assertTrue(_locale_is_compatible('en_GB', 'en_AU'))
- self.assertTrue(_locale_is_compatible('en_GB', 'C'))
- self.assertTrue(_locale_is_compatible('C', 'en_GB'))
- self.assertFalse(_locale_is_compatible('fr_FR', 'en_GB'))
+ self.assertTrue(_locale_is_compatible("en_GB", "en_GB"))
+ self.assertTrue(_locale_is_compatible("en_GB", "en_AU"))
+ self.assertTrue(_locale_is_compatible("en_GB", "C"))
+ self.assertTrue(_locale_is_compatible("C", "en_GB"))
+ self.assertFalse(_locale_is_compatible("fr_FR", "en_GB"))
def test_user_key(self):
- os.environ['ODRS_REVIEWS_SECRET'] = '1'
- self.assertEqual(_get_user_key('foo', 'gimp.desktop'), '8d68a9e8054a18cb11e62242f9036aca786551d8')
+ os.environ["ODRS_REVIEWS_SECRET"] = "1"
+ self.assertEqual(
+ _get_user_key("foo", "gimp.desktop"),
+ "8d68a9e8054a18cb11e62242f9036aca786551d8",
+ )
def test_legacy_hash(self):
- self.assertEqual(_password_hash('foo'), '9cab340b3184a1f792d6629806703aed450ecd48')
+ self.assertEqual(
+ _password_hash("foo"), "9cab340b3184a1f792d6629806703aed450ecd48"
+ )
+
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/app_data/odrs/util.py b/app_data/odrs/util.py
index bc13dad..51e76e9 100644
--- a/app_data/odrs/util.py
+++ b/app_data/odrs/util.py
@@ -14,63 +14,70 @@ from sqlalchemy import or_
from flask import Response
+
def json_success(msg=None, errcode=200):
- """ Success handler: JSON output """
+ """Success handler: JSON output"""
item = {}
- item['success'] = True
+ item["success"] = True
if msg:
- item['msg'] = msg
- dat = json.dumps(item, sort_keys=True, indent=4, separators=(',', ': '))
- return Response(response=dat,
- status=errcode, \
- mimetype='application/json')
+ item["msg"] = msg
+ dat = json.dumps(item, sort_keys=True, indent=4, separators=(",", ": "))
+ return Response(response=dat, status=errcode, mimetype="application/json")
+
def json_error(msg=None, errcode=400):
- """ Error handler: JSON output """
+ """Error handler: JSON output"""
item = {}
- item['success'] = False
+ item["success"] = False
if msg:
- item['msg'] = msg
- dat = json.dumps(item, sort_keys=True, indent=4, separators=(',', ': '))
- return Response(response=dat,
- status=errcode, \
- mimetype='application/json')
+ item["msg"] = msg
+ dat = json.dumps(item, sort_keys=True, indent=4, separators=(",", ": "))
+ return Response(response=dat, status=errcode, mimetype="application/json")
+
def _get_datestr_from_dt(when):
- return int('%04i%02i%02i' % (when.year, when.month, when.day))
+ return int("%04i%02i%02i" % (when.year, when.month, when.day))
+
def _get_user_key(user_hash, app_id):
from odrs import app
- key = 'invalid'
+
+ key = "invalid"
try:
- key = hashlib.sha1(app.secret_key.encode('utf-8') +
- user_hash.encode('utf-8') +
- app_id.encode('utf-8')).hexdigest()
+ key = hashlib.sha1(
+ app.secret_key.encode("utf-8")
+ + user_hash.encode("utf-8")
+ + app_id.encode("utf-8")
+ ).hexdigest()
except UnicodeEncodeError as e:
- print('invalid input: %s,%s: %s' % (user_hash, app_id, str(e)))
+ print("invalid input: %s,%s: %s" % (user_hash, app_id, str(e)))
return key
-def _eventlog_add(user_addr=None,
- user_id=None,
- app_id=None,
- message=None,
- important=False):
- """ Adds a warning to the event log """
+
+def _eventlog_add(
+ user_addr=None, user_id=None, app_id=None, message=None, important=False
+):
+ """Adds a warning to the event log"""
from .models import Event
from odrs import db
+
db.session.add(Event(user_addr, user_id, app_id, message, important))
db.session.commit()
+
def _get_rating_for_component(component, min_total=1):
- """ Gets the ratings information for the application """
+ """Gets the ratings information for the application"""
from odrs import db
from odrs.models import Review, Component
# get all ratings for app
array = [0] * 6
- for rating in db.session.query(Review.rating).\
- join(Component).\
- filter(Component.app_id.in_(component.app_ids)).all():
+ for rating in (
+ db.session.query(Review.rating)
+ .join(Component)
+ .filter(Component.app_id.in_(component.app_ids))
+ .all()
+ ):
idx = int(rating[0] / 20)
if idx > 5:
continue
@@ -81,33 +88,44 @@ def _get_rating_for_component(component, min_total=1):
return []
# return as dict
- item = {'total': sum(array)}
+ item = {"total": sum(array)}
for idx in range(6):
- item['star{}'.format(idx)] = array[idx]
+ item["star{}".format(idx)] = array[idx]
return item
+
def _password_hash(value):
- """ Generate a legacy salted hash of the password string """
- salt = 'odrs%%%'
- return hashlib.sha1(salt.encode('utf-8') + value.encode('utf-8')).hexdigest()
+ """Generate a legacy salted hash of the password string"""
+ salt = "odrs%%%"
+ return hashlib.sha1(salt.encode("utf-8") + value.encode("utf-8")).hexdigest()
+
def _addr_hash(value):
- """ Generate a salted hash of the IP address """
+ """Generate a salted hash of the IP address"""
from odrs import app
- return hashlib.sha1((app.secret_key + value).encode('utf-8')).hexdigest()
+
+ return hashlib.sha1((app.secret_key + value).encode("utf-8")).hexdigest()
+
def _get_taboos_for_locale(locale):
from .models import Taboo
from odrs import db
- if locale.find('_') != -1:
- lang, _ = locale.split('_', maxsplit=1)
- return db.session.query(Taboo).\
- filter(or_(Taboo.locale == locale,
- Taboo.locale == lang,
- Taboo.locale == 'en')).all()
- return db.session.query(Taboo).\
- filter(or_(Taboo.locale == locale,
- Taboo.locale == 'en')).all()
+
+ if locale.find("_") != -1:
+ lang, _ = locale.split("_", maxsplit=1)
+ return (
+ db.session.query(Taboo)
+ .filter(
+ or_(Taboo.locale == locale, Taboo.locale == lang, Taboo.locale == "en")
+ )
+ .all()
+ )
+ return (
+ db.session.query(Taboo)
+ .filter(or_(Taboo.locale == locale, Taboo.locale == "en"))
+ .all()
+ )
+
def _sanitised_input(val):
@@ -115,53 +133,57 @@ def _sanitised_input(val):
val = val.strip()
# fix up style issues
- val = val.replace('!!!', '!')
- val = val.replace(':)', '')
- val = val.replace(' ', ' ')
+ val = val.replace("!!!", "!")
+ val = val.replace(":)", "")
+ val = val.replace(" ", " ")
return val
+
def _sanitised_summary(val):
val = _sanitised_input(val)
- if val.endswith('.'):
- val = val[:len(val)-1]
+ if val.endswith("."):
+ val = val[: len(val) - 1]
return val
+
def _sanitised_description(val):
return _sanitised_input(val)
+
def _sanitised_version(val):
# remove epoch
- idx = val.find(':')
+ idx = val.find(":")
if idx != -1:
- val = val[idx+1:]
+ val = val[idx + 1 :]
# remove distro addition
- idx = val.find('+')
+ idx = val.find("+")
if idx != -1:
val = val[:idx]
- idx = val.find('~')
+ idx = val.find("~")
if idx != -1:
val = val[:idx]
return val
+
def _locale_is_compatible(l1, l2):
- """ Returns True if the locale is compatible """
+ """Returns True if the locale is compatible"""
# trivial case
if l1 == l2:
return True
# language code matches
- lang1 = l1.split('_')[0]
- lang2 = l2.split('_')[0]
+ lang1 = l1.split("_")[0]
+ lang2 = l2.split("_")[0]
if lang1 == lang2:
return True
# LANG=C
- en_langs = ['C', 'en']
+ en_langs = ["C", "en"]
if lang1 in en_langs and lang2 in en_langs:
return True
diff --git a/app_data/odrs/views.py b/app_data/odrs/views.py
index 233434b..c42ff6e 100644
--- a/app_data/odrs/views.py
+++ b/app_data/odrs/views.py
@@ -9,94 +9,120 @@
import os
-from flask import request, url_for, redirect, flash, render_template, send_from_directory, g
+from flask import (
+ request,
+ url_for,
+ redirect,
+ flash,
+ render_template,
+ send_from_directory,
+ g,
+)
from flask_login import login_user, logout_user
from odrs import app, db
from .models import Moderator
+
@app.context_processor
def _utility_processor():
def format_rating(rating):
nr_stars = int(rating / 20)
- tmp = ''
+ tmp = ""
for _ in range(0, nr_stars):
- tmp += '★'
+ tmp += "★"
for _ in range(0, 5 - nr_stars):
- tmp += '☆'
+ tmp += "☆"
return tmp
def format_truncate(tmp, length):
if len(tmp) <= length:
return tmp
- return tmp[:length] + '…'
+ return tmp[:length] + "…"
def url_for_other_page(page):
args = request.view_args.copy()
- args['page'] = page
+ args["page"] = page
return url_for(request.endpoint, **args)
- return dict(format_rating=format_rating,
- format_truncate=format_truncate,
- url_for_other_page=url_for_other_page)
+ return dict(
+ format_rating=format_rating,
+ format_truncate=format_truncate,
+ url_for_other_page=url_for_other_page,
+ )
+
-@app.route('/login', methods=['GET', 'POST'])
+@app.route("/login", methods=["GET", "POST"])
def odrs_login():
- if request.method != 'POST':
- return render_template('login.html')
- user = db.session.query(Moderator).filter(Moderator.username == request.form['username']).first()
+ if request.method != "POST":
+ return render_template("login.html")
+ user = (
+ db.session.query(Moderator)
+ .filter(Moderator.username == request.form["username"])
+ .first()
+ )
if not user:
- flash('Incorrect username')
- return redirect(url_for('.odrs_login'))
- if not user.verify_password(request.form['password']):
- flash('Incorrect password')
- return redirect(url_for('.odrs_login'))
+ flash("Incorrect username")
+ return redirect(url_for(".odrs_login"))
+ if not user.verify_password(request.form["password"]):
+ flash("Incorrect password")
+ return redirect(url_for(".odrs_login"))
login_user(user, remember=False)
g.user = user
- flash('Logged in')
- return redirect(url_for('.odrs_index'))
+ flash("Logged in")
+ return redirect(url_for(".odrs_index"))
+
-@app.route('/logout')
+@app.route("/logout")
def odrs_logout():
logout_user()
- flash('Logged out.')
- return redirect(url_for('.odrs_index'))
+ flash("Logged out.")
+ return redirect(url_for(".odrs_index"))
+
@app.errorhandler(400)
def _error_internal(msg=None, errcode=400):
- """ Error handler: Internal """
- flash('Internal error: %s' % msg)
- return render_template('error.html'), errcode
+ """Error handler: Internal"""
+ flash("Internal error: %s" % msg)
+ return render_template("error.html"), errcode
+
@app.errorhandler(401)
def _error_permission_denied(msg=None):
- """ Error handler: Permission Denied """
- flash('Permission denied: %s' % msg)
- return render_template('error.html'), 401
+ """Error handler: Permission Denied"""
+ flash("Permission denied: %s" % msg)
+ return render_template("error.html"), 401
+
@app.errorhandler(404)
def odrs_error_page_not_found(msg=None):
- """ Error handler: File not found """
+ """Error handler: File not found"""
flash(msg)
- return render_template('error.html'), 404
+ return render_template("error.html"), 404
+
-@app.route('/')
+@app.route("/")
def odrs_index():
- """ start page """
- return render_template('index.html')
+ """start page"""
+ return render_template("index.html")
+
-@app.route('/privacy')
+@app.route("/privacy")
def odrs_privacy():
- """ odrs_privacy page """
- return render_template('privacy.html')
+ """odrs_privacy page"""
+ return render_template("privacy.html")
-@app.route('/oars')
+
+@app.route("/oars")
def oars_index():
- """ OARS page """
- return render_template('oars.html')
+ """OARS page"""
+ return render_template("oars.html")
+
-@app.route('/<path:resource>')
+@app.route("/<path:resource>")
def odrs_static_resource(resource):
- """ Return a static image or resource """
- return send_from_directory("%s/odrs/static/" % os.environ['HOME'], os.path.basename(resource))
+ """Return a static image or resource"""
+ return send_from_directory(
+ "%s/odrs/static/" % os.environ["HOME"], os.path.basename(resource)
+ )
diff --git a/app_data/odrs/views_admin.py b/app_data/odrs/views_admin.py
index e34d29e..a43075c 100644
--- a/app_data/odrs/views_admin.py
+++ b/app_data/odrs/views_admin.py
@@ -21,8 +21,9 @@ from .models import Review, User, Moderator, Vote, Taboo, Component
from .models import _vote_exists
from .util import _get_datestr_from_dt, _get_taboos_for_locale
+
def _get_chart_labels_months():
- """ Gets the chart labels """
+ """Gets the chart labels"""
now = datetime.date.today()
labels = []
offset = 0
@@ -32,52 +33,59 @@ def _get_chart_labels_months():
labels.append(calendar.month_name[now.month - i - offset])
return labels
+
def _get_chart_labels_days():
- """ Gets the chart labels """
+ """Gets the chart labels"""
now = datetime.date.today()
labels = []
for i in range(0, 30):
then = now - datetime.timedelta(i)
- labels.append('%02i-%02i-%02i' % (then.year, then.month, then.day))
+ labels.append("%02i-%02i-%02i" % (then.year, then.month, then.day))
return labels
+
def _get_langs_for_user(user):
if not user:
return None
- if not getattr(user, 'locales', None):
+ if not getattr(user, "locales", None):
return None
if not user.locales:
return None
- if user.locales == '*':
+ if user.locales == "*":
return None
- return user.locales.split(',')
+ return user.locales.split(",")
+
def _get_hash_for_user(user):
if not user:
return None
- if not getattr(user, 'user_hash', None):
+ if not getattr(user, "user_hash", None):
return None
return user.user_hash
+
def _password_check(value):
- """ Check the password for suitability """
+ """Check the password for suitability"""
success = True
if len(value) < 8:
success = False
- flash('The password is too short, the minimum is 8 characters', 'warning')
+ flash("The password is too short, the minimum is 8 characters", "warning")
if value.isalnum():
success = False
- flash('The password requires at least one non-alphanumeric character', 'warning')
+ flash(
+ "The password requires at least one non-alphanumeric character", "warning"
+ )
return success
+
def _email_check(value):
- """ Do a quick and dirty check on the email address """
- if len(value) < 5 or value.find('@') == -1 or value.find('.') == -1:
+ """Do a quick and dirty check on the email address"""
+ if len(value) < 5 or value.find("@") == -1 or value.find(".") == -1:
return False
return True
-class Pagination():
+class Pagination:
def __init__(self, page, per_page, total_count):
self.page = page
self.per_page = per_page
@@ -95,30 +103,40 @@ class Pagination():
def has_next(self):
return self.page < self.pages
- def iter_pages(self, left_edge=2, left_current=2,
- right_current=5, right_edge=2):
+ def iter_pages(self, left_edge=2, left_current=2, right_current=5, right_edge=2):
last = 0
for num in range(1, self.pages + 1):
- if num <= left_edge or \
- (num > self.page - left_current - 1 and \
- num < self.page + right_current) or \
- num > self.pages - right_edge:
+ if (
+ num <= left_edge
+ or (
+ num > self.page - left_current - 1
+ and num < self.page + right_current
+ )
+ or num > self.pages - right_edge
+ ):
if last + 1 != num:
yield None
yield num
last = num
+
def _get_analytics_by_interval(size, interval):
- """ Gets analytics data """
+ """Gets analytics data"""
array = []
now = datetime.date.today()
# yes, there's probably a way to do this in one query
for i in range(size):
- start = _get_datestr_from_dt(now - datetime.timedelta((i * interval) + interval - 1))
+ start = _get_datestr_from_dt(
+ now - datetime.timedelta((i * interval) + interval - 1)
+ )
end = _get_datestr_from_dt(now - datetime.timedelta((i * interval) - 1))
- stmt = text('SELECT fetch_cnt FROM analytics WHERE datestr BETWEEN :start AND :end')
- res = db.session.execute(stmt.bindparams(start=start, end=end)) # pylint: disable=no-member
+ stmt = text(
+ "SELECT fetch_cnt FROM analytics WHERE datestr BETWEEN :start AND :end"
+ )
+ res = db.session.execute( # pylint: disable=no-member
+ stmt.bindparams(start=start, end=end)
+ )
# add all these up
tmp = 0
@@ -127,8 +145,9 @@ def _get_analytics_by_interval(size, interval):
array.append(tmp)
return array
+
def _get_stats_by_interval(size, interval, msg):
- """ Gets stats data """
+ """Gets stats data"""
cnt = []
now = datetime.date.today()
@@ -136,39 +155,50 @@ def _get_stats_by_interval(size, interval, msg):
for i in range(size):
start = now - datetime.timedelta((i * interval) + interval - 1)
end = now - datetime.timedelta((i * interval) - 1)
- stmt = text('SELECT COUNT(*) FROM eventlog '
- 'WHERE message = :msg AND date_created BETWEEN :start AND :end')
- res = db.session.execute(stmt.bindparams(start=start, end=end, msg=msg)) # pylint: disable=no-member
+ stmt = text(
+ "SELECT COUNT(*) FROM eventlog "
+ "WHERE message = :msg AND date_created BETWEEN :start AND :end"
+ )
+ res = db.session.execute( # pylint: disable=no-member
+ stmt.bindparams(start=start, end=end, msg=msg)
+ )
cnt.append(res.fetchone()[0])
return cnt
-@app.route('/admin/graph_month')
+
+@app.route("/admin/graph_month")
@login_required
def admin_graph_month():
"""
Show nice graph graphs.
"""
data_fetch = _get_analytics_by_interval(30, 1)
- data_review = _get_stats_by_interval(30, 1, 'reviewed')
- return render_template('graph-month.html',
- labels=_get_chart_labels_days()[::-1],
- data_requests=data_fetch[::-1],
- data_submitted=data_review[::-1])
+ data_review = _get_stats_by_interval(30, 1, "reviewed")
+ return render_template(
+ "graph-month.html",
+ labels=_get_chart_labels_days()[::-1],
+ data_requests=data_fetch[::-1],
+ data_submitted=data_review[::-1],
+ )
+
-@app.route('/admin/graph_year')
+@app.route("/admin/graph_year")
@login_required
def admin_graph_year():
"""
Show nice graph graphs.
"""
data_fetch = _get_analytics_by_interval(12, 30)
- data_review = _get_stats_by_interval(12, 30, 'reviewed')
- return render_template('graph-year.html',
- labels=_get_chart_labels_months()[::-1],
- data_requests=data_fetch[::-1],
- data_submitted=data_review[::-1])
+ data_review = _get_stats_by_interval(12, 30, "reviewed")
+ return render_template(
+ "graph-year.html",
+ labels=_get_chart_labels_months()[::-1],
+ data_requests=data_fetch[::-1],
+ data_submitted=data_review[::-1],
+ )
-@app.route('/admin/stats')
+
+@app.route("/admin/stats")
@login_required
def admin_show_stats():
"""
@@ -176,95 +206,133 @@ def admin_show_stats():
"""
# security check
if not current_user.is_admin:
- flash('Unable to show stats as non-admin', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to show stats as non-admin", "error")
+ return redirect(url_for(".odrs_index"))
stats = {}
# get the total number of reviews
- rs = db.session.execute("SELECT COUNT(*) FROM reviews;") # pylint: disable=no-member
- stats['Active reviews'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(*) FROM reviews;"
+ )
+ stats["Active reviews"] = rs.fetchone()[0]
# unique reviewers
- rs = db.session.execute("SELECT COUNT(DISTINCT(user_id)) FROM reviews;") # pylint: disable=no-member
- stats['Unique reviewers'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(DISTINCT(user_id)) FROM reviews;"
+ )
+ stats["Unique reviewers"] = rs.fetchone()[0]
# total votes
- rs = db.session.execute("SELECT COUNT(*) FROM votes WHERE val = 1;") # pylint: disable=no-member
- stats['User upvotes'] = rs.fetchone()[0]
- rs = db.session.execute("SELECT COUNT(*) FROM votes WHERE val = -1;") # pylint: disable=no-member
- stats['User downvotes'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(*) FROM votes WHERE val = 1;"
+ )
+ stats["User upvotes"] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(*) FROM votes WHERE val = -1;"
+ )
+ stats["User downvotes"] = rs.fetchone()[0]
# unique voters
- rs = db.session.execute("SELECT COUNT(DISTINCT(user_id)) FROM votes;") # pylint: disable=no-member
- stats['Unique voters'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(DISTINCT(user_id)) FROM votes;"
+ )
+ stats["Unique voters"] = rs.fetchone()[0]
# unique languages
- rs = db.session.execute("SELECT COUNT(DISTINCT(locale)) FROM reviews;") # pylint: disable=no-member
- stats['Unique languages'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(DISTINCT(locale)) FROM reviews;"
+ )
+ stats["Unique languages"] = rs.fetchone()[0]
# unique distros
- rs = db.session.execute("SELECT COUNT(DISTINCT(distro)) FROM reviews;") # pylint: disable=no-member
- stats['Unique distros'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(DISTINCT(distro)) FROM reviews;"
+ )
+ stats["Unique distros"] = rs.fetchone()[0]
# unique apps
- rs = db.session.execute("SELECT COUNT(*) FROM components;") # pylint: disable=no-member
- stats['Unique apps reviewed'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(*) FROM components;"
+ )
+ stats["Unique apps reviewed"] = rs.fetchone()[0]
# unique distros
- rs = db.session.execute("SELECT COUNT(*) FROM reviews WHERE reported > 0;") # pylint: disable=no-member
- stats['Reported reviews'] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(*) FROM reviews WHERE reported > 0;"
+ )
+ stats["Reported reviews"] = rs.fetchone()[0]
# star reviews
for star in range(1, 6):
- rs = db.session.execute("SELECT COUNT(*) FROM reviews WHERE rating = {};".format(star * 20)) #
pylint: disable=no-member
- stats['%i star reviews' % star] = rs.fetchone()[0]
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT COUNT(*) FROM reviews WHERE rating = {};".format(star * 20)
+ )
+ stats["%i star reviews" % star] = rs.fetchone()[0]
# popularity view
- viewed = db.session.query(Component.app_id, Component.fetch_cnt).\
- filter(Component.app_id != None).\
- order_by(Component.fetch_cnt.desc()).\
- limit(50).all()
+ viewed = (
+ db.session.query(Component.app_id, Component.fetch_cnt)
+ .filter(Component.app_id != None)
+ .order_by(Component.fetch_cnt.desc())
+ .limit(50)
+ .all()
+ )
# popularity reviews
- submitted = db.session.query(Component.app_id, Component.review_cnt).\
- filter(Component.app_id != None).\
- order_by(Component.review_cnt.desc()).\
- limit(50).all()
+ submitted = (
+ db.session.query(Component.app_id, Component.review_cnt)
+ .filter(Component.app_id != None)
+ .order_by(Component.review_cnt.desc())
+ .limit(50)
+ .all()
+ )
# users
- users_awesome = db.session.query(User).\
- filter(User.karma != 0).\
- order_by(User.karma.desc()).\
- limit(10).all()
- users_haters = db.session.query(User).\
- filter(User.karma != 0).\
- order_by(User.karma.asc()).\
- limit(10).all()
+ users_awesome = (
+ db.session.query(User)
+ .filter(User.karma != 0)
+ .order_by(User.karma.desc())
+ .limit(10)
+ .all()
+ )
+ users_haters = (
+ db.session.query(User)
+ .filter(User.karma != 0)
+ .order_by(User.karma.asc())
+ .limit(10)
+ .all()
+ )
# distros
- rs = db.session.execute("SELECT DISTINCT(distro), COUNT(distro) AS total " # pylint: disable=no-member
- "FROM reviews GROUP BY distro ORDER BY total DESC "
- "LIMIT 8;")
+ rs = db.session.execute( # pylint: disable=no-member
+ "SELECT DISTINCT(distro), COUNT(distro) AS total "
+ "FROM reviews GROUP BY distro ORDER BY total DESC "
+ "LIMIT 8;"
+ )
labels = []
data = []
for s in rs:
name = s[0]
- for suffix in [' Linux', ' GNU/Linux', ' OS', ' Linux']:
+ for suffix in [" Linux", " GNU/Linux", " OS", " Linux"]:
if name.endswith(suffix):
- name = name[:-len(suffix)]
+ name = name[: -len(suffix)]
labels.append(name)
data.append(s[1])
- return render_template('stats.html',
- users_awesome=users_awesome,
- users_haters=users_haters,
- results_stats=stats,
- results_viewed=viewed,
- results_submitted=submitted,
- labels=labels, data=data)
+ return render_template(
+ "stats.html",
+ users_awesome=users_awesome,
+ users_haters=users_haters,
+ results_stats=stats,
+ results_viewed=viewed,
+ results_submitted=submitted,
+ labels=labels,
+ data=data,
+ )
+
-@app.route('/admin/review/<int:review_id>')
+@app.route("/admin/review/<int:review_id>")
@login_required
def admin_show_review(review_id):
"""
@@ -272,8 +340,8 @@ def admin_show_review(review_id):
"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
# has the user already voted
if current_user.user:
@@ -283,48 +351,50 @@ def admin_show_review(review_id):
# does the review contain any banned keywords
matched_taboos = review.matches_taboos(_get_taboos_for_locale(review.locale))
- return render_template('show.html', r=review,
- vote_exists=vote,
- matched_taboos=matched_taboos)
+ return render_template(
+ "show.html", r=review, vote_exists=vote, matched_taboos=matched_taboos
+ )
+
-@app.route('/admin/modify/<int:review_id>', methods=['POST'])
+@app.route("/admin/modify/<int:review_id>", methods=["POST"])
@login_required
def admin_modify(review_id):
- """ Change details about a review """
+ """Change details about a review"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
- if 'distro' in request.form:
- review.distro = request.form['distro']
- if 'locale' in request.form:
- review.locale = request.form['locale']
- if 'user_display' in request.form:
- if len(request.form['user_display']) == 0:
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
+ if "distro" in request.form:
+ review.distro = request.form["distro"]
+ if "locale" in request.form:
+ review.locale = request.form["locale"]
+ if "user_display" in request.form:
+ if len(request.form["user_display"]) == 0:
review.user_display = None
else:
- review.user_display = request.form['user_display']
- if 'description' in request.form:
- review.description = request.form['description']
- if 'summary' in request.form:
- review.summary = request.form['summary']
- if 'version' in request.form:
- review.version = request.form['version']
+ review.user_display = request.form["user_display"]
+ if "description" in request.form:
+ review.description = request.form["description"]
+ if "summary" in request.form:
+ review.summary = request.form["summary"]
+ if "version" in request.form:
+ review.version = request.form["version"]
db.session.commit()
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ return redirect(url_for(".admin_show_review", review_id=review_id))
-@app.route('/admin/user_ban/<user_hash>')
+
+@app.route("/admin/user_ban/<user_hash>")
@login_required
def admin_user_ban(user_hash):
- """ Change details about a review """
+ """Change details about a review"""
# security check
if not current_user.is_admin:
- flash('Unable to ban user as non-admin', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to ban user as non-admin", "error")
+ return redirect(url_for(".odrs_index"))
user = db.session.query(User).filter(User.user_hash == user_hash).first()
if not user:
- flash('No user with that user_hash')
- return redirect(url_for('.odrs_index'))
+ flash("No user with that user_hash")
+ return redirect(url_for(".odrs_index"))
user.is_banned = True
# delete any of the users reviews
@@ -332,84 +402,91 @@ def admin_user_ban(user_hash):
for review in user.reviews:
db.session.delete(review)
db.session.commit()
- flash('Banned user and deleted {} reviews'.format(nr_delete))
- return redirect(url_for('.odrs_show_reported'))
+ flash("Banned user and deleted {} reviews".format(nr_delete))
+ return redirect(url_for(".odrs_show_reported"))
+
-@app.route('/admin/unreport/<int:review_id>')
+@app.route("/admin/unreport/<int:review_id>")
@login_required
def admin_unreport(review_id):
- """ Unreport a perfectly valid review """
+ """Unreport a perfectly valid review"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
review.reported = 0
db.session.commit()
- flash('Review unreported')
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ flash("Review unreported")
+ return redirect(url_for(".admin_show_review", review_id=review_id))
-@app.route('/admin/unremove/<int:review_id>')
+
+@app.route("/admin/unremove/<int:review_id>")
@login_required
def admin_unremove(review_id):
- """ Unreport a perfectly valid review """
+ """Unreport a perfectly valid review"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
review.date_deleted = None
db.session.commit()
- flash('Review unremoved')
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ flash("Review unremoved")
+ return redirect(url_for(".admin_show_review", review_id=review_id))
+
-@app.route('/admin/englishify/<int:review_id>')
+@app.route("/admin/englishify/<int:review_id>")
@login_required
def admin_englishify(review_id):
- """ Marks a review as writen in English """
+ """Marks a review as writen in English"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
- parts = review.locale.split('_')
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
+ parts = review.locale.split("_")
if len(parts) == 1:
- review.locale = 'en'
+ review.locale = "en"
else:
- review.locale = 'en_' + parts[1]
+ review.locale = "en_" + parts[1]
db.session.commit()
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ return redirect(url_for(".admin_show_review", review_id=review_id))
-@app.route('/admin/anonify/<int:review_id>')
+
+@app.route("/admin/anonify/<int:review_id>")
@login_required
def admin_anonify(review_id):
- """ Removes the username from the review """
+ """Removes the username from the review"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
review.user_display = None
db.session.commit()
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ return redirect(url_for(".admin_show_review", review_id=review_id))
+
-@app.route('/admin/delete/<review_id>/force')
+@app.route("/admin/delete/<review_id>/force")
@login_required
def admin_delete_force(review_id):
- """ Delete a review """
+ """Delete a review"""
review = db.session.query(Review).filter(Review.review_id == review_id).first()
if not review:
- flash('No review with that ID')
- return redirect(url_for('.odrs_index'))
+ flash("No review with that ID")
+ return redirect(url_for(".odrs_index"))
db.session.delete(review)
db.session.commit()
- flash('Deleted review')
- return redirect(url_for('.odrs_show_reported'))
+ flash("Deleted review")
+ return redirect(url_for(".odrs_show_reported"))
-@app.route('/admin/delete/<review_id>')
+
+@app.route("/admin/delete/<review_id>")
@login_required
def admin_delete(review_id):
- """ Ask for confirmation to delete a review """
- return render_template('delete.html', review_id=review_id)
+ """Ask for confirmation to delete a review"""
+ return render_template("delete.html", review_id=review_id)
+
-@app.route('/admin/show/all')
-@app.route('/admin/show/all/page/<int:page>')
+@app.route("/admin/show/all")
+@app.route("/admin/show/all/page/<int:page>")
@login_required
def admin_show_all(page=1):
"""
@@ -422,48 +499,55 @@ def admin_show_all(page=1):
reviews_per_page = 20
pagination = Pagination(page, reviews_per_page, len(reviews))
- reviews = reviews[(page-1) * reviews_per_page:page * reviews_per_page]
- return render_template('show-all.html',
- pagination=pagination,
- reviews=reviews)
+ reviews = reviews[(page - 1) * reviews_per_page : page * reviews_per_page]
+ return render_template("show-all.html", pagination=pagination, reviews=reviews)
+
def _review_filter_keys(keys):
cond = []
for key in keys:
- cond.append(Review.user_display.like('%{}%'.format(key)))
- cond.append(Review.summary.like('%{}%'.format(key)))
- cond.append(Review.description.like('%{}%'.format(key)))
+ cond.append(Review.user_display.like("%{}%".format(key)))
+ cond.append(Review.summary.like("%{}%".format(key)))
+ cond.append(Review.description.like("%{}%".format(key)))
return or_(*cond)
-@app.route('/admin/search')
-@app.route('/admin/search/<int:max_results>')
+
+@app.route("/admin/search")
+@app.route("/admin/search/<int:max_results>")
def admin_search(max_results=19):
# no search results
- if 'value' not in request.args:
- return render_template('search.html')
-
- keys = request.args['value'].split(' ')
- reviews = db.session.query(Review).\
- filter(_review_filter_keys(keys)).\
- order_by(Review.date_created.desc()).\
- limit(max_results).all()
- return render_template('show-all.html',
- reviews=reviews)
-
-@app.route('/admin/show/reported')
-@app.route('/admin/show/reported/<int:limit>')
+ if "value" not in request.args:
+ return render_template("search.html")
+
+ keys = request.args["value"].split(" ")
+ reviews = (
+ db.session.query(Review)
+ .filter(_review_filter_keys(keys))
+ .order_by(Review.date_created.desc())
+ .limit(max_results)
+ .all()
+ )
+ return render_template("show-all.html", reviews=reviews)
+
+
+@app.route("/admin/show/reported")
+@app.route("/admin/show/reported/<int:limit>")
@login_required
def odrs_show_reported(limit=1):
"""
Return all the reported reviews on the server as HTML.
"""
- reviews = db.session.query(Review).\
- filter(Review.reported >= limit).\
- order_by(Review.date_created.desc()).all()
- return render_template('show-all.html', reviews=reviews)
+ reviews = (
+ db.session.query(Review)
+ .filter(Review.reported >= limit)
+ .order_by(Review.date_created.desc())
+ .all()
+ )
+ return render_template("show-all.html", reviews=reviews)
+
-@app.route('/admin/show/user/<user_hash>')
+@app.route("/admin/show/user/<user_hash>")
@login_required
def admin_show_user(user_hash):
"""
@@ -471,32 +555,38 @@ def admin_show_user(user_hash):
"""
user = db.session.query(User).filter(User.user_hash == user_hash).first()
if not user:
- flash('No user with that user_hash')
- return redirect(url_for('.admin_show_all'))
+ flash("No user with that user_hash")
+ return redirect(url_for(".admin_show_all"))
reviews = db.session.query(Review).filter(Review.user_id == user.user_id).all()
- return render_template('show-all.html', reviews=reviews)
+ return render_template("show-all.html", reviews=reviews)
-@app.route('/admin/show/app/<app_id>')
+
+@app.route("/admin/show/app/<app_id>")
@login_required
def admin_show_app(app_id):
"""
Return all the reviews from a user on the server as HTML.
"""
- reviews = db.session.query(Review).\
- join(Component).\
- filter(Component.app_id == app_id).all()
- return render_template('show-all.html', reviews=reviews)
+ reviews = (
+ db.session.query(Review)
+ .join(Component)
+ .filter(Component.app_id == app_id)
+ .all()
+ )
+ return render_template("show-all.html", reviews=reviews)
+
-@app.route('/admin/show/lang/<locale>')
+@app.route("/admin/show/lang/<locale>")
@login_required
def admin_show_lang(locale):
"""
Return all the reviews from a user on the server as HTML.
"""
reviews = db.session.query(Review).filter(Review.locale == locale).all()
- return render_template('show-all.html', reviews=reviews)
+ return render_template("show-all.html", reviews=reviews)
-@app.route('/admin/moderators/all')
+
+@app.route("/admin/moderators/all")
@login_required
def admin_moderator_show_all():
"""
@@ -504,96 +594,111 @@ def admin_moderator_show_all():
"""
# security check
if not current_user.is_admin:
- flash('Unable to show all moderators', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to show all moderators", "error")
+ return redirect(url_for(".odrs_index"))
mods = db.session.query(Moderator).all()
- return render_template('mods.html', mods=mods)
+ return render_template("mods.html", mods=mods)
+
-@app.route('/admin/moderator/add', methods=['GET', 'POST'])
+@app.route("/admin/moderator/add", methods=["GET", "POST"])
@login_required
def admin_moderator_add():
- """ Add a moderator [ADMIN ONLY] """
+ """Add a moderator [ADMIN ONLY]"""
# only accept form data
- if request.method != 'POST':
- return redirect(url_for('.profile'))
+ if request.method != "POST":
+ return redirect(url_for(".profile"))
# security check
if not current_user.is_admin:
- flash('Unable to add moderator as non-admin', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to add moderator as non-admin", "error")
+ return redirect(url_for(".odrs_index"))
- for key in ['username_new', 'password_new', 'display_name']:
+ for key in ["username_new", "password_new", "display_name"]:
if not key in request.form:
- flash('Unable to add moderator as {} missing'.format(key), 'error')
- return redirect(url_for('.odrs_index'))
- if db.session.query(Moderator).\
- filter(Moderator.username == request.form['username_new']).first():
- flash('Already a entry with that username', 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("Unable to add moderator as {} missing".format(key), "error")
+ return redirect(url_for(".odrs_index"))
+ if (
+ db.session.query(Moderator)
+ .filter(Moderator.username == request.form["username_new"])
+ .first()
+ ):
+ flash("Already a entry with that username", "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
# verify password
- password = request.form['password_new']
+ password = request.form["password_new"]
if not _password_check(password):
- return redirect(url_for('.admin_moderator_show_all'))
+ return redirect(url_for(".admin_moderator_show_all"))
# verify username
- username_new = request.form['username_new']
+ username_new = request.form["username_new"]
if len(username_new) < 3:
- flash('Username invalid', 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("Username invalid", "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
if not _email_check(username_new):
- flash('Invalid email address', 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("Invalid email address", "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
# verify name
- display_name = request.form['display_name']
+ display_name = request.form["display_name"]
if len(display_name) < 3:
- flash('Name invalid', 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("Name invalid", "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
# verify username
db.session.add(Moderator(username_new, password, display_name))
db.session.commit()
- flash('Added user')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("Added user")
+ return redirect(url_for(".admin_moderator_show_all"))
-@app.route('/admin/moderator/<int:moderator_id>/admin')
+
+@app.route("/admin/moderator/<int:moderator_id>/admin")
@login_required
def odrs_moderator_show(moderator_id):
"""
Shows an admin panel for a moderator
"""
if moderator_id != current_user.moderator_id and not current_user.is_admin:
- flash('Unable to show moderator information', 'error')
- return redirect(url_for('.odrs_index'))
- mod = db.session.query(Moderator).filter(Moderator.moderator_id == moderator_id).first()
+ flash("Unable to show moderator information", "error")
+ return redirect(url_for(".odrs_index"))
+ mod = (
+ db.session.query(Moderator)
+ .filter(Moderator.moderator_id == moderator_id)
+ .first()
+ )
if not mod:
- flash("No entry with moderator ID {}".format(moderator_id), 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
- return render_template('modadmin.html', u=mod)
+ flash("No entry with moderator ID {}".format(moderator_id), "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
+ return render_template("modadmin.html", u=mod)
+
-@app.route('/admin/moderator/<int:moderator_id>/delete')
+@app.route("/admin/moderator/<int:moderator_id>/delete")
@login_required
def admin_moderate_delete(moderator_id):
- """ Delete a moderator """
+ """Delete a moderator"""
# security check
if not current_user.is_admin:
- flash('Unable to delete moderator as not admin', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to delete moderator as not admin", "error")
+ return redirect(url_for(".odrs_index"))
# check whether exists in database
- mod = db.session.query(Moderator).filter(Moderator.moderator_id == moderator_id).first()
+ mod = (
+ db.session.query(Moderator)
+ .filter(Moderator.moderator_id == moderator_id)
+ .first()
+ )
if not mod:
- flash("No entry with moderator ID {}".format(moderator_id), 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("No entry with moderator ID {}".format(moderator_id), "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
db.session.delete(mod)
db.session.commit()
- flash('Deleted user')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("Deleted user")
+ return redirect(url_for(".admin_moderator_show_all"))
+
-@app.route('/admin/taboo/all')
+@app.route("/admin/taboo/all")
@login_required
def admin_taboo_show_all():
"""
@@ -601,67 +706,80 @@ def admin_taboo_show_all():
"""
# security check
if not current_user.is_admin:
- flash('Unable to show all taboos', 'error')
- return redirect(url_for('.odrs_index'))
- taboos = db.session.query(Taboo).\
- order_by(Taboo.locale.asc()).\
- order_by(Taboo.value.asc()).all()
- return render_template('taboos.html', taboos=taboos)
-
-@app.route('/admin/taboo/add', methods=['GET', 'POST'])
+ flash("Unable to show all taboos", "error")
+ return redirect(url_for(".odrs_index"))
+ taboos = (
+ db.session.query(Taboo)
+ .order_by(Taboo.locale.asc())
+ .order_by(Taboo.value.asc())
+ .all()
+ )
+ return render_template("taboos.html", taboos=taboos)
+
+
+@app.route("/admin/taboo/add", methods=["GET", "POST"])
@login_required
def admin_taboo_add():
- """ Add a taboo [ADMIN ONLY] """
+ """Add a taboo [ADMIN ONLY]"""
# only accept form data
- if request.method != 'POST':
- return redirect(url_for('.admin_taboo_show_all'))
+ if request.method != "POST":
+ return redirect(url_for(".admin_taboo_show_all"))
# security check
if not current_user.is_admin:
- flash('Unable to add taboo as non-admin', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to add taboo as non-admin", "error")
+ return redirect(url_for(".odrs_index"))
- for key in ['locale', 'value', 'description', 'severity']:
+ for key in ["locale", "value", "description", "severity"]:
if not key in request.form:
- flash('Unable to add taboo as {} missing'.format(key), 'error')
- return redirect(url_for('.odrs_index'))
- if db.session.query(Taboo).\
- filter(Taboo.locale == request.form['locale']).\
- filter(Taboo.value == request.form['value']).first():
- flash('Already added that taboo', 'warning')
- return redirect(url_for('.admin_taboo_show_all'))
+ flash("Unable to add taboo as {} missing".format(key), "error")
+ return redirect(url_for(".odrs_index"))
+ if (
+ db.session.query(Taboo)
+ .filter(Taboo.locale == request.form["locale"])
+ .filter(Taboo.value == request.form["value"])
+ .first()
+ ):
+ flash("Already added that taboo", "warning")
+ return redirect(url_for(".admin_taboo_show_all"))
# verify username
- db.session.add(Taboo(request.form['locale'],
- request.form['value'],
- request.form['description'],
- int(request.form['severity'])))
+ db.session.add(
+ Taboo(
+ request.form["locale"],
+ request.form["value"],
+ request.form["description"],
+ int(request.form["severity"]),
+ )
+ )
db.session.commit()
- flash('Added taboo')
- return redirect(url_for('.admin_taboo_show_all'))
+ flash("Added taboo")
+ return redirect(url_for(".admin_taboo_show_all"))
-@app.route('/admin/taboo/<int:taboo_id>/delete')
+
+@app.route("/admin/taboo/<int:taboo_id>/delete")
@login_required
def admin_taboo_delete(taboo_id):
- """ Delete an taboo """
+ """Delete an taboo"""
# security check
if not current_user.is_admin:
- flash('Unable to delete taboo as not admin', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to delete taboo as not admin", "error")
+ return redirect(url_for(".odrs_index"))
# check whether exists in database
taboo = db.session.query(Taboo).filter(Taboo.taboo_id == taboo_id).first()
if not taboo:
- flash("No taboo with ID {}".format(taboo_id), 'warning')
- return redirect(url_for('.admin_taboo_show_all'))
+ flash("No taboo with ID {}".format(taboo_id), "warning")
+ return redirect(url_for(".admin_taboo_show_all"))
db.session.delete(taboo)
db.session.commit()
- flash('Deleted taboo')
- return redirect(url_for('.admin_taboo_show_all'))
+ flash("Deleted taboo")
+ return redirect(url_for(".admin_taboo_show_all"))
+
-@app.route('/admin/component/all')
+@app.route("/admin/component/all")
@login_required
def admin_component_show_all():
"""
@@ -669,14 +787,18 @@ def admin_component_show_all():
"""
# security check
if not current_user.is_admin:
- flash('Unable to show all components', 'error')
- return redirect(url_for('.odrs_index'))
- components = db.session.query(Component).\
- order_by(Component.app_id.asc()).\
- order_by(Component.review_cnt.asc()).all()
- return render_template('components.html', components=components)
-
-@app.route('/admin/component/join/<component_id_parent>/<component_id_child>')
+ flash("Unable to show all components", "error")
+ return redirect(url_for(".odrs_index"))
+ components = (
+ db.session.query(Component)
+ .order_by(Component.app_id.asc())
+ .order_by(Component.review_cnt.asc())
+ .all()
+ )
+ return render_template("components.html", components=components)
+
+
+@app.route("/admin/component/join/<component_id_parent>/<component_id_child>")
@login_required
def admin_component_join(component_id_parent, component_id_child):
"""
@@ -684,62 +806,79 @@ def admin_component_join(component_id_parent, component_id_child):
"""
# security check
if not current_user.is_admin:
- flash('Unable to join components', 'error')
- return redirect(url_for('.odrs_index'))
- parent = db.session.query(Component).filter(Component.app_id == component_id_parent).first()
+ flash("Unable to join components", "error")
+ return redirect(url_for(".odrs_index"))
+ parent = (
+ db.session.query(Component)
+ .filter(Component.app_id == component_id_parent)
+ .first()
+ )
if not parent:
- flash('No parent component found', 'warning')
- return redirect(url_for('.admin_component_show_all'))
- child = db.session.query(Component).filter(Component.app_id == component_id_child).first()
+ flash("No parent component found", "warning")
+ return redirect(url_for(".admin_component_show_all"))
+ child = (
+ db.session.query(Component)
+ .filter(Component.app_id == component_id_child)
+ .first()
+ )
if not child:
- flash('No child component found', 'warning')
- return redirect(url_for('.admin_component_show_all'))
+ flash("No child component found", "warning")
+ return redirect(url_for(".admin_component_show_all"))
if parent.component_id == child.component_id:
- flash('Parent and child components were the same', 'warning')
- return redirect(url_for('.admin_component_show_all'))
+ flash("Parent and child components were the same", "warning")
+ return redirect(url_for(".admin_component_show_all"))
if parent.component_id == child.component_id_parent:
- flash('Parent and child already set up', 'warning')
- return redirect(url_for('.admin_component_show_all'))
+ flash("Parent and child already set up", "warning")
+ return redirect(url_for(".admin_component_show_all"))
# return best message
adopted = parent.adopt(child)
db.session.commit()
if adopted:
- flash('Joined components, adopting {} additional components'.format(adopted), 'info')
+ flash(
+ "Joined components, adopting {} additional components".format(adopted),
+ "info",
+ )
else:
- flash('Joined components', 'info')
- return redirect(url_for('.admin_component_show_all'))
+ flash("Joined components", "info")
+ return redirect(url_for(".admin_component_show_all"))
-@app.route('/admin/component/join', methods=['POST'])
+@app.route("/admin/component/join", methods=["POST"])
@login_required
def admin_component_join2():
- """ Change details about the any user """
+ """Change details about the any user"""
# security check
if not current_user.is_admin:
- flash('Unable to join components', 'error')
- return redirect(url_for('.odrs_index'))
+ flash("Unable to join components", "error")
+ return redirect(url_for(".odrs_index"))
# set each thing in turn
parent = None
children = []
for key in request.form:
- if key == 'parent':
- parent = db.session.query(Component).\
- filter(Component.app_id == request.form[key]).first()
- if key == 'child':
+ if key == "parent":
+ parent = (
+ db.session.query(Component)
+ .filter(Component.app_id == request.form[key])
+ .first()
+ )
+ if key == "child":
for component_id in request.form.getlist(key):
- child = db.session.query(Component).\
- filter(Component.app_id == component_id).first()
+ child = (
+ db.session.query(Component)
+ .filter(Component.app_id == component_id)
+ .first()
+ )
if child:
children.append(child)
if not parent:
- flash('No parent component found', 'warning')
- return redirect(url_for('.admin_component_show_all'))
+ flash("No parent component found", "warning")
+ return redirect(url_for(".admin_component_show_all"))
if not children:
- flash('No child components found', 'warning')
- return redirect(url_for('.admin_component_show_all'))
+ flash("No child components found", "warning")
+ return redirect(url_for(".admin_component_show_all"))
# adopt each child
adopted = 0
@@ -750,91 +889,101 @@ def admin_component_join2():
adopted += parent.adopt(child)
db.session.commit()
if adopted:
- flash('Joined {} components, '
- 'adopting {} additional components'.format(len(children),
- adopted), 'info')
+ flash(
+ "Joined {} components, "
+ "adopting {} additional components".format(len(children), adopted),
+ "info",
+ )
else:
- flash('Joined {} components'.format(len(children)), 'info')
- return redirect(url_for('.admin_component_show_all'))
+ flash("Joined {} components".format(len(children)), "info")
+ return redirect(url_for(".admin_component_show_all"))
-@app.route('/admin/component/delete/<int:component_id>')
+
+@app.route("/admin/component/delete/<int:component_id>")
@login_required
def admin_component_delete(component_id):
"""
Delete component, and any reviews.
"""
if not current_user.is_admin:
- flash('Unable to delete component', 'error')
- return redirect(url_for('.odrs_index'))
- component = db.session.query(Component).filter(Component.component_id == component_id).first()
+ flash("Unable to delete component", "error")
+ return redirect(url_for(".odrs_index"))
+ component = (
+ db.session.query(Component)
+ .filter(Component.component_id == component_id)
+ .first()
+ )
if not component:
- flash('Unable to find component', 'error')
- return redirect(url_for('.admin_component_show_all'))
+ flash("Unable to find component", "error")
+ return redirect(url_for(".admin_component_show_all"))
- flash('Deleted component with {} reviews'.format(len(component.reviews)), 'info')
+ flash("Deleted component with {} reviews".format(len(component.reviews)), "info")
db.session.delete(component)
db.session.commit()
- return redirect(url_for('.admin_component_show_all'))
+ return redirect(url_for(".admin_component_show_all"))
+
-@app.route('/admin/vote/<int:review_id>/<val_str>')
+@app.route("/admin/vote/<int:review_id>/<val_str>")
@login_required
def admin_vote(review_id, val_str):
- """ Up or downvote an existing review by @val karma points """
+ """Up or downvote an existing review by @val karma points"""
if not current_user.user:
- flash('No user for moderator')
- return redirect(url_for('.admin_show_review', review_id=review_id))
- if val_str == 'up':
+ flash("No user for moderator")
+ return redirect(url_for(".admin_show_review", review_id=review_id))
+ if val_str == "up":
val = 1
- elif val_str == 'down':
+ elif val_str == "down":
val = -1
- elif val_str == 'meh':
+ elif val_str == "meh":
val = 0
else:
- flash('Invalid vote value')
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ flash("Invalid vote value")
+ return redirect(url_for(".admin_show_review", review_id=review_id))
# the user already has a review
if _vote_exists(review_id, current_user.user_id):
- flash('already voted on this app')
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ flash("already voted on this app")
+ return redirect(url_for(".admin_show_review", review_id=review_id))
current_user.user.karma += val
db.session.add(Vote(current_user.user_id, val, review_id=review_id))
db.session.commit()
- flash('Recorded vote')
- return redirect(url_for('.admin_show_review', review_id=review_id))
+ flash("Recorded vote")
+ return redirect(url_for(".admin_show_review", review_id=review_id))
-@app.route('/admin/moderator/<int:moderator_id>/modify_by_admin', methods=['POST'])
+
+@app.route("/admin/moderator/<int:moderator_id>/modify_by_admin", methods=["POST"])
@login_required
def admin_user_modify_by_admin(moderator_id):
- """ Change details about the any user """
+ """Change details about the any user"""
# security check
if moderator_id != current_user.moderator_id and not current_user.is_admin:
- flash('Unable to modify user as non-admin', 'error')
- return redirect(url_for('.odrs_index'))
-
- mod = db.session.query(Moderator).filter(Moderator.moderator_id == moderator_id).first()
+ flash("Unable to modify user as non-admin", "error")
+ return redirect(url_for(".odrs_index"))
+
+ mod = (
+ db.session.query(Moderator)
+ .filter(Moderator.moderator_id == moderator_id)
+ .first()
+ )
if not mod:
- flash('moderator_id invalid', 'warning')
- return redirect(url_for('.admin_moderator_show_all'))
+ flash("moderator_id invalid", "warning")
+ return redirect(url_for(".admin_moderator_show_all"))
# set each thing in turn
- mod.is_enabled = 'is_enabled' in request.form
- mod.is_admin = 'is_admin' in request.form
- for key in ['display_name',
- 'password',
- 'user_hash',
- 'locales']:
+ mod.is_enabled = "is_enabled" in request.form
+ mod.is_admin = "is_admin" in request.form
+ for key in ["display_name", "password", "user_hash", "locales"]:
# unchecked checkbuttons are not included in the form data
if key not in request.form:
continue
val = request.form[key]
# don't set the optional password
- if key == 'password' and len(val) == 0:
+ if key == "password" and len(val) == 0:
continue
setattr(mod, key, val)
db.session.commit()
- flash('Updated profile')
- return redirect(url_for('.odrs_moderator_show', moderator_id=moderator_id))
+ flash("Updated profile")
+ return redirect(url_for(".odrs_moderator_show", moderator_id=moderator_id))
diff --git a/app_data/odrs/views_api.py b/app_data/odrs/views_api.py
index 1e3a8cf..7a5f27b 100644
--- a/app_data/odrs/views_api.py
+++ b/app_data/odrs/views_api.py
@@ -20,30 +20,46 @@ from odrs import app, db, csrf
from .models import Review, User, Vote, Analytic, Component
from .models import _vote_exists
-from .util import json_success, json_error, _locale_is_compatible, _eventlog_add, _get_user_key,
_get_datestr_from_dt
-from .util import _sanitised_version, _sanitised_summary, _sanitised_description, _get_rating_for_component
+from .util import (
+ json_success,
+ json_error,
+ _locale_is_compatible,
+ _eventlog_add,
+ _get_user_key,
+ _get_datestr_from_dt,
+)
+from .util import (
+ _sanitised_version,
+ _sanitised_summary,
+ _sanitised_description,
+ _get_rating_for_component,
+)
from .util import _get_taboos_for_locale
ODRS_REPORTED_CNT = 2
+
def _get_client_address():
- """ Gets user IP address """
- if request.headers.getlist('X-Forwarded-For'):
- return request.headers.getlist('X-Forwarded-For')[0]
+ """Gets user IP address"""
+ if request.headers.getlist("X-Forwarded-For"):
+ return request.headers.getlist("X-Forwarded-For")[0]
return request.remote_addr
+
def _wilson(ku, kd):
# algorithm from http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
wilson = 0
if ku > 0 or kd > 0:
- wilson = ((ku + 1.9208) / (ku + kd) -
- 1.96 * math.sqrt((ku * kd) / (ku + kd) + 0.9604) /
- (ku + kd)) / (1 + 3.8416 / (ku + kd))
+ wilson = (
+ (ku + 1.9208) / (ku + kd)
+ - 1.96 * math.sqrt((ku * kd) / (ku + kd) + 0.9604) / (ku + kd)
+ ) / (1 + 3.8416 / (ku + kd))
wilson *= 100
return int(wilson)
+
def _get_review_score(review, item):
- """ Gets a review score given certain parameters """
+ """Gets a review score given certain parameters"""
ku = review.karma_up
kd = review.karma_down
@@ -56,123 +72,146 @@ def _get_review_score(review, item):
# For every year that has passed and for a mismatched version or distro, we
# add a penalty. Penalties will reduce the final score.
penalties = months_old // 12
- if review.version != item['version']:
+ if review.version != item["version"]:
penalties += 1
- if review.distro != item['distro']:
+ if review.distro != item["distro"]:
penalties += 1
w = _wilson(ku, kd)
return max(0, w - penalties * 10)
+
def _check_str(val):
- """ Return with success if the summary and description """
- if val.find('<') != -1:
+ """Return with success if the summary and description"""
+ if val.find("<") != -1:
return False
- if val.find('<') != -1:
+ if val.find("<") != -1:
return False
return True
-@app.route('/1.0/reviews/api/submit', methods=['POST'])
+
+@app.route("/1.0/reviews/api/submit", methods=["POST"])
@csrf.exempt
def api_submit():
"""
Submits a new review.
"""
try:
- request_item = json.loads(request.data.decode('utf8'))
+ request_item = json.loads(request.data.decode("utf8"))
except ValueError as e:
return json_error(str(e))
- required_fields = ['app_id', 'locale', 'summary', 'description',
- 'user_hash', 'version', 'distro', 'rating',
- 'user_display']
+ required_fields = [
+ "app_id",
+ "locale",
+ "summary",
+ "description",
+ "user_hash",
+ "version",
+ "distro",
+ "rating",
+ "user_display",
+ ]
for key in required_fields:
if not key in request_item:
- return json_error('invalid data, expected %s' % key)
+ return json_error("invalid data, expected %s" % key)
if not request_item[key]:
- return json_error('missing data, expected %s' % key)
+ return json_error("missing data, expected %s" % key)
# check format
- if not len(request_item['user_hash']) == 40:
- return json_error('the user_hash is invalid')
+ if not len(request_item["user_hash"]) == 40:
+ return json_error("the user_hash is invalid")
# check fields for markup and length
- if len(request_item['summary']) > 70:
- return json_error('summary is too long')
- if len(request_item['description']) > 3000:
- return json_error('description is too long')
- for key in ['summary', 'description']:
+ if len(request_item["summary"]) > 70:
+ return json_error("summary is too long")
+ if len(request_item["description"]) > 3000:
+ return json_error("description is too long")
+ for key in ["summary", "description"]:
if not _check_str(request_item[key]):
- return json_error('%s is not a valid string' % key)
+ return json_error("%s is not a valid string" % key)
# check user has not been banned
- user = db.session.query(User).filter(User.user_hash == request_item['user_hash']).first()
+ user = (
+ db.session.query(User)
+ .filter(User.user_hash == request_item["user_hash"])
+ .first()
+ )
if user:
if user.is_banned:
- return json_error('account has been disabled due to abuse')
+ return json_error("account has been disabled due to abuse")
else:
- user = User(request_item['user_hash'])
+ user = User(request_item["user_hash"])
db.session.add(user)
# user has already reviewed
- if db.session.query(Review).\
- join(Component).\
- filter(Component.app_id == request_item['app_id']).\
- filter(Review.user_id == user.user_id).first():
- _eventlog_add(_get_client_address(),
- user.user_id,
- request_item['app_id'],
- 'already reviewed')
- return json_error('already reviewed this app')
+ if (
+ db.session.query(Review)
+ .join(Component)
+ .filter(Component.app_id == request_item["app_id"])
+ .filter(Review.user_id == user.user_id)
+ .first()
+ ):
+ _eventlog_add(
+ _get_client_address(),
+ user.user_id,
+ request_item["app_id"],
+ "already reviewed",
+ )
+ return json_error("already reviewed this app")
# component definately exists now!
- component = db.session.query(Component).filter(Component.app_id == request_item['app_id']).first()
+ component = (
+ db.session.query(Component)
+ .filter(Component.app_id == request_item["app_id"])
+ .first()
+ )
if component:
component.review_cnt += 1
else:
- component = Component(request_item['app_id'])
+ component = Component(request_item["app_id"])
db.session.add(component)
db.session.commit()
# create new
review = Review()
- review.locale = request_item['locale']
- review.summary = _sanitised_summary(request_item['summary'])
+ review.locale = request_item["locale"]
+ review.summary = _sanitised_summary(request_item["summary"])
if len(review.summary) < 2:
- return json_error('summary is too short')
- review.description = _sanitised_description(request_item['description'])
+ return json_error("summary is too short")
+ review.description = _sanitised_description(request_item["description"])
if len(review.description) < 2:
- return json_error('description is too short')
+ return json_error("description is too short")
review.user_id = user.user_id
- review.version = _sanitised_version(request_item['version'])
- review.distro = request_item['distro']
- review.rating = request_item['rating']
+ review.version = _sanitised_version(request_item["version"])
+ review.distro = request_item["distro"]
+ review.rating = request_item["rating"]
review.user_addr = _get_client_address()
review.component_id = component.component_id
# check if valid
- user_display_ignore = ['root',
- 'Administrator',
- 'Live System User',
- 'user',
- 'Unknown']
- if request_item['user_display'] not in user_display_ignore:
- review.user_display = request_item['user_display']
+ user_display_ignore = [
+ "root",
+ "Administrator",
+ "Live System User",
+ "user",
+ "Unknown",
+ ]
+ if request_item["user_display"] not in user_display_ignore:
+ review.user_display = request_item["user_display"]
# contains taboos
if review.matches_taboos(_get_taboos_for_locale(review.locale)):
review.reported = 5
# log and add
- _eventlog_add(_get_client_address(),
- review.user_id,
- component.app_id,
- 'reviewed')
+ _eventlog_add(_get_client_address(), review.user_id, component.app_id, "reviewed")
db.session.add(review)
db.session.commit()
return json_success()
-@app.route('/1.0/reviews/api/app/<app_id>/<user_hash>')
-@app.route('/1.0/reviews/api/app/<app_id>')
+
+@app.route("/1.0/reviews/api/app/<app_id>/<user_hash>")
+@app.route("/1.0/reviews/api/app/<app_id>")
def api_show_app(app_id, user_hash=None):
"""
Return details about an application.
@@ -180,73 +219,86 @@ def api_show_app(app_id, user_hash=None):
reviews = []
component = db.session.query(Component).filter(Component.app_id == app_id).first()
if component:
- reviews = db.session.query(Review).\
- join(Component).\
- filter(Component.app_id.in_(component.app_ids)).\
- filter(Review.reported < ODRS_REPORTED_CNT).\
- order_by(Review.date_created.desc()).all()
+ reviews = (
+ db.session.query(Review)
+ .join(Component)
+ .filter(Component.app_id.in_(component.app_ids))
+ .filter(Review.reported < ODRS_REPORTED_CNT)
+ .order_by(Review.date_created.desc())
+ .all()
+ )
items = [review.asdict(user_hash) for review in reviews]
- dat = json.dumps(items, sort_keys=True, indent=4, separators=(',', ': '))
- return Response(response=dat,
- status=200, \
- mimetype='application/json')
+ dat = json.dumps(items, sort_keys=True, indent=4, separators=(",", ": "))
+ return Response(response=dat, status=200, mimetype="application/json")
+
-@app.route('/1.0/reviews/api/fetch', methods=['POST'])
+@app.route("/1.0/reviews/api/fetch", methods=["POST"])
@csrf.exempt
def api_fetch():
"""
Return details about an application.
"""
try:
- request_item = json.loads(request.data.decode('utf8'))
+ request_item = json.loads(request.data.decode("utf8"))
except ValueError as e:
return json_error(str(e))
- for key in ['app_id', 'user_hash', 'locale', 'distro', 'limit', 'version']:
+ for key in ["app_id", "user_hash", "locale", "distro", "limit", "version"]:
if not key in request_item:
- return json_error('invalid data, expected %s' % key)
+ return json_error("invalid data, expected %s" % key)
if not request_item[key] and request_item[key] != 0:
- return json_error('missing data, expected %s' % key)
+ return json_error("missing data, expected %s" % key)
# check format
- if not len(request_item['user_hash']) == 40:
- return json_error('the user_hash is invalid')
+ if not len(request_item["user_hash"]) == 40:
+ return json_error("the user_hash is invalid")
# increments the fetch count on one specific application
datestr = _get_datestr_from_dt(datetime.date.today())
- stmt = insert(Analytic).values(datestr=datestr, app_id=request_item['app_id'])
- if db.session.bind.dialect.name != 'sqlite': # pylint: disable=no-member
+ stmt = insert(Analytic).values(datestr=datestr, app_id=request_item["app_id"])
+ if db.session.bind.dialect.name != "sqlite": # pylint: disable=no-member
stmt_ondupe = stmt.on_duplicate_key_update(fetch_cnt=Analytic.fetch_cnt + 1)
else:
stmt_ondupe = stmt
try:
- db.session.execute(stmt_ondupe) # pylint: disable=no-member
+ db.session.execute(stmt_ondupe) # pylint: disable=no-member
db.session.commit()
except IntegrityError as e:
- print('ignoring: {}'.format(str(e)))
+ print("ignoring: {}".format(str(e)))
# increment the counter for the stats
- component = db.session.query(Component).filter(Component.app_id == request_item['app_id']).first()
+ component = (
+ db.session.query(Component)
+ .filter(Component.app_id == request_item["app_id"])
+ .first()
+ )
if component:
component.fetch_cnt += 1
db.session.commit()
# also add any compat IDs
- app_ids = [request_item['app_id']]
- if 'compat_ids' in request_item:
- app_ids.extend(request_item['compat_ids'])
+ app_ids = [request_item["app_id"]]
+ if "compat_ids" in request_item:
+ app_ids.extend(request_item["compat_ids"])
if component:
for app_id in component.app_ids:
if app_id not in app_ids:
app_ids.append(app_id)
- reviews = db.session.query(Review).\
- join(Component).\
- filter(Component.app_id.in_(app_ids)).\
- filter(Review.reported < ODRS_REPORTED_CNT).all()
+ reviews = (
+ db.session.query(Review)
+ .join(Component)
+ .filter(Component.app_id.in_(app_ids))
+ .filter(Review.reported < ODRS_REPORTED_CNT)
+ .all()
+ )
# if user does not exist then create
- user = db.session.query(User).filter(User.user_hash == request_item['user_hash']).first()
+ user = (
+ db.session.query(User)
+ .filter(User.user_hash == request_item["user_hash"])
+ .first()
+ )
if not user:
- user = User(user_hash=request_item['user_hash'])
+ user = User(user_hash=request_item["user_hash"])
db.session.add(user)
db.session.commit()
@@ -255,50 +307,53 @@ def api_fetch():
for review in reviews:
# the user isn't going to be able to read this
- if not _locale_is_compatible(review.locale, request_item['locale']):
+ if not _locale_is_compatible(review.locale, request_item["locale"]):
continue
# return all results
- item_new = review.asdict(request_item['user_hash'])
- item_new['score'] = _get_review_score(review, request_item)
- item_new['user_skey'] = _get_user_key(request_item['user_hash'], item_new['app_id'])
+ item_new = review.asdict(request_item["user_hash"])
+ item_new["score"] = _get_review_score(review, request_item)
+ item_new["user_skey"] = _get_user_key(
+ request_item["user_hash"], item_new["app_id"]
+ )
# the UI can hide the vote buttons on reviews already voted on
if _vote_exists(review.review_id, user.user_id):
- item_new['vote_id'] = 1
+ item_new["vote_id"] = 1
items_new.append(item_new)
# fake something so the user can get the user_skey
if len(items_new) == 0:
item_new = {}
- item_new['score'] = 0
- item_new['app_id'] = request_item['app_id']
- item_new['user_hash'] = request_item['user_hash']
- item_new['user_skey'] = _get_user_key(request_item['user_hash'], item_new['app_id'])
+ item_new["score"] = 0
+ item_new["app_id"] = request_item["app_id"]
+ item_new["user_hash"] = request_item["user_hash"]
+ item_new["user_skey"] = _get_user_key(
+ request_item["user_hash"], item_new["app_id"]
+ )
items_new.append(item_new)
# sort and cut to limit
- items_new.sort(key=lambda item: item['score'], reverse=True)
+ items_new.sort(key=lambda item: item["score"], reverse=True)
- if request_item['limit'] == 0:
+ if request_item["limit"] == 0:
limit = 50
else:
- limit = request_item.get('limit', -1)
+ limit = request_item.get("limit", -1)
- start = request_item.get('start', 0)
- items_new = items_new[start : start+limit]
+ start = request_item.get("start", 0)
+ items_new = items_new[start : start + limit]
- dat = json.dumps(items_new, sort_keys=True, indent=4, separators=(',', ': '))
- response = Response(response=dat,
- status=200, \
- mimetype='application/json')
+ dat = json.dumps(items_new, sort_keys=True, indent=4, separators=(",", ": "))
+ response = Response(response=dat, status=200, mimetype="application/json")
response.cache_control.private = True
response.add_etag()
return response.make_conditional(request)
-@app.route('/1.0/reviews/api/moderate/<user_hash>')
-@app.route('/1.0/reviews/api/moderate/<user_hash>/<locale>')
+
+@app.route("/1.0/reviews/api/moderate/<user_hash>")
+@app.route("/1.0/reviews/api/moderate/<user_hash>/<locale>")
def api_moderate(user_hash, locale=None):
"""
Return all the reviews on the server the user can moderate.
@@ -307,7 +362,7 @@ def api_moderate(user_hash, locale=None):
items = []
user = db.session.query(User).filter(User.user_hash == user_hash).first()
if not user:
- return json_error('no user for {}'.format(user_hash))
+ return json_error("no user for {}".format(user_hash))
for review in db.session.query(Review).all():
if locale and not _locale_is_compatible(review.locale, locale):
continue
@@ -316,68 +371,90 @@ def api_moderate(user_hash, locale=None):
items.append(review.asdict(user_hash))
if len(items) > 250:
break
- dat = json.dumps(items, sort_keys=True, indent=4, separators=(',', ': '))
- return Response(response=dat,
- status=200, \
- mimetype='application/json')
+ dat = json.dumps(items, sort_keys=True, indent=4, separators=(",", ": "))
+ return Response(response=dat, status=200, mimetype="application/json")
+
def _vote(val):
"""
Up or downvote an existing review by @val karma points.
"""
try:
- request_item = json.loads(request.data.decode('utf8'))
+ request_item = json.loads(request.data.decode("utf8"))
except ValueError as e:
return json_error(str(e))
- for key in ['review_id', 'app_id', 'user_hash', 'user_skey']:
+ for key in ["review_id", "app_id", "user_hash", "user_skey"]:
if not key in request_item:
- return json_error('invalid data, required %s' % key)
+ return json_error("invalid data, required %s" % key)
if request_item[key] is None:
- return json_error('missing data, expected %s' % key)
+ return json_error("missing data, expected %s" % key)
# check format
- if not len(request_item['user_hash']) == 40:
- return json_error('the user_hash is invalid')
- if not len(request_item['user_skey']) == 40:
- return json_error('the user_skey is invalid')
+ if not len(request_item["user_hash"]) == 40:
+ return json_error("the user_hash is invalid")
+ if not len(request_item["user_skey"]) == 40:
+ return json_error("the user_skey is invalid")
# get user
- user = db.session.query(User).filter(User.user_hash == request_item['user_hash']).first()
+ user = (
+ db.session.query(User)
+ .filter(User.user_hash == request_item["user_hash"])
+ .first()
+ )
if not user:
- user = User(request_item['user_hash'])
+ user = User(request_item["user_hash"])
db.session.add(user)
else:
# user is naughty
if user.is_banned:
- return json_error('account has been disabled due to abuse')
+ return json_error("account has been disabled due to abuse")
# the user is too harsh
if val < 0 and user.karma < -50:
- return json_error('all negative karma used up')
-
- if request_item['user_skey'] != _get_user_key(request_item['user_hash'], request_item['app_id']):
- _eventlog_add(_get_client_address(), user.user_id, None,
- 'invalid user_skey of %s' % request_item['user_skey'], important=True)
- #print('expected user_skey of %s' % _get_user_key(request_item['user_hash'], request_item['app_id']))
- return json_error('invalid user_skey')
+ return json_error("all negative karma used up")
+
+ if request_item["user_skey"] != _get_user_key(
+ request_item["user_hash"], request_item["app_id"]
+ ):
+ _eventlog_add(
+ _get_client_address(),
+ user.user_id,
+ None,
+ "invalid user_skey of %s" % request_item["user_skey"],
+ important=True,
+ )
+ # print('expected user_skey of %s' % _get_user_key(request_item['user_hash'],
request_item['app_id']))
+ return json_error("invalid user_skey")
# the user already has a review
- if _vote_exists(request_item['review_id'], user.user_id):
- _eventlog_add(_get_client_address(), user.user_id, request_item['app_id'],
- 'duplicate vote')
- return json_error('already voted on this app')
+ if _vote_exists(request_item["review_id"], user.user_id):
+ _eventlog_add(
+ _get_client_address(),
+ user.user_id,
+ request_item["app_id"],
+ "duplicate vote",
+ )
+ return json_error("already voted on this app")
# update the per-user karma
user.karma += val
- review = db.session.query(Review).\
- join(Component).\
- filter(Component.app_id == request_item['app_id']).first()
+ review = (
+ db.session.query(Review)
+ .join(Component)
+ .filter(Component.app_id == request_item["app_id"])
+ .first()
+ )
if not review:
- _eventlog_add(_get_client_address(), user.user_id, None,
- 'invalid review ID of %s' % request_item['app_id'], important=True)
- return json_error('invalid review ID')
+ _eventlog_add(
+ _get_client_address(),
+ user.user_id,
+ None,
+ "invalid review ID of %s" % request_item["app_id"],
+ important=True,
+ )
+ return json_error("invalid review ID")
# update review
if val == -5:
@@ -390,14 +467,19 @@ def _vote(val):
db.session.commit()
# add the vote to the database
- db.session.add(Vote(user.user_id, val, review_id=request_item['review_id']))
+ db.session.add(Vote(user.user_id, val, review_id=request_item["review_id"]))
db.session.commit()
- _eventlog_add(_get_client_address(), user.user_id, request_item['app_id'],
- 'voted %i on review' % val)
+ _eventlog_add(
+ _get_client_address(),
+ user.user_id,
+ request_item["app_id"],
+ "voted %i on review" % val,
+ )
+
+ return json_success("voted #%i %i" % (request_item["review_id"], val))
- return json_success('voted #%i %i' % (request_item['review_id'], val))
-@app.route('/1.0/reviews/api/upvote', methods=['POST'])
+@app.route("/1.0/reviews/api/upvote", methods=["POST"])
@csrf.exempt
def api_upvote():
"""
@@ -405,7 +487,8 @@ def api_upvote():
"""
return _vote(1)
-@app.route('/1.0/reviews/api/downvote', methods=['POST'])
+
+@app.route("/1.0/reviews/api/downvote", methods=["POST"])
@csrf.exempt
def api_downvote():
"""
@@ -413,7 +496,8 @@ def api_downvote():
"""
return _vote(-1)
-@app.route('/1.0/reviews/api/dismiss', methods=['POST'])
+
+@app.route("/1.0/reviews/api/dismiss", methods=["POST"])
@csrf.exempt
def api_dismiss():
"""
@@ -421,7 +505,8 @@ def api_dismiss():
"""
return _vote(0)
-@app.route('/1.0/reviews/api/report', methods=['POST'])
+
+@app.route("/1.0/reviews/api/report", methods=["POST"])
@csrf.exempt
def api_report():
"""
@@ -429,54 +514,69 @@ def api_report():
"""
return _vote(-5)
-@app.route('/1.0/reviews/api/remove', methods=['POST'])
+
+@app.route("/1.0/reviews/api/remove", methods=["POST"])
@csrf.exempt
def api_remove():
"""
Remove a review.
"""
try:
- request_item = json.loads(request.data.decode('utf8'))
+ request_item = json.loads(request.data.decode("utf8"))
except ValueError as e:
return json_error(str(e))
- for key in ['review_id', 'app_id', 'user_hash', 'user_skey']:
+ for key in ["review_id", "app_id", "user_hash", "user_skey"]:
if not key in request_item:
- return json_error('invalid data, required %s' % key)
+ return json_error("invalid data, required %s" % key)
if not request_item[key]:
- return json_error('missing data, expected %s' % key)
+ return json_error("missing data, expected %s" % key)
# check format
- if not len(request_item['user_hash']) == 40:
- return json_error('the user_hash is invalid')
- if not len(request_item['user_skey']) == 40:
- return json_error('the user_skey is invalid')
+ if not len(request_item["user_hash"]) == 40:
+ return json_error("the user_hash is invalid")
+ if not len(request_item["user_skey"]) == 40:
+ return json_error("the user_skey is invalid")
# the user already has a review
- user = db.session.query(User).filter(User.user_hash == request_item['user_hash']).first()
+ user = (
+ db.session.query(User)
+ .filter(User.user_hash == request_item["user_hash"])
+ .first()
+ )
if not user:
- return json_error('no review')
- review = db.session.query(Review).\
- filter(Review.review_id == request_item['review_id']).\
- filter(Review.user_id == user.user_id).first()
+ return json_error("no review")
+ review = (
+ db.session.query(Review)
+ .filter(Review.review_id == request_item["review_id"])
+ .filter(Review.user_id == user.user_id)
+ .first()
+ )
if not review:
- return json_error('no review')
- if review.component.app_id != request_item['app_id']:
- return json_error('the app_id is invalid')
-
- if request_item['user_skey'] != _get_user_key(request_item['user_hash'], request_item['app_id']):
- _eventlog_add(_get_client_address(), user.user_id, None,
- 'invalid user_skey of %s' % request_item['user_skey'], important=True)
- return json_error('invalid user_skey')
+ return json_error("no review")
+ if review.component.app_id != request_item["app_id"]:
+ return json_error("the app_id is invalid")
+
+ if request_item["user_skey"] != _get_user_key(
+ request_item["user_hash"], request_item["app_id"]
+ ):
+ _eventlog_add(
+ _get_client_address(),
+ user.user_id,
+ None,
+ "invalid user_skey of %s" % request_item["user_skey"],
+ important=True,
+ )
+ return json_error("invalid user_skey")
db.session.delete(review)
db.session.commit()
- _eventlog_add(_get_client_address(),
- user.user_id,
- request_item['app_id'],
- 'removed review')
- return json_success('removed review #%i' % request_item['review_id'])
+ _eventlog_add(
+ _get_client_address(), user.user_id, request_item["app_id"], "removed review"
+ )
+ return json_success("removed review #%i" % request_item["review_id"])
-@app.route('/1.0/reviews/api/ratings/<app_id>')
+
+@app.route("/1.0/reviews/api/ratings/<app_id>")
def api_rating_for_id(app_id):
"""
Get the star ratings for a specific application.
@@ -485,28 +585,26 @@ def api_rating_for_id(app_id):
component = db.session.query(Component).filter(Component.app_id == app_id).first()
if component:
ratings = _get_rating_for_component(component)
- dat = json.dumps(ratings, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ': '))
- return Response(response=dat,
- status=200, \
- mimetype='application/json')
+ dat = json.dumps(
+ ratings, ensure_ascii=False, sort_keys=True, indent=4, separators=(",", ": ")
+ )
+ return Response(response=dat, status=200, mimetype="application/json")
+
-@app.route('/1.0/reviews/api/ratings')
+@app.route("/1.0/reviews/api/ratings")
def api_ratings():
"""
Get the star ratings for all known applications.
"""
item = {}
- for component in db.session.query(Component).\
- order_by(Component.app_id.asc()).all():
+ for component in db.session.query(Component).order_by(Component.app_id.asc()).all():
ratings = _get_rating_for_component(component, 2)
if len(ratings) == 0:
continue
item[component.app_id] = ratings
- dat = json.dumps(item, sort_keys=True, indent=4, separators=(',', ': '))
- response = Response(response=dat,
- status=200, \
- mimetype='application/json')
+ dat = json.dumps(item, sort_keys=True, indent=4, separators=(",", ": "))
+ response = Response(response=dat, status=200, mimetype="application/json")
response.cache_control.public = True
response.add_etag()
return response.make_conditional(request)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]