diff --git a/alembic/versions/40734564d415_init_suchwowx.py b/alembic/versions/40734564d415_init_suchwowx.py new file mode 100644 index 0000000..8298ae9 --- /dev/null +++ b/alembic/versions/40734564d415_init_suchwowx.py @@ -0,0 +1,62 @@ +"""init suchwowx + +Revision ID: 40734564d415 +Revises: +Create Date: 2021-12-28 22:05:09.994215 + +""" +from uuid import uuid4 + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '40734564d415' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + mods_table = op.create_table('moderators', + sa.Column('id', sa.Integer, autoincrement=True, nullable=False, primary_key=True), + sa.Column('user_id', sa.Integer, nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], name='moderators_user_id_fkey'), + ) + users_table = op.create_table('users', + sa.Column('id', sa.Integer, autoincrement=True, nullable=False), + sa.Column('register_date', sa.DateTime(), autoincrement=False, nullable=True), + sa.Column('last_login_date', sa.DateTime(), autoincrement=False, nullable=True), + sa.Column('verified', sa.Boolean, autoincrement=False, nullable=True), + sa.Column('public_address', sa.String(180), autoincrement=False, nullable=True), + sa.Column('nonce', sa.String(180), autoincrement=False, nullable=True), + sa.Column('nonce_date', sa.DateTime(), autoincrement=False, nullable=True), + sa.Column('handle', sa.String(40), autoincrement=False, nullable=True, ), + sa.Column('bio', sa.String(600), autoincrement=False, nullable=True), + sa.Column('profile_image', sa.String(300), autoincrement=False, nullable=True), + sa.Column('website_url', sa.String(120), autoincrement=False, nullable=True), + sa.Column('moderator_id', sa.Integer, nullable=True), + sa.PrimaryKeyConstraint('id', name='users_pkey'), + sa.UniqueConstraint('handle', name='users_handle_key'), + sa.ForeignKeyConstraint(['moderator_id'], ['moderators.id'], name='users_user_id_fkey'), + ) + memes_table = op.create_table('memes', + sa.Column('id', sa.String(80), server_default=uuid4().hex, autoincrement=False, nullable=False), + sa.Column('user_id', sa.Integer, autoincrement=False, nullable=True), + sa.Column('create_date', sa.DateTime(), autoincrement=False, nullable=True), + sa.Column('title', sa.String(80), autoincrement=False, nullable=True), + sa.Column('description', sa.String(300), autoincrement=False, nullable=True), + sa.Column('file_name', sa.String(300), autoincrement=False, nullable=True), + sa.Column('minted', sa.Boolean, autoincrement=False, nullable=True), + sa.Column('meta_ipfs_hash', sa.String(100), autoincrement=False, nullable=True), + sa.Column('meme_ipfs_hash', sa.String(100), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], name='artwork_user_id_fkey'), + sa.PrimaryKeyConstraint('id', name='artwork_pkey'), + sa.UniqueConstraint('meta_ipfs_hash', name='memes_meta_ipfs_hash_key'), + sa.UniqueConstraint('meme_ipfs_hash', name='memes_meme_ipfs_hash_key') + ) + +def downgrade(): + op.drop_table('moderators') + op.drop_table('users') + op.drop_table('memes') diff --git a/suchwowx/models.py b/suchwowx/models.py index e1e99fc..c685db7 100644 --- a/suchwowx/models.py +++ b/suchwowx/models.py @@ -95,7 +95,7 @@ class Meme(db.Model): meme_ipfs_hash = db.Column(db.String(100), unique=True, nullable=True) title = db.Column(db.String(50)) description = db.Column(db.String(400), nullable=True) - creator_handle = db.Column(db.String(50), nullable=True) + minted = db.Column(db.Boolean, default=False) def __repr__(self): return str(f'meme-{self.id}') diff --git a/suchwowx/static/js/main.js b/suchwowx/static/js/main.js new file mode 100644 index 0000000..b479bd1 --- /dev/null +++ b/suchwowx/static/js/main.js @@ -0,0 +1,8 @@ +async function getSignedData(publicAddress, jsonData) { + const signedData = await window.ethereum.request({ + method: 'eth_signTypedData_v3', + params: [publicAddress, JSON.stringify(jsonData)] + }); + console.log(signedData); + return signedData +} diff --git a/suchwowx/static/js/metamask.js b/suchwowx/static/js/metamask.js new file mode 100644 index 0000000..190edd3 --- /dev/null +++ b/suchwowx/static/js/metamask.js @@ -0,0 +1,78 @@ +window.addEventListener('DOMContentLoaded', () => { + onboardMetaMask() +}) + +async function onboardMetaMask(){ + const onboarding = new MetaMaskOnboarding(); + const onboardButton = document.getElementById('metamaskConnect'); + let accounts; + let nonce = 0; + + const connectButton = async () => { + if (!MetaMaskOnboarding.isMetaMaskInstalled()) { + onboardButton.innerText = 'Click here to install MetaMask!'; + onboardButton.onclick = () => { + onboardButton.classList.add('is-loading'); + onboardButton.disabled = true; + onboarding.startOnboarding(); + }; + } else if (accounts && accounts.length > 0) { + onboardButton.classList.remove('is-loading'); + onboardButton.disabled = false; + onboarding.stopOnboarding(); + } else { + onboardButton.onclick = async () => { + onboardButton.classList.add('is-loading'); + onboardButton.disabled = true; + let userExists; + const allAccounts = await window.ethereum.request({ + method: 'eth_requestAccounts', + }); + await fetch('/api/v1/user_exists?public_address=' + allAccounts[0]) + .then((resp) => resp.json()) + .then(function(data) { + if (!data['success']) { + console.log('error checking user_exists!') + return + } + console.log(data); + nonce = data['nonce']; + }) + + const msg = 'Authentication request from SuchWowX app! Verifying message with nonce ' + nonce + const signedData = await window.ethereum.request({ + method: 'personal_sign', + params: [msg, allAccounts[0]] + }); + console.log(`Signing data with msg "${msg}", address "${allAccounts[0]}", signed data: ${signedData}`) + + await fetch('/api/v1/authenticate/metamask', { + method: 'POST', + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify({ + 'signed_data': signedData, + 'public_address': allAccounts[0], + 'nonce': nonce, + 'message': msg, + }) + }) + .then((resp) => resp.json()) + .then(function(data) { + console.log(data); + if (data['success']) { + window.location.href = '/'; + } + }) + } + } + }; + + connectButton(); + if (MetaMaskOnboarding.isMetaMaskInstalled()) { + window.ethereum.on('accountsChanged', (newAccounts) => { + window.location.href = '/disconnect'; + }); + } +}; diff --git a/suchwowx/templates/includes/navbar.html b/suchwowx/templates/includes/navbar.html index 12b2146..765690c 100644 --- a/suchwowx/templates/includes/navbar.html +++ b/suchwowx/templates/includes/navbar.html @@ -15,9 +15,9 @@ {% endif %} New Meme {% else %} - Connect + Connect {% endif %} {% else %} - Go Home + Go Home {% endif %} diff --git a/suchwowx/templates/includes/scripts.html b/suchwowx/templates/includes/scripts.html index 5741a57..48fdd60 100644 --- a/suchwowx/templates/includes/scripts.html +++ b/suchwowx/templates/includes/scripts.html @@ -1,6 +1,10 @@ +{% if not current_user.is_authenticated %} + + + +{% endif %} - - + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} @@ -18,92 +22,3 @@ {% endif %} {% endwith %} - -{% if not current_user.is_authenticated %} - - - -{% endif %}