[odrs-web] Add a user_id foreign key to all tables
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [odrs-web] Add a user_id foreign key to all tables
- Date: Tue, 2 Jul 2019 10:03:48 +0000 (UTC)
commit 2baf9227267d42e578b79c75833792cd5b95d6ee
Author: Richard Hughes <richard hughsie com>
Date: Tue Jul 2 10:56:46 2019 +0100
Add a user_id foreign key to all tables
The now-duplicate user_hash will be removed in the next commit to allow pods to migrate without downtime.
app_data/migrations/versions/19526c284b29_.py | 64 +++++++++++++++++++++++++++
app_data/odrs/dbutils.py | 8 +++-
app_data/odrs/models.py | 27 +++++++++--
app_data/odrs/tests/odrs_test.py | 6 +--
app_data/odrs/util.py | 3 +-
app_data/odrs/views_admin.py | 2 +-
app_data/odrs/views_api.py | 47 ++++++++++++--------
7 files changed, 130 insertions(+), 27 deletions(-)
---
diff --git a/app_data/migrations/versions/19526c284b29_.py b/app_data/migrations/versions/19526c284b29_.py
new file mode 100644
index 0000000..cd1ec34
--- /dev/null
+++ b/app_data/migrations/versions/19526c284b29_.py
@@ -0,0 +1,64 @@
+"""
+
+Revision ID: 19526c284b29
+Revises: 84deb10331db
+Create Date: 2019-07-02 10:51:23.952062
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '19526c284b29'
+down_revision = '84deb10331db'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+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():
+ op.add_column('eventlog', sa.Column('user_id', sa.Integer(), nullable=True))
+ op.add_column('moderators', sa.Column('user_id', sa.Integer(), nullable=True))
+ op.add_column('reviews', sa.Column('user_id', sa.Integer(), nullable=True))
+ op.add_column('votes', sa.Column('user_id', sa.Integer(), nullable=True))
+ op.create_foreign_key(None, 'eventlog', 'users', ['user_id'], ['user_id'])
+ op.create_foreign_key(None, 'moderators', 'users', ['user_id'], ['user_id'])
+ op.create_foreign_key(None, 'reviews', 'users', ['user_id'], ['user_id'])
+ op.create_foreign_key(None, 'votes', 'users', ['user_id'], ['user_id'])
+
+ 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')
+ for val in db.session.query(Moderator).all():
+ val.user_id = _hash_to_id(val.user_hash)
+ db.session.commit()
+
+ 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')
+ 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')
diff --git a/app_data/odrs/dbutils.py b/app_data/odrs/dbutils.py
index ef25f03..8be1831 100644
--- a/app_data/odrs/dbutils.py
+++ b/app_data/odrs/dbutils.py
@@ -11,11 +11,17 @@ def init_db(db):
db.metadata.create_all(bind=db.engine)
# ensure admin user exists
- from .models import Moderator
+ from .models import Moderator, User
+ user = db.session.query(User).filter(User.user_hash ==
'deadbeef348c0f88529f3bfd937ec1a5d90aefc7').first()
+ if not user:
+ 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'
mod.is_admin = True
+ mod.user_id = user.user_id
db.session.add(mod)
db.session.commit()
diff --git a/app_data/odrs/models.py b/app_data/odrs/models.py
index 134c0e3..ea100d3 100644
--- a/app_data/odrs/models.py
+++ b/app_data/odrs/models.py
@@ -11,7 +11,8 @@ import datetime
from werkzeug.security import generate_password_hash, check_password_hash
-from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Index
+from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Index, ForeignKey
+from sqlalchemy.orm import relationship
from odrs import db
@@ -51,11 +52,15 @@ class Vote(db.Model):
vote_id = Column(Integer, primary_key=True, nullable=False, unique=True)
date_created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
user_hash = Column(Text)
+ user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
val = Column(Integer, default=0)
review_id = Column(Integer, default=0)
- def __init__(self, user_hash, val, review_id=0):
+ user = relationship('User')
+
+ def __init__(self, user_id, user_hash, val, review_id=0):
self.review_id = review_id
+ self.user_id = user_id
self.user_hash = user_hash
self.val = val
@@ -77,6 +82,10 @@ 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')
+
def __init__(self, user_hash=None):
self.user_hash = user_hash
self.karma = 0
@@ -99,6 +108,7 @@ class Review(db.Model):
summary = Column(Text)
description = Column(Text)
user_hash = Column(Text)
+ user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
user_addr = Column(Text)
user_display = Column(Text)
version = Column(Text)
@@ -108,6 +118,8 @@ class Review(db.Model):
karma_down = Column(Integer, default=0)
reported = Column(Integer, default=0)
+ user = relationship('User', back_populates='reviews')
+
def __init__(self):
self.app_id = None
self.locale = None
@@ -117,6 +129,7 @@ class Review(db.Model):
self.distro = None
self.karma_up = 0
self.karma_down = 0
+ self.user_id = 0
self.user_hash = None
self.user_display = None
self.rating = 0
@@ -159,12 +172,16 @@ class Event(db.Model):
date_created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
user_addr = Column(Text)
user_hash = Column(Text)
+ user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
message = Column(Text)
app_id = Column(Text)
important = Column(Boolean, default=False)
- def __init__(self, user_addr, user_hash=None, app_id=None, message=None, important=False):
+ user = relationship('User')
+
+ def __init__(self, user_addr, user_id=None, user_hash=None, app_id=None, message=None, important=False):
self.user_addr = user_addr
+ self.user_id = user_id
self.user_hash = user_hash
self.message = message
self.app_id = app_id
@@ -186,13 +203,17 @@ class Moderator(db.Model):
is_enabled = Column(Boolean, default=False)
is_admin = Column(Boolean, default=False)
user_hash = Column(Text)
+ user_id = Column(Integer, ForeignKey('users.user_id'), nullable=True)
locales = Column(Text)
+ user = relationship('User')
+
def __init__(self, username=None, password=None, display_name=None):
self.username = username
self.display_name = display_name
self.is_enabled = False
self.is_admin = False
+ self.user_id = 0
self.user_hash = None
self.locales = None
self.locales = password
diff --git a/app_data/odrs/tests/odrs_test.py b/app_data/odrs/tests/odrs_test.py
index b3d5241..ffb8c1e 100644
--- a/app_data/odrs/tests/odrs_test.py
+++ b/app_data/odrs/tests/odrs_test.py
@@ -319,12 +319,12 @@ class OdrsTest(unittest.TestCase):
def test_api_moderate_locale(self):
- rv = self.app.get('/1.0/reviews/api/moderate/FIXMEuserhash/en_GB')
+ 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/FIXMEuserhash/en_GB')
+ 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/FIXMEuserhash/fr_FR')
+ 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):
diff --git a/app_data/odrs/util.py b/app_data/odrs/util.py
index c7e22c3..e22352d 100644
--- a/app_data/odrs/util.py
+++ b/app_data/odrs/util.py
@@ -49,6 +49,7 @@ def _get_user_key(user_hash, app_id):
return key
def _eventlog_add(user_addr=None,
+ user_id=None,
user_hash=None,
app_id=None,
message=None,
@@ -56,7 +57,7 @@ def _eventlog_add(user_addr=None,
""" Adds a warning to the event log """
from .models import Event
from odrs import db
- db.session.add(Event(user_addr, user_hash, app_id, message, important))
+ db.session.add(Event(user_addr, user_id, user_hash, app_id, message, important))
db.session.commit()
def _get_rating_for_app_id(app_id, min_total=1):
diff --git a/app_data/odrs/views_admin.py b/app_data/odrs/views_admin.py
index d39f04d..16cfe65 100644
--- a/app_data/odrs/views_admin.py
+++ b/app_data/odrs/views_admin.py
@@ -625,7 +625,7 @@ def admin_vote(review_id, val_str):
user = User(user_hash)
db.session.add(user)
user.karma += val
- db.session.add(Vote(user_hash, val, review_id=review_id))
+ db.session.add(Vote(user.user_id, user_hash, val, review_id=review_id))
db.session.commit()
flash('Recorded vote')
return redirect(url_for('.admin_show_review', review_id=review_id))
diff --git a/app_data/odrs/views_api.py b/app_data/odrs/views_api.py
index 1447d96..8232e11 100644
--- a/app_data/odrs/views_api.py
+++ b/app_data/odrs/views_api.py
@@ -102,6 +102,7 @@ def api_submit():
filter(Review.app_id == item['app_id']).\
filter(Review.user_hash == item['user_hash']).first():
_eventlog_add(_get_client_address(),
+ user.user_id,
item['user_hash'],
item['app_id'],
'already reviewed')
@@ -113,6 +114,7 @@ def api_submit():
review.locale = item['locale']
review.summary = _sanitised_summary(item['summary'])
review.description = _sanitised_description(item['description'])
+ review.user_id = user.user_id
review.user_hash = item['user_hash']
review.version = _sanitised_version(item['version'])
review.distro = item['distro']
@@ -130,6 +132,7 @@ def api_submit():
# log and add
_eventlog_add(_get_client_address(),
+ review.user_id,
review.user_hash,
review.app_id,
'reviewed')
@@ -295,19 +298,7 @@ def _vote(val):
if not len(item['user_skey']) == 40:
return json_error('the user_skey is invalid')
- if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']):
- _eventlog_add(_get_client_address(), item['user_hash'], None,
- 'invalid user_skey of %s' % item['user_skey'], important=True)
- #print('expected user_skey of %s' % _get_user_key(item['user_hash'], item['app_id']))
- return json_error('invalid user_skey')
-
- # the user already has a review
- if _vote_exists(item['review_id'], item['user_hash']):
- _eventlog_add(_get_client_address(), item['user_hash'], item['app_id'],
- 'duplicate vote')
- return json_error('already voted on this app')
-
- # update the per-user karma
+ # get user
user = db.session.query(User).filter(User.user_hash == item['user_hash']).first()
if not user:
user = User(item['user_hash'])
@@ -320,12 +311,26 @@ def _vote(val):
# the user is too harsh
if val < 0 and user.karma < -50:
- return json_error('odrs_all negative karma used up')
+ return json_error('all negative karma used up')
+
+ if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']):
+ _eventlog_add(_get_client_address(), user.user_id, item['user_hash'], None,
+ 'invalid user_skey of %s' % item['user_skey'], important=True)
+ #print('expected user_skey of %s' % _get_user_key(item['user_hash'], item['app_id']))
+ return json_error('invalid user_skey')
+
+ # the user already has a review
+ if _vote_exists(item['review_id'], item['user_hash']):
+ _eventlog_add(_get_client_address(), user.user_id, item['user_hash'], 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).filter(Review.app_id == item['app_id']).first()
if not review:
- _eventlog_add(_get_client_address(), item['user_hash'], None,
+ _eventlog_add(_get_client_address(), user.user_id, item['user_hash'], None,
'invalid review ID of %s' % item['app_id'], important=True)
return json_error('invalid review ID')
@@ -340,9 +345,9 @@ def _vote(val):
db.session.commit()
# add the vote to the database
- db.session.add(Vote(item['user_hash'], val, review_id=item['review_id']))
+ db.session.add(Vote(user.user_id, item['user_hash'], val, review_id=item['review_id']))
db.session.commit()
- _eventlog_add(_get_client_address(), item['user_hash'], item['app_id'],
+ _eventlog_add(_get_client_address(), user.user_id, item['user_hash'], item['app_id'],
'voted %i on review' % val)
return json_success('voted #%i %i' % (item['review_id'], val))
@@ -396,6 +401,11 @@ def api_remove():
if not len(item['user_skey']) == 40:
return json_error('the user_skey is invalid')
+ # get user
+ user = db.session.query(User).filter(User.user_hash == item['user_hash']).first()
+ if not user:
+ return json_error('no review')
+
# the user already has a review
review = db.session.query(Review).\
filter(Review.review_id == item['review_id']).\
@@ -406,13 +416,14 @@ def api_remove():
return json_error('the app_id is invalid')
if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']):
- _eventlog_add(_get_client_address(), item['user_hash'], None,
+ _eventlog_add(_get_client_address(), user.user_id, None,
'invalid user_skey of %s' % 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,
item['user_hash'],
item['app_id'],
'removed review')
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]