Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

feat: instatiate db using sqlalch #238

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
361cd6c
feat: instatiate db using sqlalch
internnos Sep 10, 2022
968e6ee
refactor: use env variable
internnos Sep 10, 2022
2ab02ae
feat: remove unecessary file
internnos Sep 10, 2022
d468859
feat(routes): change user model
internnos Sep 10, 2022
b682657
feat(user): add github field
internnos Sep 10, 2022
7da1016
feat: verify signature
internnos Sep 15, 2022
ed4d5ff
feat(register_user): convert signature string to tuple
internnos Sep 15, 2022
2bc2261
feat: github is not mandatory
internnos Sep 16, 2022
ab9d079
feat: remove unused code
internnos Sep 16, 2022
1143eb7
fix: existing user error handling
internnos Sep 19, 2022
6687ca6
fix: abi path
internnos Sep 19, 2022
7c770e6
feat(db): move
internnos Sep 20, 2022
b8a08ed
feat: add package
internnos Sep 20, 2022
1f0805a
fix: comment out broken import due to cairo v0.10
internnos Sep 20, 2022
c22801a
docs: add env variables
internnos Sep 20, 2022
f47bc6d
fix(fetchUserInfo): fix user query
internnos Sep 20, 2022
05a5b34
fix(registerUser): verify signature
internnos Sep 20, 2022
3aa42aa
fix: signature datatype
internnos Sep 20, 2022
89fba89
fix(StarklingsUser): change wallet address length
internnos Sep 20, 2022
4a7ea17
fix(StarklingsUser): signature datatype
internnos Sep 20, 2022
2abe463
feat: add abi
internnos Sep 22, 2022
b4645ea
fix: instantiate db
internnos Sep 22, 2022
4e119b9
fix: signature datatype
internnos Sep 22, 2022
672bb3e
fix: signature datatype
internnos Sep 22, 2022
77af810
fix: signature datatype
internnos Sep 22, 2022
304d100
feat(updateUser): add
internnos Sep 22, 2022
c7d8ecc
fix(ValidatedExercise): validated_exercise_id length
internnos Sep 22, 2022
247448b
fix(ValidatedExercise): wallet_address length
internnos Sep 22, 2022
f0bb2e2
fix(ValidatedExercise): validated_exercise_id length
internnos Sep 22, 2022
4b4f71d
feat(updateUser): verify signature
internnos Sep 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions starklings-backend/starklings_backend/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import os
import pymysql
from sqlalchemy.orm import declarative_base, sessionmaker
from models import StarklingsUser,Path,Exercise,ValidatedExercise, Base
from sqlalchemy import create_engine
from dotenv import load_dotenv
load_dotenv()

host=os.environ.get('DATABASE_HOST', '')
database=os.environ.get('DATABASE_NAME', '')
user=os.environ.get('DATABASE_USER', '')
password=os.environ.get('DATABASE_PWD', '')

engine = create_engine(f'mysql+pymysql://{user}:{password}@{host}/{database}', echo=True)

Session = sessionmaker(bind=engine)
Base.metadata.create_all(engine)
42 changes: 42 additions & 0 deletions starklings-backend/starklings_backend/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship, declarative_base

Base = declarative_base()

class StarklingsUser(Base):
__tablename__ = "starklings_user"
wallet_address = Column(String(42), primary_key=True)
signature = Column(String(255), nullable=False)
github = Column(String(255), nullable=True)
username = Column(String(255), nullable=False)
score = Column(Integer, nullable=False, default=0)
starklings_user = relationship("ValidatedExercise")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename it to validated_exercises

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

according to the docs, the arg to relationship is the Class name cmiiw

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i change to table name, i'll get this error instead

sqlalchemy.exc.ArgumentError: relationship 'starklings_user' expects a class or a mapper argument (received: <class 'sqlalchemy.sql.schema.Table'>)



class Path(Base):
__tablename__ = "path"
path_name = Column(String(255), primary_key=True)
num_exercises = Column(Integer, nullable=False)
path = relationship("Exercise")


class Exercise(Base):
__tablename__ = "exercise"
exercise_name = Column(String(255), primary_key=True)
score = Column(Integer, nullable=False, default=0)
path_name = Column(String(255), ForeignKey("path.path_name"), nullable=False)
exercise = relationship("ValidatedExercise")


class ValidatedExercise(Base):
__tablename__ = "validated_exercise"
validated_exercise_id = Column(String(64), primary_key=True)
exercise_name = Column(
String(255),
ForeignKey("exercise.exercise_name"),
nullable=False,
)
wallet_address = Column(
String(42), ForeignKey("starklings_user.wallet_address"), nullable=False
)

4 changes: 0 additions & 4 deletions starklings-backend/starklings_backend/models/shared.py

This file was deleted.

8 changes: 0 additions & 8 deletions starklings-backend/starklings_backend/models/user.py

This file was deleted.

33 changes: 23 additions & 10 deletions starklings-backend/starklings_backend/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
import bcrypt
from sqlalchemy.exc import IntegrityError
from flask_sqlalchemy import SQLAlchemy
from starklings_backend.utils import verify_email
from starklings_backend.models.shared import db
from starklings_backend.models.user import Starklingsuser
from starklings_backend.utils import verify_email, VerifySignature
from starklings_backend.models import StarklingsUser, Path, Exercise, ValidatedExercise, Base
from starklings_backend.exercise import verify_exercise
from checker import ExerciceFailed
import tempfile
from starklings_backend.db import Session



app_routes = Blueprint('app_routes', __name__)

db = Session()

@app_routes.route('/', methods=['GET'])
def landing():
return 'Starklings API'
Expand All @@ -27,18 +31,27 @@ def register_user():
"""
try:
signature = request.json.get('signature', None)
# convert string to tuple
signature = eval(signature)
wallet_address = request.json.get('wallet_address', None)
username = request.json.get('username', wallet_address)
github = request.json.get('github', None)
message_hash = request.json.get('message_hash', '')
network = request.json.get('network', 'testnet')
if None in [wallet_address, signature]:
return "Wrong form", 400
#@TODO: Check Signature validity

user = Starklingsuser(wallet_address=wallet_address, signature=signature, username=username)
db.session.commit()
return f'Welcome! {username}', 200
# verify signature
verify_signature = VerifySignature(abi, network, wallet_address)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is abi defined

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved!

is_valid, error = verify_signature.verify_signature(message_hash, signature)
if error is None:
user = StarklingsUser(wallet_address=wallet_address, signature=signature, github=github, username=username)
db.add(user)
db.commit()
return f'Welcome! {username}', 200
return 'Signature invalid', 400

except IntegrityError as e:
db.session.rollback()
session.rollback()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is session defined

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have fixed it!

return 'User Already Exists', 400
except AttributeError:
return 'Provide an Email and Password in JSON format in the request body', 400
Expand All @@ -54,7 +67,7 @@ def fetch_user_info():
wallet_address = request.json.get('wallet_address', None)
if not wallet_address:
return 'Missing address', 400
user = Starklingsuser.query.filter_by(wallet_address=wallet_address).first()
user = StarklingsUser.query.filter_by(wallet_address=wallet_address).first()
if not user:
return 'User Not Found!', 404

Expand Down
58 changes: 48 additions & 10 deletions starklings-backend/starklings_backend/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
import json
import os
import re
from starknet_py.net.gateway_client import GatewayClient
from starknet_py.net.networks import TESTNET, MAINNET
from starknet_py.contract import Contract
import asyncio

regex = re.compile(r'([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+')

regex = re.compile(r"([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+")


def verify_email(email):
if re.fullmatch(regex, email):
return True
return True
else:
return False
return False


class Requester:
def __init__(self, base_url, **kwargs):
Expand All @@ -22,25 +28,25 @@ def __init__(self, base_url, **kwargs):
setattr(self.session, arg, kwargs[arg])

def request(self, method, url, **kwargs):
return self.session.request(method, self.base_url+url, **kwargs)
return self.session.request(method, self.base_url + url, **kwargs)

def head(self, url, **kwargs):
return self.session.head(self.base_url+url, **kwargs)
return self.session.head(self.base_url + url, **kwargs)

def get(self, url, **kwargs):
return self.session.get(self.base_url+url, **kwargs)
return self.session.get(self.base_url + url, **kwargs)

def post(self, url, data, **kwargs):
return self.session.post(self.base_url+url, data=data, **kwargs)
return self.session.post(self.base_url + url, data=data, **kwargs)

def put(self, url, **kwargs):
return self.session.put(self.base_url+url, **kwargs)
return self.session.put(self.base_url + url, **kwargs)

def patch(self, url, **kwargs):
return self.session.patch(self.base_url+url, **kwargs)
return self.session.patch(self.base_url + url, **kwargs)

def delete(self, url, **kwargs):
return self.session.delete(self.base_url+url, **kwargs)
return self.session.delete(self.base_url + url, **kwargs)

@staticmethod
def __deep_merge(source, destination):
Expand All @@ -51,3 +57,35 @@ def __deep_merge(source, destination):
else:
destination[key] = value
return destination


class VerifySignature:
SUPPORTED_NETWORKS = ["mainnet", "testnet"]

def __init__(self, abi, network, contract_address):
with open(abi, "r") as reader:
abi = json.load(reader)
assert network in self.SUPPORTED_NETWORKS
network = self.set_network(network)
self.contract = Contract(
contract_address,
abi,
network,
)

def set_network(self, network):
if network == "testnet":
return GatewayClient(TESTNET)
elif network == "mainnet":
return GatewayClient(MAINNET)

def __call__(self, message_hash, signature):
try:
asyncio.run(
self.contract.functions["is_valid_signature"].call(
message_hash, (signature[0], signature[1])
)
)
return "Valid Signature", None
except Exception as e:
return "Invalid Signature", 400