get dialed in with avax in configs and frontend

main
lza_menace 3 years ago
parent 9561eb668b
commit 011674b6bd

@ -45,6 +45,7 @@ def run_migrations_offline():
target_metadata=target_metadata, target_metadata=target_metadata,
literal_binds=True, literal_binds=True,
dialect_opts={"paramstyle": "named"}, dialect_opts={"paramstyle": "named"},
render_as_batch=True
) )
with context.begin_transaction(): with context.begin_transaction():
@ -66,7 +67,8 @@ def run_migrations_online():
with connectable.connect() as connection: with connectable.connect() as connection:
context.configure( context.configure(
connection=connection, target_metadata=target_metadata connection=connection, target_metadata=target_metadata,
render_as_batch=True
) )
with context.begin_transaction(): with context.begin_transaction():

@ -0,0 +1,54 @@
"""add profile metadata ipfs and wow addy
Revision ID: c548cc54ee17
Revises: 40734564d415
Create Date: 2021-12-30 01:35:12.774067
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c548cc54ee17'
down_revision = '40734564d415'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('memes', schema=None) as batch_op:
batch_op.create_unique_constraint('memes_file_name_uniq', ['file_name'])
with op.batch_alter_table('moderators', schema=None) as batch_op:
batch_op.alter_column('user_id',
existing_type=sa.INTEGER(),
nullable=True)
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.add_column(sa.Column('ipfs_hash', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('wownero_address', sa.String(length=120), nullable=True))
batch_op.drop_constraint('users_user_id_fkey', type_='foreignkey')
batch_op.drop_column('moderator_id')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.add_column(sa.Column('moderator_id', sa.INTEGER(), nullable=True))
batch_op.create_foreign_key('users_user_id_fkey', 'moderators', ['moderator_id'], ['id'])
batch_op.drop_column('wownero_address')
batch_op.drop_column('ipfs_hash')
with op.batch_alter_table('moderators', schema=None) as batch_op:
batch_op.alter_column('user_id',
existing_type=sa.INTEGER(),
nullable=False)
with op.batch_alter_table('memes', schema=None) as batch_op:
batch_op.drop_constraint('memes_file_name_uniq', type_='unique')
# ### end Alembic commands ###

File diff suppressed because it is too large Load Diff

@ -36,6 +36,8 @@ class User(db.Model):
handle = db.Column(db.String(40), unique=True) handle = db.Column(db.String(40), unique=True)
bio = db.Column(db.String(600), nullable=True) bio = db.Column(db.String(600), nullable=True)
profile_image = db.Column(db.String(300), nullable=True) profile_image = db.Column(db.String(300), nullable=True)
ipfs_hash = db.Column(db.String(100), nullable=True)
wownero_address = db.Column(db.String(120), nullable=True)
website_url = db.Column(db.String(120), nullable=True) website_url = db.Column(db.String(120), nullable=True)
moderator = db.relationship('Moderator', back_populates='user') moderator = db.relationship('Moderator', back_populates='user')
memes = db.relationship('Meme', back_populates='user') memes = db.relationship('Meme', back_populates='user')

@ -41,6 +41,40 @@ def user_exists():
}) })
@bp.route('/update/user', methods=['POST'])
def update_user():
if not current_user.is_authenticated:
return jsonify({
'success': False,
'message': 'Must be authenticated in order to update.'
})
data = request.get_json()
_u = User.query.get(int(data['user_id']))
if _u:
if current_user.id == _u.id:
_u.wownero_address = data['wownero_address']
_u.ipfs_hash = data['ipfs_hash']
_u.handle = data['handle']
db.session.commit()
return jsonify({
'success': True,
'message': 'Updated user record.'
})
else:
return jsonify({
'success': False,
'message': 'Cannot edit another record.'
})
else:
return jsonify({
'success': False,
'message': 'User does not exist.'
})
@bp.route('/authenticate/metamask', methods=['POST']) @bp.route('/authenticate/metamask', methods=['POST'])
def authenticate_metamask(): def authenticate_metamask():
""" """

@ -7,6 +7,17 @@ async function getSignedData(publicAddress, jsonData) {
return signedData return signedData
} }
async function notif(s, t) {
new Noty({
type: t,
theme: 'relax',
layout: 'topCenter',
text: s,
timeout: 4500
}).show();
return
}
async function confirmAvalanche(){ async function confirmAvalanche(){
let debug = true; let debug = true;
let chainId; let chainId;

@ -8,7 +8,7 @@
{% if request.path == '/' %} {% if request.path == '/' %}
<a class="button is-secondary" href="{{ url_for('meta.about') }}" up-target=".container">About</a> <a class="button is-secondary" href="{{ url_for('meta.about') }}" up-target=".container">About</a>
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<a class="button is-secondary" href="{{ url_for('user.show', handle=current_user.handle) }}" up-follow=".container" up-preload>Profile</a> <a class="button is-secondary" href="{{ url_for('user.show', handle=current_user.handle) }}">Profile</a>
<a class="button is-danger" href="{{ url_for('meta.disconnect') }}">Disconnect</a> <a class="button is-danger" href="{{ url_for('meta.disconnect') }}">Disconnect</a>
{% if current_user.is_moderator() %} {% if current_user.is_moderator() %}
<a class="button is-warning" href="{{ url_for('meme.mod') }}" up-preload up-follow=".container">Mod</a> <a class="button is-warning" href="{{ url_for('meme.mod') }}" up-preload up-follow=".container">Mod</a>

@ -1,7 +1,6 @@
<script src="/static/js/main.js"></script>
<script src="/static/js/vendor/noty-3.2.0.js"></script> <script src="/static/js/vendor/noty-3.2.0.js"></script>
<script src="/static/js/main.js"></script>
{% if not current_user.is_authenticated %} {% if not current_user.is_authenticated %}
<!-- <script src="/static/js/vendor/web3-1.3.6.min.js"></script> -->
<script src="/static/js/vendor/metamask-onboarding-1.0.1.bundle.js"></script> <script src="/static/js/vendor/metamask-onboarding-1.0.1.bundle.js"></script>
<script src="/static/js/metamask.js"></script> <script src="/static/js/metamask.js"></script>
{% endif %} {% endif %}

@ -1,3 +1,4 @@
{% set is_user = current_user == user %}
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
{% include 'includes/head.html' %} {% include 'includes/head.html' %}
@ -8,31 +9,179 @@
{% include 'includes/navbar.html' %} {% include 'includes/navbar.html' %}
{% if user %} {% if user %}
<div id="screen"> <div class="screen">
<div class="screen"> <div class="columns">
<p><strong>From Avax Chain</strong></p> <div class="column is-one-third">
<p>Handle: ?</p> <img src="{{ user.get_profile_image() }}" id="profileImage" />
<img src="{{ user.get_profile_image() }}" id="profileImage" /> </div>
</br></br> <div class="column is-full">
<p><strong>From Local Database</strong></p> <p><strong>From Avax Chain</strong></p>
<p>Handle: <input type="text" placeholder="{{ user.handle }}" value="{{ user.handle }}"></input></p> <p>Handle: <span id="userHandle" class="mr-4">?</span></p>
<p>Register Date: <strong>{{ user.register_date }}</strong></p> <p>Wownero Address: <span id="wowneroAddress" class="mr-4">?</span></p>
<p>Login Date: <strong>{{ user.last_login_date }}</strong></p> <p>Profile IPFS Hash: <span id="metadataIPFSHash">?</span></p>
<p>Moderator: <strong>{{ user.is_moderator() }}</strong></p> <p>Tipped AVAX: <span id="tippedAVAX">?</span></p>
<p>Verified: <strong>{{ user.verified }}</strong></p> <p>Tipped WOWX: <span id="tippedWOWX">?</span></p>
<p>Memes Posted: <strong>{{ user.memes | length }}</strong></p> <p>Tipped WOW: <span id="tippedWOW">?</span></p>
{% if user.bio %}
<p>Bio: {{ user.bio }}</p> </br></br>
{% endif %} <p><strong>From Local Database</strong></p>
{% if user.website %} <p>
<p>Website: <a href="{{ user.website_url }}" target="_blank">{{ user.website_url }}</a></p> Handle: <input id="handleInput" type="text" placeholder="{{ user.handle }}" value="{{ user.handle }}"></input>
{% endif %} {% if is_user %}
</div> <a onclick="publishHandleAVAX()" class="publishAVAX">Publish AVAX</a>
{% endif %}
</p>
<p>
Wownero Address: <input id="wowneroAddressInput" type="text" placeholder="{{ user.wownero_address }}" value="{{ user.wownero_address }}"></input>
{% if is_user %}
<a onclick="publishWowneroAddress()" class="publishAVAX">Publish AVAX</a>
{% endif %}
</p>
<p>
Metadata IPFS Hash: <input id="metadataIPFSHashInput" type="text" placeholder="{{ user.ipfs_hash }}" value="{{ user.ipfs_hash }}"></input>
{% if is_user %}
<a onclick="publishMetadataIPFSHash()" class="publishAVAX">Publish AVAX</a>
{% endif %}
</p>
<p><a onclick="saveDB()" class="ml-2 button is-primary">Save DB</a></p>
<p>Register Date: <strong>{{ user.register_date }}</strong></p>
<p>Login Date: <strong>{{ user.last_login_date }}</strong></p>
<p>Moderator: <strong>{{ user.is_moderator() }}</strong></p>
<p>Verified: <strong>{{ user.verified }}</strong></p>
<p>Memes Posted: <strong>{{ user.memes | length }}</strong></p>
{% if user.bio %}
<p>Bio: {{ user.bio }}</p>
{% endif %}
{% if user.website %}
<p>Website: <a href="{{ user.website_url }}" target="_blank">{{ user.website_url }}</a></p>
{% endif %}
</div>
</div> </div>
</div>
{% endif %} {% endif %}
</div> </div>
</section> </section>
{% include 'includes/footer.html' %}
<script src="/static/js/vendor/web3-1.3.6.min.js"></script>
<script type="text/javascript">
let contractABI = {{ config.CONTRACT_ABI | tojson }};
let contractAddress = "{{ config.CONTRACT_ADDRESS }}";
const w3 = new Web3(Web3.givenProvider || "http://127.0.0.1:7545");
const contract = new w3.eth.Contract(contractABI, contractAddress);
async function getMetamaskAccount() {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts',
});
const account = accounts[0];
return account
}
async function saveDB() {
await fetch('{{ url_for("api.update_user" ) }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify({
'user_id': {{ user.id }},
'handle': document.getElementById('handleInput').value,
'wownero_address': document.getElementById('wowneroAddressInput').value,
'ipfs_hash': document.getElementById('metadataIPFSHashInput').value,
})
})
.then((resp) => resp.json())
.then(function(data) {
console.log(data)
if (data['success']) {
notif('Updated user information in this server\'s database', 'success');
notif('Publish to AVAX to make the data more available', 'info');
} else {
notif('There was an issue posting data to the API. Try again later.', 'error');
}
})
}
async function fetchUserProfile() {
_walletAddress = w3.utils.toChecksumAddress('{{ user.public_address }}');
const userProfile = await contract.methods.userProfile(_walletAddress).call();
document.getElementById('userHandle').innerHTML = userProfile.userHandle;
document.getElementById('wowneroAddress').innerHTML = userProfile.wowneroAddress;
document.getElementById('metadataIPFSHash').innerHTML = userProfile.metadataIPFSHash;
document.getElementById('tippedAVAX').innerHTML = userProfile.tippedAVAX;
document.getElementById('tippedWOWX').innerHTML = 0;
return
}
async function publishHandleAVAX() {
const handle = document.getElementById('handleInput').value;
if (handle == "") {
notif('Cannot publish an empty value.', 'warning');
}
const walletAddress = await getMetamaskAccount();
const gasPrice = await w3.eth.getGasPrice();
const gasLimit = await contract.methods.setUserHandle(handle).estimateGas(function(err, gas){
return gas;
});
console.log(`Attempting to update user handle ${handle} with gas limit of ${gasLimit} gas and gas price of ${gasPrice}`);
let res = await contract.methods.setUserHandle(handle).send({
from: walletAddress,
value: 0,
gasPrice: gasPrice,
gas: gasLimit
});
console.log(res);
}
async function publishWowneroAddress() {
const address = document.getElementById('wowneroAddressInput').value;
if (address == "") {
notif('Cannot publish an empty value.', 'warning');
}
const walletAddress = await getMetamaskAccount();
const gasPrice = await w3.eth.getGasPrice();
const gasLimit = await contract.methods.setUserWowneroAddress(address).estimateGas(function(err, gas){
return gas;
});
console.log(`Attempting to update Wownero address ${address} with gas limit of ${gasLimit} gas and gas price of ${gasPrice}`);
let res = await contract.methods.setUserWowneroAddress(address).send({
from: walletAddress,
value: 0,
gasPrice: gasPrice,
gas: gasLimit
});
console.log(res);
}
async function publishMetadataIPFSHash() {
const _hash = document.getElementById('metadataIPFSHashInput').value;
if (_hash == "") {
notif('Cannot publish an empty value.', 'warning');
}
const walletAddress = await getMetamaskAccount();
const gasPrice = await w3.eth.getGasPrice();
const gasLimit = await contract.methods.setUserMetadata(_hash).estimateGas(function(err, gas){
return gas;
});
console.log(`Attempting to update user metadata hash ${_hash} with gas limit of ${gasLimit} gas and gas price of ${gasPrice}`);
let res = await contract.methods.setUserMetadata(_hash).send({
from: walletAddress,
value: 0,
gasPrice: gasPrice,
gas: gasLimit
});
console.log(res);
}
window.addEventListener('DOMContentLoaded', () => {
fetchUserProfile();
});
</script>
<style>
input { width: 30%; }
</style>
</body> </body>
</html> </html>

Loading…
Cancel
Save