From ae625cb3e10d92285bfffb42a2b63e982c8c8bd8 Mon Sep 17 00:00:00 2001 From: Will O'Beirne Date: Mon, 4 Mar 2019 16:47:52 -0500 Subject: [PATCH 1/2] Generate random ID for public facing entities. --- backend/grant/comment/models.py | 2 ++ backend/grant/milestone/models.py | 2 ++ backend/grant/proposal/models.py | 6 +++++- backend/grant/rfp/models.py | 3 ++- backend/grant/user/models.py | 4 +++- backend/grant/utils/misc.py | 13 +++++++++++++ 6 files changed, 27 insertions(+), 3 deletions(-) diff --git a/backend/grant/comment/models.py b/backend/grant/comment/models.py index 4fca9241..c8a9d284 100644 --- a/backend/grant/comment/models.py +++ b/backend/grant/comment/models.py @@ -3,6 +3,7 @@ import datetime from functools import reduce from grant.extensions import ma, db from grant.utils.ma_fields import UnixDate +from grant.utils.misc import gen_random_id from sqlalchemy.orm import raiseload HIDDEN_CONTENT = '~~comment removed by admin~~' @@ -25,6 +26,7 @@ class Comment(db.Model): replies = db.relationship("Comment") def __init__(self, proposal_id, user_id, parent_comment_id, content): + self.id = gen_random_id(Comment) self.proposal_id = proposal_id self.user_id = user_id self.parent_comment_id = parent_comment_id diff --git a/backend/grant/milestone/models.py b/backend/grant/milestone/models.py index 66cf899f..9f92ae9a 100644 --- a/backend/grant/milestone/models.py +++ b/backend/grant/milestone/models.py @@ -4,6 +4,7 @@ from grant.extensions import ma, db from grant.utils.exceptions import ValidationException from grant.utils.ma_fields import UnixDate from grant.utils.enums import MilestoneStage +from grant.utils.misc import gen_random_id class MilestoneException(Exception): @@ -52,6 +53,7 @@ class Milestone(db.Model): stage: str = MilestoneStage.IDLE, proposal_id=int, ): + self.id = gen_random_id(Milestone) self.title = title self.content = content self.stage = stage diff --git a/backend/grant/proposal/models.py b/backend/grant/proposal/models.py index 518d7a98..4f952978 100644 --- a/backend/grant/proposal/models.py +++ b/backend/grant/proposal/models.py @@ -9,7 +9,7 @@ from grant.comment.models import Comment from grant.email.send import send_email from grant.extensions import ma, db from grant.utils.exceptions import ValidationException -from grant.utils.misc import dt_to_unix, make_url +from grant.utils.misc import dt_to_unix, make_url, gen_random_id from grant.utils.requests import blockchain_get from grant.settings import PROPOSAL_STAKING_AMOUNT from grant.utils.enums import ( @@ -64,6 +64,7 @@ class ProposalUpdate(db.Model): content = db.Column(db.Text, nullable=False) def __init__(self, proposal_id: int, title: str, content: str): + self.id = gen_random_id(ProposalUpdate) self.proposal_id = proposal_id self.title = title self.content = content @@ -93,6 +94,7 @@ class ProposalContribution(db.Model): user_id: int = None, staking: bool = False, ): + self.id = gen_random_id(ProposalUpdate) self.proposal_id = proposal_id self.amount = amount self.user_id = user_id @@ -180,6 +182,7 @@ class ProposalArbiter(db.Model): user = db.relationship("User", uselist=False, lazy=True, back_populates="arbiter_proposals") def __init__(self, proposal_id: int, user_id: int = None, status: str = ProposalArbiterStatus.MISSING): + self.id = gen_random_id(ProposalArbiter) self.proposal_id = proposal_id self.user_id = user_id self.status = status @@ -249,6 +252,7 @@ class Proposal(db.Model): deadline_duration: int = 5184000, # 60 days category: str = '' ): + self.id = gen_random_id(Proposal) self.date_created = datetime.datetime.now() self.status = status self.title = title diff --git a/backend/grant/rfp/models.py b/backend/grant/rfp/models.py index fc12fa53..02e0d2be 100644 --- a/backend/grant/rfp/models.py +++ b/backend/grant/rfp/models.py @@ -1,7 +1,7 @@ from datetime import datetime from grant.extensions import ma, db from grant.utils.enums import RFPStatus -from grant.utils.misc import dt_to_unix +from grant.utils.misc import dt_to_unix, gen_random_id from grant.utils.enums import Category @@ -49,6 +49,7 @@ class RFP(db.Model): ): # TODO add status assert assert Category.includes(category) + self.id = gen_random_id(RFP) self.date_created = datetime.now() self.title = title self.brief = brief diff --git a/backend/grant/user/models.py b/backend/grant/user/models.py index 7ef72395..290b90ec 100644 --- a/backend/grant/user/models.py +++ b/backend/grant/user/models.py @@ -10,7 +10,7 @@ from grant.email.subscription_settings import ( email_subscriptions_to_dict ) from grant.extensions import ma, db, security -from grant.utils.misc import make_url +from grant.utils.misc import make_url, gen_random_id from grant.utils.social import generate_social_url from grant.utils.upload import extract_avatar_filename, construct_avatar_url from grant.utils import totp_2fa @@ -96,6 +96,7 @@ class Avatar(db.Model): self._image_url = extract_avatar_filename(image_url) def __init__(self, image_url, user_id): + self.id = gen_random_id(Avatar) self.image_url = image_url self.user_id = user_id @@ -143,6 +144,7 @@ class User(db.Model, UserMixin): display_name=None, title=None, ): + self.id = gen_random_id(User) self.email_address = email_address self.display_name = display_name self.title = title diff --git a/backend/grant/utils/misc.py b/backend/grant/utils/misc.py index 5416924f..1157ac9b 100644 --- a/backend/grant/utils/misc.py +++ b/backend/grant/utils/misc.py @@ -64,3 +64,16 @@ def make_preview(content: str, max_length: int): truncated = True return content + '...' if truncated else content + + +def gen_random_id(model): + min_id = 100000 + max_id = pow(2, 31) - 1 + random_id = random.randint(min_id, max_id) + + # If it already exists, generate a new one (recursively) + existing = model.query.filter_by(id=random_id).first() + if existing: + random_id = gen_random_id(model) + + return random_id From 400774c4d342ad8d9a686d2e41eae7042716994e Mon Sep 17 00:00:00 2001 From: Will O'Beirne Date: Mon, 4 Mar 2019 17:20:47 -0500 Subject: [PATCH 2/2] Remove unused endpoint / test, fix another test. --- backend/grant/user/views.py | 20 -------------------- backend/tests/user/test_user_api.py | 11 ++--------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/backend/grant/user/views.py b/backend/grant/user/views.py index 2ed025e1..4dc0407d 100644 --- a/backend/grant/user/views.py +++ b/backend/grant/user/views.py @@ -34,26 +34,6 @@ from .models import ( blueprint = Blueprint('user', __name__, url_prefix='/api/v1/users') -@blueprint.route("/", methods=["GET"]) -@query({ - "proposalId": fields.Str(required=False, missing=None) -}) -def get_users(proposal_id): - proposal = Proposal.query.filter_by(id=proposal_id).first() - if not proposal: - users = User.query.all() - else: - users = ( - User.query - .join(proposal_team) - .join(Proposal) - .filter(proposal_team.c.proposal_id == proposal.id) - .all() - ) - result = users_schema.dump(users) - return result - - @blueprint.route("/me", methods=["GET"]) @auth.requires_auth def get_me(): diff --git a/backend/tests/user/test_user_api.py b/backend/tests/user/test_user_api.py index a8456a57..f3cd18e7 100644 --- a/backend/tests/user/test_user_api.py +++ b/backend/tests/user/test_user_api.py @@ -34,14 +34,6 @@ class TestUserAPI(BaseUserConfig): # should not be able to add social self.assertFalse(user_db.social_medias) - def test_get_all_users(self): - users_get_resp = self.app.get( - "/api/v1/users/" - ) - self.assert200(users_get_resp) - users_json = users_get_resp.json - self.assertEqual(users_json[0]["displayName"], self.user.display_name) - def test_get_single_user_by_id(self): users_get_resp = self.app.get( "/api/v1/users/{}".format(self.user.id) @@ -163,11 +155,12 @@ class TestUserAPI(BaseUserConfig): self.assert200(user_update_resp, user_update_resp.json) user_json = user_update_resp.json + print(user_json) self.assertFalse(user_json["avatar"]) self.assertFalse(len(user_json["socialMedias"])) self.assertEqual(user_json["displayName"], updated_user["displayName"]) self.assertEqual(user_json["title"], updated_user["title"]) - mock_remove_avatar.assert_called_with(test_user["avatar"]["link"], 1) + mock_remove_avatar.assert_called_with(test_user["avatar"]["link"], self.user.id) def test_update_user_400_when_required_param_not_passed(self): self.login_default_user()