Skip to content

Commit

Permalink
🛼🦺 ↝ Adding blueprints for api routes, connection to database, and co…
Browse files Browse the repository at this point in the history
  • Loading branch information
Gizmotronn committed Jan 19, 2023
1 parent 5eae7dc commit 230fce4
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 113 deletions.
2 changes: 2 additions & 0 deletions Server/.flaskenv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FLASK_APP=app.py
FLASK_DEBUG=1
4 changes: 1 addition & 3 deletions Server/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ flask = "*"
flask_cors = "*"
thirdweb-sdk = "*"
python-dotenv = "*"
psycopg2 = "*"

[dev-packages]

[requires]
python_version = "3.8.9"
41 changes: 21 additions & 20 deletions Server/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Server/README.md

This file was deleted.

93 changes: 9 additions & 84 deletions Server/app.py
Original file line number Diff line number Diff line change
@@ -1,99 +1,24 @@
from flask import Flask, request, make_response, jsonify
from flask import Flask, request, make_response, jsonify, Blueprint
from thirdweb.types import LoginPayload
from thirdweb import ThirdwebSDK
from datetime import datetime, timedelta
import os

import moralisHandler
from auth.moralisHandler import moralis_handler
from auth.thirdwebHandler import thirdweb_handler
from contracts.planetDrop import planet_drop
from database.connection import database_connection

app = Flask(__name__)

# Getting proposals (move to separate file)
web3Sdk = ThirdwebSDK("goerli")
contract = web3Sdk.get_contract("0xCcaA1ABA77Bae6296D386C2F130c46FEc3E5A004")
proposals = contract.call("getProposals")

# Minting candidate nfts
nftSdk = ThirdwebSDK('mumbai')
nftContract = nftSdk.get_contract("0xed6e837Fda815FBf78E8E7266482c5Be80bC4bF9")
app.register_blueprint(moralis_handler, url_prefix='/moralis-auth')
app.register_blueprint(thirdweb_handler, url_prefix='/auth')
app.register_blueprint(planet_drop, url_prefix='/planets')
app.register_blueprint(database_connection, url_prefix='/database')

@app.route('/')
def index():
return "Hello World"

@app.route('/proposals', methods=["GET"])
def getProposals():
# Mint nft based on proposal id
proposalCandidate = nftContract.call("lazyMint", _amount, _baseURIForTokens, _data) # Get this from Jupyter notebook -> https://thirdweb.com/mumbai/0xed6e837Fda815FBf78E8E7266482c5Be80bC4bF9/nfts token id 0 (e.g.)
createProposal = contract.call("createProposal", _owner, _title, _description, _target, _deadline, _image) # Get this from PUSH req contents

return proposals

@app.route('/login', methods=['POST'])
def login():
private_key = os.environ.get("PRIVATE_KEY")

if not private_key:
print("Missing PRIVATE_KEY environment variable")
return "Wallet private key not set", 400

sdk = ThirdwebSDK.from_private_key(private_key, 'mumbai') # Initialise the sdk using the wallet and on mumbai testnet chain
payload = LoginPayload.from_json(request.json['payload'])

# Generate access token using signed payload
domain = 'sailors.skinetics.tech'
token = sdk.auth.generate_auth_token(domain, payload)

res = make_response()
res.set_cookie(
'access_token',
token,
path='/',
httponly=True,
secure=True,
samesite='strict',
)
return res, 200

@app.route('/authenticate', methods=['POST'])
def authenticate():
private_key = os.environ.get("PRIVATE_KEY")

if not private_key:
print("Missing PRIVATE_KEY environment variable")
return "Wallet private key not set", 400

sdk = ThirdwebSDK.from_private_key(private_key, 'mumbai')

# Get access token from cookies
token = request.cookies.get('access_token')
if not token:
return 'Unauthorised', 401

domain = 'sailors.skinetics.tech'

try:
address = sdk.auth.authenticate(domain, token)
except:
return "Unauthorized", 401

print(jsonify(address))
return jsonify(address), 200

@app.route('/logout', methods=['POST'])
def logout():
res = make_response()
res.set_cookie(
'access_token',
'none',
expires=datetime.utcnow() + timedelta(second = 5)
)
return res, 200

@app.route('/helloworld')
def helloworld():
return "address" #address

# Getting proposals route
#@app.route('/proposals')
#def getProposals():
Expand Down
10 changes: 5 additions & 5 deletions Server/moralisHandler.py → Server/auth/moralisHandler.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from flask import Flask
from flask import request
from flask import Blueprint, request
from moralis import auth
from flask_cors import CORS
from app import app

moralis_handler = Blueprint('moralis_handler', __name__)

# Moralis setup
apiKey = "kJfYYpmMmfKhvaWMdD3f3xMMb24B4MHBDDVrfjslkKgTilvMgdwr1bwKUr8vWdHH" # Move to env

# Authentication routes -> move to auth.py later
# Request a challenge when a user attempts to connect their wallet
@app.route('/requestChallenge', methods=['GET'])
@moralis_handler.route('/requestChallenge', methods=['GET'])
def reqChallenge():
args = request.args # Fetch the arguments from the request

Expand All @@ -35,7 +35,7 @@ def reqChallenge():
return result

# Verify signature from user
@app.route('/verifyChallenge', methods=['GET'])
@moralis_handler.route('/verifyChallenge', methods=['GET'])
def verifyChallenge():
args = request.args

Expand Down
85 changes: 85 additions & 0 deletions Server/auth/thirdwebHandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from flask import Blueprint, request
from thirdweb.types import LoginPayload
from thirdweb import ThirdwebSDK
from datetime import datetime, timedelta
import os

thirdweb_handler = Blueprint('thirdweb_handler', __name__)

# Getting proposals
web3Sdk = ThirdwebSDK("goerli")
contract = web3Sdk.get_contract("0xCcaA1ABA77Bae6296D386C2F130c46FEc3E5A004")
proposals = contract.call("getProposals")

# Minting candidate nfts
nftSdk = ThirdwebSDK('mumbai')
nftContract = nftSdk.get_contract("0xed6e837Fda815FBf78E8E7266482c5Be80bC4bF9")

@thirdweb_handler.route('/login', methods=['POST'])
def login():
private_key = os.environ.get("PRIVATE_KEY")

if not private_key:
print("Missing PRIVATE_KEY environment variable")
return "Wallet private key not set", 400

sdk = ThirdwebSDK.from_private_key(private_key, 'mumbai') # Initialise the sdk using the wallet and on mumbai testnet chain
payload = LoginPayload.from_json(request.json['payload'])

# Generate access token using signed payload
domain = 'sailors.skinetics.tech'
token = sdk.auth.generate_auth_token(domain, payload)

res = make_response()
res.set_cookie(
'access_token',
token,
path='/',
httponly=True,
secure=True,
samesite='strict',
)
return res, 200

@thirdweb_handler.route('/authenticate', methods=['POST'])
def authenticate():
private_key = os.environ.get("PRIVATE_KEY")

if not private_key:
print("Missing PRIVATE_KEY environment variable")
return "Wallet private key not set", 400

sdk = ThirdwebSDK.from_private_key(private_key, 'mumbai')

# Get access token from cookies
token = request.cookies.get('access_token')
if not token:
return 'Unauthorised', 401

domain = 'sailors.skinetics.tech'

try:
address = sdk.auth.authenticate(domain, token)
except:
return "Unauthorized", 401

print(jsonify(address))
return jsonify(address), 200

@thirdweb_handler.route('/logout', methods=['POST'])
def logout():
res = make_response()
res.set_cookie(
'access_token',
'none',
expires=datetime.utcnow() + timedelta(second = 5)
)
return res, 200

@thirdweb_handler.route('/proposals', methods=["GET", "POST"])
def getProposals():
# Mint nft based on proposal id
proposalCandidate = nftContract.call("lazyMint", _amount, _baseURIForTokens, _data) # Get this from Jupyter notebook -> https://thirdweb.com/mumbai/0xed6e837Fda815FBf78E8E7266482c5Be80bC4bF9/nfts token id 0 (e.g.)
createProposal = contract.call("createProposal", _owner, _title, _description, _target, _deadline, _image) # Get this from PUSH req contents

return proposals
39 changes: 39 additions & 0 deletions Server/contracts/planetDrop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from flask import Blueprint, request
from thirdweb import ThirdwebSDK

planet_drop = Blueprint('planet_drop', __name__)

# Get NFT balance for Planet Edition Drop (https://thirdweb.com/goerli/0xdf35Bb26d9AAD05EeC5183c6288f13c0136A7b43/code)
@planet_drop.route('/balance')
def get_balance():
# Planet Edition Drop Contract
network = "goerli"
sdk = ThirdwebSDK(network)
contract = sdk.get_edition_drop("0xdf35Bb26d9AAD05EeC5183c6288f13c0136A7b43")

address = "0xCdc5929e1158F7f0B320e3B942528E6998D8b25c"
token_id = 0
balance = contract.balance_of(address, token_id)

return str(balance)

@planet_drop.route('/get_planet')
def get_planet():
network = 'goerli'
sdk = ThirdwebSDK(network)

# Getting Planet (candidate nfts)
contract = sdk.get_contract("0x766215a318E2AD1EbdC4D92cF2A3b70CBedeac31")
tic55525572 = contract.call("uri", 0) # For token id 0, tic id 55525572
return str(tic55525572)

@planet_drop.route('/mint_planet', methods=["GET", "POST"])
def create_planet():
#Output from IPFS gateway: #{"name":"TIC 55525572","description":"Exoplanet candidate discovered by TIC ID. \n\nReferences: https://exoplanets.nasa.gov/exoplanet-catalog/7557/toi-813-b/\nhttps://exofop.ipac.caltech.edu/tess/target.php?id=55525572\n\nDeepnote Analysis: https://deepnote.com/workspace/star-sailors-49d2efda-376f-4329-9618-7f871ba16007/project/Star-Sailors-Light-Curve-Plot-b4c251b4-c11a-481e-8206-c29934eb75da/%2FMultisector%20Analysis.ipynb","image":"ipfs://Qma2q8RgX1X2ZVcfnJ7b9RJeKHzoTXahs2ezzqQP4f5yvT/0.png","external_url":"","background_color":"","attributes":[{"trait_type":"tic","value":"55525572"},{"trait_type":"mass_earth","value":"36.4"},{"trait_type":"type","value":"neptune-like"},{"trait_type":"orbital_period","value":"83.9"},{"trait_type":"eccentricity","value":"0.0"},{"trait_type":"detection_method","value":"transit"},{"trait_type":"orbital_radius","value":"0.423"},{"trait_type":"radius_jupiter","value":"0.599"},{"trait_type":"distance_earth","value":"858"}]}
# Multiple instances for the same ID will be created (as long as the traits are the same), one for each person, as each planet instance appeared differently and will be manipulated differently by users
# Creating a planet nft based on discovery
network = 'goerli'
sdk = ThirdwebSDK(network)
contract = sdk.get_contract("0x766215a318E2AD1EbdC4D92cF2A3b70CBedeac31")
#data = contract.call("lazyMint", _amount, _baseURIForTokens, _data) (POST data)
# Interaction flow -> https://www.notion.so/skinetics/Sample-Planets-Contract-4c3bdcbca4b9450382f9cc4e72e081f7
36 changes: 36 additions & 0 deletions Server/database/connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from flask import Blueprint
from dotenv import load_dotenv
import psycopg2

database_connection = Blueprint('database_connection', __name__)

load_dotenv()
url = os.getenv("DATABASE_URL")
connection = psycopg2.connect(url)

# PostgreSQL queries
CREATE_USERS_TABLE = (
'CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, address TEXT);'
)
CREATE_PLANETS_TABLE = (
"""CREATE TABLE IF NOT EXISTS planets (user_id INTEGER, temperature REAL, date TIMESTAMP, FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE);"""
)
INSERT_USER_RETURN_ID = 'INSERT INTO users (address) VALUES (%s) RETURNING id;'
INSERT_PLANET = (
'INSERT INTO planets (user_id, temperature, date) VALUES (%s, %s, %s);'
)

# User Management
@database_connection.post('/api/user')
def addUser():
data = request.get_json()
address = data['address']

# Connect to the database
with connection:
with connection.cursor() as cursor:
cursor.execute(CREATE_USERS_TABLE)
cursor.execute(INSERT_USER_RETURN_ID, (address,))
user_id = cursor.fetchone()[0]

return {'id': user_id, 'message': f"User {address} created"}, 201
3 changes: 3 additions & 0 deletions Server/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Make sure to initialise the Flask app with `pipenv` and run the command `export FLASK_APP=app.py`

We'll have a simple wrapper on Deepnote that will communicate with the multi-layered (aka file) Flask app here, until Deepnote supports multiple files in a Flask container

0 comments on commit 230fce4

Please sign in to comment.