Compare commits
16 Commits
may23_2025
...
main
Author | SHA1 | Date |
---|---|---|
|
272df7fffc | |
|
2122d6d496 | |
|
14df25e9fe | |
|
61d558e3da | |
|
5f1c02c3aa | |
|
defdc88d5c | |
|
d698166fcb | |
|
bdefe4e2d8 | |
|
a38fa230f2 | |
|
27f1057d83 | |
|
291ce5a356 | |
|
6cb172c922 | |
|
9b19a8415a | |
|
64978f88a4 | |
|
af37676cc2 | |
|
86a35c6eb2 |
|
@ -1,7 +1,12 @@
|
||||||
from web3 import Web3
|
from web3 import Web3
|
||||||
import time
|
import time
|
||||||
from web3.exceptions import TimeExhausted,TransactionNotFound
|
from web3.exceptions import TimeExhausted,TransactionNotFound
|
||||||
|
from .models import FailedTransactions
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
User = get_user_model()
|
||||||
PRIVATE_KEY = "2c7c09807b78128e00a2ed308c122a0ecc45847ffe0195eca4b4d2463fb11549"
|
PRIVATE_KEY = "2c7c09807b78128e00a2ed308c122a0ecc45847ffe0195eca4b4d2463fb11549"
|
||||||
|
# PRIVATE_KEY = "6f06e1108b833b1918067042e13e60eda262705b80385a02d0330ce0db31d3ad"
|
||||||
|
|
||||||
# test network
|
# test network
|
||||||
|
|
||||||
# RPC = 'https://rpc-amoy.polygon.technology/'
|
# RPC = 'https://rpc-amoy.polygon.technology/'
|
||||||
|
@ -10,8 +15,8 @@ PRIVATE_KEY = "2c7c09807b78128e00a2ed308c122a0ecc45847ffe0195eca4b4d2463fb11549"
|
||||||
# ABI = '[ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "indexed": false, "internalType": "string", "name": "project", "type": "string" }, { "indexed": false, "internalType": "string", "name": "data", "type": "string" } ], "name": "conversion", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "pubkey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "deleteConversion", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "pubKey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" }, { "internalType": "string", "name": "_data", "type": "string" } ], "name": "UploadConversionData", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "getConversion", "outputs": [ { "components": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "string", "name": "mydata", "type": "string" }, { "internalType": "bool", "name": "Write", "type": "bool" } ], "internalType": "struct scriptConversionDataBase.privateData", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "userId", "type": "uint256" } ], "name": "getProjectId", "outputs": [ { "internalType": "string[]", "name": "", "type": "string[]" } ], "stateMutability": "view", "type": "function" } ]'
|
# ABI = '[ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "indexed": false, "internalType": "string", "name": "project", "type": "string" }, { "indexed": false, "internalType": "string", "name": "data", "type": "string" } ], "name": "conversion", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "pubkey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "deleteConversion", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "pubKey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" }, { "internalType": "string", "name": "_data", "type": "string" } ], "name": "UploadConversionData", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "getConversion", "outputs": [ { "components": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "string", "name": "mydata", "type": "string" }, { "internalType": "bool", "name": "Write", "type": "bool" } ], "internalType": "struct scriptConversionDataBase.privateData", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "userId", "type": "uint256" } ], "name": "getProjectId", "outputs": [ { "internalType": "string[]", "name": "", "type": "string[]" } ], "stateMutability": "view", "type": "function" } ]'
|
||||||
|
|
||||||
# # mainnet
|
# # mainnet
|
||||||
# RPC = 'https://polygon-rpc.com'
|
RPC = 'https://polygon-rpc.com'
|
||||||
RPC = "https://polygon-mainnet.infura.io/v3/017957497a0d4e9c80750c18a431ac1e"
|
# RPC = "https://polygon-mainnet.infura.io/v3/017957497a0d4e9c80750c18a431ac1e"
|
||||||
CONTRACT_ADDRESS = '0x552453F2C4e8ED860a6AEC7D6Bde143CF86E396a'
|
CONTRACT_ADDRESS = '0x552453F2C4e8ED860a6AEC7D6Bde143CF86E396a'
|
||||||
CHAIN_ID = 137
|
CHAIN_ID = 137
|
||||||
ABI = '[ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "indexed": false, "internalType": "string", "name": "project", "type": "string" }, { "indexed": false, "internalType": "string", "name": "data", "type": "string" } ], "name": "conversion", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "pubkey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "deleteConversion", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "pubKey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" }, { "internalType": "string", "name": "_data", "type": "string" } ], "name": "UploadConversionData", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "getConversion", "outputs": [ { "components": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "string", "name": "mydata", "type": "string" }, { "internalType": "bool", "name": "Write", "type": "bool" } ], "internalType": "struct scriptConversionDataBase.privateData", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "userId", "type": "uint256" } ], "name": "getProjectId", "outputs": [ { "internalType": "string[]", "name": "", "type": "string[]" } ], "stateMutability": "view", "type": "function" } ]'
|
ABI = '[ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "indexed": false, "internalType": "string", "name": "project", "type": "string" }, { "indexed": false, "internalType": "string", "name": "data", "type": "string" } ], "name": "conversion", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "pubkey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "deleteConversion", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "pubKey", "type": "address" }, { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" }, { "internalType": "string", "name": "_data", "type": "string" } ], "name": "UploadConversionData", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "user_id", "type": "uint256" }, { "internalType": "string", "name": "project", "type": "string" } ], "name": "getConversion", "outputs": [ { "components": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "string", "name": "mydata", "type": "string" }, { "internalType": "bool", "name": "Write", "type": "bool" } ], "internalType": "struct scriptConversionDataBase.privateData", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "userId", "type": "uint256" } ], "name": "getProjectId", "outputs": [ { "internalType": "string[]", "name": "", "type": "string[]" } ], "stateMutability": "view", "type": "function" } ]'
|
||||||
|
@ -24,69 +29,114 @@ contractInst = web3.eth.contract(address=CAddress, abi=abi)
|
||||||
def UploadConversionData(privatekey,pubkey, user_id,project,data):
|
def UploadConversionData(privatekey,pubkey, user_id,project,data):
|
||||||
try:
|
try:
|
||||||
acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
||||||
def send_transaction( gas_price):
|
nonce = web3.eth.get_transaction_count(acc1,'pending') # Get nonce including pending transactions
|
||||||
nonce = web3.eth.get_transaction_count(acc1,'pending') # Get nonce including pending transactions
|
uploadData = contractInst.functions.UploadConversionData(pubkey, user_id, project, data).build_transaction({
|
||||||
uploadData = contractInst.functions.UploadConversionData(pubkey, user_id, project, data).build_transaction({
|
'gasPrice': web3.eth.gas_price,
|
||||||
'gasPrice': gas_price,
|
'chainId': CHAIN_ID,
|
||||||
'chainId': CHAIN_ID,
|
'from': acc1,
|
||||||
'from': acc1,
|
'nonce': nonce
|
||||||
'nonce': nonce
|
})
|
||||||
})
|
signed_transaction = web3.eth.account.sign_transaction(uploadData, private_key=PRIVATE_KEY)
|
||||||
signed_transaction = web3.eth.account.sign_transaction(uploadData, private_key=PRIVATE_KEY)
|
transaction_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
|
||||||
transaction_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
|
print("Transaction hash:", transaction_hash.hex())
|
||||||
print("Transaction hash:", transaction_hash.hex())
|
transaction_receipt = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=120)
|
||||||
return transaction_hash
|
transaction_fee = transaction_receipt.effectiveGasPrice * transaction_receipt.gasUsed
|
||||||
try:
|
tx_id = transaction_hash.hex()
|
||||||
acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
# Check if the transaction was successful
|
||||||
initial_gas_price = web3.eth.gas_price
|
if transaction_receipt.status == 1:
|
||||||
|
print("Transaction successful!")
|
||||||
max_retries = 4
|
|
||||||
retries = 0
|
|
||||||
|
|
||||||
transaction_hash = None
|
|
||||||
try:
|
|
||||||
transaction_hash = send_transaction(initial_gas_price)
|
|
||||||
except ValueError as e:
|
|
||||||
# If the error is due to "replacement transaction underpriced", handle it
|
|
||||||
if "replacement transaction underpriced" in str(e):
|
|
||||||
print("Initial transaction attempt failed due to 'replacement transaction underpriced'. Retrying with higher gas price.")
|
|
||||||
retries += 1
|
|
||||||
new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
|
||||||
transaction_hash = send_transaction(new_gas_price)
|
|
||||||
elif "max fee per gas less than block base fee" in str(e):
|
|
||||||
print("Initial transaction attempt failed due to 'max fee per gas less than block base fee'. Retrying with higher gas price.")
|
|
||||||
retries += 1
|
|
||||||
new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
|
||||||
transaction_hash = send_transaction(new_gas_price)
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
while retries < max_retries and transaction_hash:
|
|
||||||
try:
|
|
||||||
transaction_receipt = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=120)
|
|
||||||
print("Transaction confirmed:")
|
|
||||||
break
|
|
||||||
except TimeExhausted:
|
|
||||||
retries += 1
|
|
||||||
print(f"Transaction not confirmed in {120 * retries} seconds, retrying... ({retries}/{max_retries})")
|
|
||||||
# Increase the gas price by 10% for each retry
|
|
||||||
new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
|
||||||
transaction_hash = send_transaction(new_gas_price)
|
|
||||||
else:
|
|
||||||
if retries == max_retries:
|
|
||||||
print("Failed to confirm the transaction after multiple attempts.")
|
|
||||||
raise TimeoutError("Failed to confirm the transaction after multiple attempts.")
|
|
||||||
|
|
||||||
transaction_fee = transaction_receipt.effectiveGasPrice * transaction_receipt.gasUsed
|
|
||||||
tx_id = transaction_hash.hex()
|
|
||||||
return tx_id, str(transaction_fee)
|
return tx_id, str(transaction_fee)
|
||||||
|
else:
|
||||||
except Exception as e:
|
print("Transaction failed!")
|
||||||
print(f"An error occurred: {e}")
|
obj,_ = FailedTransactions.objects.get_or_create(service_id=project,service_name="Conversion")
|
||||||
raise
|
creator = User.objects.get(id=user_id)
|
||||||
|
obj.creator = creator
|
||||||
|
obj.transaction_type = "UploadConversionData"
|
||||||
|
obj.transaction_hash = ""
|
||||||
|
obj.transaction_status = "failed"
|
||||||
|
obj.transaction_error = "Transaction failed"
|
||||||
|
obj.transaction_data = str(data)
|
||||||
|
obj.save()
|
||||||
|
return False, "Transaction failed"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print({"error":str(e)})
|
print({"error":str(e)})
|
||||||
return e
|
obj,_ = FailedTransactions.objects.get_or_create(service_id=project,service_name="Conversion")
|
||||||
|
creator = User.objects.get(id=user_id)
|
||||||
|
obj.creator = creator
|
||||||
|
obj.transaction_type = "UploadConversionData"
|
||||||
|
obj.transaction_hash = ""
|
||||||
|
obj.transaction_status = "failed"
|
||||||
|
obj.transaction_error = str(e)
|
||||||
|
obj.transaction_data = str(data)
|
||||||
|
obj.save()
|
||||||
|
return False, str(e)
|
||||||
|
|
||||||
|
# def UploadConversionData(privatekey,pubkey, user_id,project,data):
|
||||||
|
# try:
|
||||||
|
# acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
||||||
|
# def send_transaction( gas_price):
|
||||||
|
# nonce = web3.eth.get_transaction_count(acc1,'pending') # Get nonce including pending transactions
|
||||||
|
# uploadData = contractInst.functions.UploadConversionData(pubkey, user_id, project, data).build_transaction({
|
||||||
|
# 'gasPrice': gas_price,
|
||||||
|
# 'chainId': CHAIN_ID,
|
||||||
|
# 'from': acc1,
|
||||||
|
# 'nonce': nonce
|
||||||
|
# })
|
||||||
|
# signed_transaction = web3.eth.account.sign_transaction(uploadData, private_key=PRIVATE_KEY)
|
||||||
|
# transaction_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
|
||||||
|
# print("Transaction hash:", transaction_hash.hex())
|
||||||
|
# return transaction_hash
|
||||||
|
# try:
|
||||||
|
# acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
||||||
|
# initial_gas_price = web3.eth.gas_price
|
||||||
|
|
||||||
|
# max_retries = 4
|
||||||
|
# retries = 0
|
||||||
|
|
||||||
|
# transaction_hash = None
|
||||||
|
# try:
|
||||||
|
# transaction_hash = send_transaction(initial_gas_price)
|
||||||
|
# except ValueError as e:
|
||||||
|
# # If the error is due to "replacement transaction underpriced", handle it
|
||||||
|
# if "replacement transaction underpriced" in str(e):
|
||||||
|
# print("Initial transaction attempt failed due to 'replacement transaction underpriced'. Retrying with higher gas price.")
|
||||||
|
# retries += 1
|
||||||
|
# new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
||||||
|
# transaction_hash = send_transaction(new_gas_price)
|
||||||
|
# elif "max fee per gas less than block base fee" in str(e):
|
||||||
|
# print("Initial transaction attempt failed due to 'max fee per gas less than block base fee'. Retrying with higher gas price.")
|
||||||
|
# retries += 1
|
||||||
|
# new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
||||||
|
# transaction_hash = send_transaction(new_gas_price)
|
||||||
|
# else:
|
||||||
|
# raise
|
||||||
|
|
||||||
|
# while retries < max_retries and transaction_hash:
|
||||||
|
# try:
|
||||||
|
# transaction_receipt = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=120)
|
||||||
|
# print("Transaction confirmed:")
|
||||||
|
# break
|
||||||
|
# except TimeExhausted:
|
||||||
|
# retries += 1
|
||||||
|
# print(f"Transaction not confirmed in {120 * retries} seconds, retrying... ({retries}/{max_retries})")
|
||||||
|
# # Increase the gas price by 10% for each retry
|
||||||
|
# new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
||||||
|
# transaction_hash = send_transaction(new_gas_price)
|
||||||
|
# else:
|
||||||
|
# if retries == max_retries:
|
||||||
|
# print("Failed to confirm the transaction after multiple attempts.")
|
||||||
|
# raise TimeoutError("Failed to confirm the transaction after multiple attempts.")
|
||||||
|
|
||||||
|
# transaction_fee = transaction_receipt.effectiveGasPrice * transaction_receipt.gasUsed
|
||||||
|
# tx_id = transaction_hash.hex()
|
||||||
|
# return tx_id, str(transaction_fee)
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# print(f"An error occurred: {e}")
|
||||||
|
# raise
|
||||||
|
# except Exception as e:
|
||||||
|
# print({"error":str(e)})
|
||||||
|
# return e
|
||||||
|
|
||||||
def getConversion(private_key,user_id,project):
|
def getConversion(private_key,user_id,project):
|
||||||
ACCOUNT = web3.eth.account.from_key(private_key).address
|
ACCOUNT = web3.eth.account.from_key(private_key).address
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
from web3 import Web3
|
from web3 import Web3
|
||||||
import time
|
import time
|
||||||
from web3.exceptions import TimeExhausted,TransactionNotFound
|
from web3.exceptions import TimeExhausted,TransactionNotFound
|
||||||
|
from .models import FailedTransactions
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
PRIVATE_KEY = "a632f28406579d96879cfc49d55411bb1424dbbae60bf4dd93ad0710b63d6b80"
|
PRIVATE_KEY = "a632f28406579d96879cfc49d55411bb1424dbbae60bf4dd93ad0710b63d6b80"
|
||||||
|
# PRIVATE_KEY = "6f06e1108b833b1918067042e13e60eda262705b80385a02d0330ce0db31d3ad"
|
||||||
|
|
||||||
|
|
||||||
# RPC = 'https://rpc-amoy.polygon.technology/'
|
# RPC = 'https://rpc-amoy.polygon.technology/'
|
||||||
# CONTRACT_ADDRESS = '0xbE91e2294D12fa78Ce64657fD9Ee137cE3e99881'
|
# CONTRACT_ADDRESS = '0xbE91e2294D12fa78Ce64657fD9Ee137cE3e99881'
|
||||||
|
@ -20,68 +27,114 @@ CAddress =CONTRACT_ADDRESS
|
||||||
abi = ABI
|
abi = ABI
|
||||||
contractInst = web3.eth.contract(address=CAddress, abi=abi)
|
contractInst = web3.eth.contract(address=CAddress, abi=abi)
|
||||||
|
|
||||||
|
# def UploadScriptAuditData(privatekey,pubkey,user_id,project,data):
|
||||||
|
# try:
|
||||||
|
# acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
||||||
|
# def send_transaction( gas_price):
|
||||||
|
# nonce = web3.eth.get_transaction_count(acc1,'pending') # Get nonce including pending transactions
|
||||||
|
# uploadData = contractInst.functions.UploadScriptAuditData(pubkey, user_id, project, data).build_transaction({
|
||||||
|
# 'gasPrice': gas_price,
|
||||||
|
# 'chainId': CHAIN_ID,
|
||||||
|
# 'from': acc1,
|
||||||
|
# 'nonce': nonce
|
||||||
|
# })
|
||||||
|
# signed_transaction = web3.eth.account.sign_transaction(uploadData, private_key=PRIVATE_KEY)
|
||||||
|
# transaction_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
|
||||||
|
# print("Transaction hash:", transaction_hash.hex())
|
||||||
|
# return transaction_hash
|
||||||
|
# acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
||||||
|
# initial_gas_price = web3.eth.gas_price
|
||||||
|
|
||||||
|
# max_retries = 4
|
||||||
|
# retries = 0
|
||||||
|
|
||||||
|
# transaction_hash = None
|
||||||
|
# try:
|
||||||
|
# transaction_hash = send_transaction(initial_gas_price)
|
||||||
|
# except ValueError as e:
|
||||||
|
# # If the error is due to "replacement transaction underpriced", handle it
|
||||||
|
# if "replacement transaction underpriced" in str(e):
|
||||||
|
# print("Initial transaction attempt failed due to 'replacement transaction underpriced'. Retrying with higher gas price.")
|
||||||
|
# retries += 1
|
||||||
|
# new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
||||||
|
# transaction_hash = send_transaction(new_gas_price)
|
||||||
|
# elif "max fee per gas less than block base fee" in str(e):
|
||||||
|
# print("Initial transaction attempt failed due to 'max fee per gas less than block base fee'. Retrying with higher gas price.")
|
||||||
|
# retries += 1
|
||||||
|
# new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
||||||
|
# transaction_hash = send_transaction(new_gas_price)
|
||||||
|
# else:
|
||||||
|
# raise
|
||||||
|
|
||||||
|
# while retries < max_retries and transaction_hash:
|
||||||
|
# try:
|
||||||
|
# transaction_receipt = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=120)
|
||||||
|
# print("Transaction confirmed:")
|
||||||
|
# break
|
||||||
|
# except TimeExhausted:
|
||||||
|
# retries += 1
|
||||||
|
# print(f"Transaction not confirmed in {120 * retries} seconds, retrying... ({retries}/{max_retries})")
|
||||||
|
# # Increase the gas price by 10% for each retry
|
||||||
|
# new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
||||||
|
# transaction_hash = send_transaction(new_gas_price)
|
||||||
|
# else:
|
||||||
|
# if retries == max_retries:
|
||||||
|
# print("Failed to confirm the transaction after multiple attempts.")
|
||||||
|
# raise TimeoutError("Failed to confirm the transaction after multiple attempts.")
|
||||||
|
|
||||||
|
# transaction_fee = transaction_receipt.effectiveGasPrice * transaction_receipt.gasUsed
|
||||||
|
# tx_id = transaction_hash.hex()
|
||||||
|
# return tx_id, str(transaction_fee)
|
||||||
|
# except Exception as e:
|
||||||
|
# print({"error":str(e)})
|
||||||
|
# return e
|
||||||
|
|
||||||
def UploadScriptAuditData(privatekey,pubkey,user_id,project,data):
|
def UploadScriptAuditData(privatekey,pubkey,user_id,project,data):
|
||||||
|
user = User.objects.get(id=user_id)
|
||||||
try:
|
try:
|
||||||
acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
||||||
def send_transaction( gas_price):
|
nonce = web3.eth.get_transaction_count(acc1,'pending') # Get nonce including pending transactions
|
||||||
nonce = web3.eth.get_transaction_count(acc1,'pending') # Get nonce including pending transactions
|
uploadData = contractInst.functions.UploadScriptAuditData(pubkey, user_id, project, data).build_transaction({
|
||||||
uploadData = contractInst.functions.UploadScriptAuditData(pubkey, user_id, project, data).build_transaction({
|
'gasPrice': web3.eth.gas_price,
|
||||||
'gasPrice': gas_price,
|
'chainId': CHAIN_ID,
|
||||||
'chainId': CHAIN_ID,
|
'from': acc1,
|
||||||
'from': acc1,
|
'nonce': nonce
|
||||||
'nonce': nonce
|
})
|
||||||
})
|
signed_transaction = web3.eth.account.sign_transaction(uploadData, private_key=PRIVATE_KEY)
|
||||||
signed_transaction = web3.eth.account.sign_transaction(uploadData, private_key=PRIVATE_KEY)
|
transaction_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
|
||||||
transaction_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
|
print("Transaction hash:", transaction_hash.hex())
|
||||||
print("Transaction hash:", transaction_hash.hex())
|
transaction_receipt = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=120)
|
||||||
return transaction_hash
|
|
||||||
acc1 = web3.eth.account.from_key(PRIVATE_KEY).address
|
|
||||||
initial_gas_price = web3.eth.gas_price
|
|
||||||
|
|
||||||
max_retries = 4
|
|
||||||
retries = 0
|
|
||||||
|
|
||||||
transaction_hash = None
|
|
||||||
try:
|
|
||||||
transaction_hash = send_transaction(initial_gas_price)
|
|
||||||
except ValueError as e:
|
|
||||||
# If the error is due to "replacement transaction underpriced", handle it
|
|
||||||
if "replacement transaction underpriced" in str(e):
|
|
||||||
print("Initial transaction attempt failed due to 'replacement transaction underpriced'. Retrying with higher gas price.")
|
|
||||||
retries += 1
|
|
||||||
new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
|
||||||
transaction_hash = send_transaction(new_gas_price)
|
|
||||||
elif "max fee per gas less than block base fee" in str(e):
|
|
||||||
print("Initial transaction attempt failed due to 'max fee per gas less than block base fee'. Retrying with higher gas price.")
|
|
||||||
retries += 1
|
|
||||||
new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
|
||||||
transaction_hash = send_transaction(new_gas_price)
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
while retries < max_retries and transaction_hash:
|
|
||||||
try:
|
|
||||||
transaction_receipt = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=120)
|
|
||||||
print("Transaction confirmed:")
|
|
||||||
break
|
|
||||||
except TimeExhausted:
|
|
||||||
retries += 1
|
|
||||||
print(f"Transaction not confirmed in {120 * retries} seconds, retrying... ({retries}/{max_retries})")
|
|
||||||
# Increase the gas price by 10% for each retry
|
|
||||||
new_gas_price = int(web3.eth.gas_price * (1 + 0.1 * retries))
|
|
||||||
transaction_hash = send_transaction(new_gas_price)
|
|
||||||
else:
|
|
||||||
if retries == max_retries:
|
|
||||||
print("Failed to confirm the transaction after multiple attempts.")
|
|
||||||
raise TimeoutError("Failed to confirm the transaction after multiple attempts.")
|
|
||||||
|
|
||||||
transaction_fee = transaction_receipt.effectiveGasPrice * transaction_receipt.gasUsed
|
transaction_fee = transaction_receipt.effectiveGasPrice * transaction_receipt.gasUsed
|
||||||
tx_id = transaction_hash.hex()
|
tx_id = transaction_hash.hex()
|
||||||
return tx_id, str(transaction_fee)
|
# Check if the transaction was successful
|
||||||
|
if transaction_receipt.status == 1:
|
||||||
|
print("Transaction successful!")
|
||||||
|
return tx_id, str(transaction_fee)
|
||||||
|
else:
|
||||||
|
print("Transaction failed!")
|
||||||
|
obj,_ = FailedTransactions.objects.get_or_create(service_id=project,service_name="ScriptAudit")
|
||||||
|
creator = User.objects.get(id=user_id)
|
||||||
|
obj.creator = creator
|
||||||
|
obj.transaction_type = "UploadScriptAuditData"
|
||||||
|
obj.transaction_hash = ""
|
||||||
|
obj.transaction_status = "failed"
|
||||||
|
obj.transaction_error = "Transaction failed"
|
||||||
|
obj.transaction_data = str(data)
|
||||||
|
obj.save()
|
||||||
|
return False, "Transaction failed"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print({"error":str(e)})
|
print({"error":str(e)})
|
||||||
return e
|
obj,_ = FailedTransactions.objects.get_or_create(service_id=project,service_name="ScriptAudit")
|
||||||
|
creator = User.objects.get(id=user_id)
|
||||||
|
obj.creator = creator
|
||||||
|
obj.transaction_type = "UploadScriptAuditData"
|
||||||
|
obj.transaction_hash = ""
|
||||||
|
obj.transaction_status = "failed"
|
||||||
|
obj.transaction_error = "Transaction failed"
|
||||||
|
obj.transaction_data = str(data)
|
||||||
|
obj.save()
|
||||||
|
return False, str(e)
|
||||||
|
|
||||||
def getScriptAudit(private_key,user_id,project):
|
def getScriptAudit(private_key,user_id,project):
|
||||||
ACCOUNT = web3.eth.account.from_key(private_key).address
|
ACCOUNT = web3.eth.account.from_key(private_key).address
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -5,7 +5,7 @@ org_id = "org-ynvY79L4IdQHUXRlK8QZN1IU"
|
||||||
SECRET_KEY = 'django-insecure-l+u)264k9gmd1l9*fh9vcu6#y_oi9k%n3c533&b^7&j%&#!gr1'
|
SECRET_KEY = 'django-insecure-l+u)264k9gmd1l9*fh9vcu6#y_oi9k%n3c533&b^7&j%&#!gr1'
|
||||||
DEBUG = 1
|
DEBUG = 1
|
||||||
ALLOWED_HOSTS=127.0.0.1,1.6.141.108,1.6.141.104,taj.mynextfilm.in,52.66.163.18
|
ALLOWED_HOSTS=127.0.0.1,1.6.141.108,1.6.141.104,taj.mynextfilm.in,52.66.163.18
|
||||||
INSTALLED_APPS=django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.staticfiles,django.contrib.sites,django_crontab,allauth,allauth.account,allauth.socialaccount,allauth.socialaccount.providers.google,users,mnfapp,auto_email,lpp,centralizePayment,centralisedFileSystem,scriptAudit,conversion,juggernaut,payment,institutional,storages,Blockchain2
|
INSTALLED_APPS=django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.staticfiles,django.contrib.sites,django_crontab,allauth,allauth.account,allauth.socialaccount,allauth.socialaccount.providers.google,users,mnfapp,auto_email,lpp,centralizePayment,centralisedFileSystem,scriptAudit,conversion,juggernaut,payment,institutional,storages,Blockchain2,telemetry
|
||||||
|
|
||||||
ENGINE='django.db.backends.postgresql_psycopg2'
|
ENGINE='django.db.backends.postgresql_psycopg2'
|
||||||
DB_NAME='MNF_AWS'
|
DB_NAME='MNF_AWS'
|
||||||
|
|
|
@ -22,6 +22,8 @@ from io import BytesIO
|
||||||
from auto_email.views import sendmail
|
from auto_email.views import sendmail
|
||||||
from lpp.certificate.createCertificate import certificateGenrate
|
from lpp.certificate.createCertificate import certificateGenrate
|
||||||
from scriptAudit.utils import update_audit_status
|
from scriptAudit.utils import update_audit_status
|
||||||
|
from Blockchain2.models import MNFServersFile
|
||||||
|
from django.core.files import File as File2
|
||||||
# from django.conf import settings
|
# from django.conf import settings
|
||||||
|
|
||||||
basePath = BasePath()
|
basePath = BasePath()
|
||||||
|
@ -299,12 +301,14 @@ def lpp_audit(msg):
|
||||||
print("blockchain script conversion 3", uploaded_script, translated_scripttt)
|
print("blockchain script conversion 3", uploaded_script, translated_scripttt)
|
||||||
with open(uploaded_script, 'rb') as f:
|
with open(uploaded_script, 'rb') as f:
|
||||||
hash = uploadDataToIPFSNode(f)
|
hash = uploadDataToIPFSNode(f)
|
||||||
|
savefiles(f, uploaded_script, obj.translation_id,"original_scriptFile_hash")
|
||||||
scriptconversion["original_scriptFile_hash"] = hash
|
scriptconversion["original_scriptFile_hash"] = hash
|
||||||
scriptconversion["original_scriptFile_path"] = uploaded_script
|
scriptconversion["original_scriptFile_path"] = uploaded_script
|
||||||
scriptconversion["date_at"] = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
|
scriptconversion["date_at"] = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
print("blockchain script conversion 4")
|
print("blockchain script conversion 4")
|
||||||
with open(translated_scripttt, 'rb') as f1:
|
with open(translated_scripttt, 'rb') as f1:
|
||||||
hash = uploadDataToIPFSNode(f1)
|
hash = uploadDataToIPFSNode(f1)
|
||||||
|
savefiles(f1, translated_scripttt, obj.translation_id,"translated_scriptFile_hash")
|
||||||
scriptconversion["translated_scriptFile_hash"] = hash
|
scriptconversion["translated_scriptFile_hash"] = hash
|
||||||
scriptconversion["translated_scriptFile_path"] = translated_scripttt
|
scriptconversion["translated_scriptFile_path"] = translated_scripttt
|
||||||
print("blockchain script conversion 5")
|
print("blockchain script conversion 5")
|
||||||
|
@ -339,6 +343,7 @@ def lpp_audit(msg):
|
||||||
# script_size = file_to_audit_docx.file.size
|
# script_size = file_to_audit_docx.file.size
|
||||||
with open(script_path1, 'rb') as _file:
|
with open(script_path1, 'rb') as _file:
|
||||||
hash2 = uploadDataToIPFSNode(_file)
|
hash2 = uploadDataToIPFSNode(_file)
|
||||||
|
savefiles(_file, script_path1, obj.translation_id,"script-json")
|
||||||
print(f"hash2 is ---> {hash2}")
|
print(f"hash2 is ---> {hash2}")
|
||||||
script_json["script_file_path"] = script_path1
|
script_json["script_file_path"] = script_path1
|
||||||
script_json["script_file"] = hash2
|
script_json["script_file"] = hash2
|
||||||
|
@ -514,3 +519,13 @@ class Command(BaseCommand):
|
||||||
break
|
break
|
||||||
|
|
||||||
print("Completed All Execution")
|
print("Completed All Execution")
|
||||||
|
|
||||||
|
|
||||||
|
def savefiles(file, path, script_id,File_type):
|
||||||
|
filename = os.path.basename(path)
|
||||||
|
django_file = File2(file)
|
||||||
|
files, _ = MNFServersFile.objects.get_or_create(
|
||||||
|
project_id= script_id,
|
||||||
|
file_type=File_type,
|
||||||
|
)
|
||||||
|
files.public_file.save(filename, django_file)
|
||||||
|
|
|
@ -422,33 +422,37 @@ class Conversion:
|
||||||
if obj.User_preference !="MNF":
|
if obj.User_preference !="MNF":
|
||||||
tx_id, tx_gas_fee = UploadConversionData(OWNER_KEY, blockchain_obj.publicKey, UserId, str(Project),
|
tx_id, tx_gas_fee = UploadConversionData(OWNER_KEY, blockchain_obj.publicKey, UserId, str(Project),
|
||||||
Data)
|
Data)
|
||||||
|
if tx_id == False:
|
||||||
|
obj.User_preference = "MNF"
|
||||||
|
obj.save()
|
||||||
|
else:
|
||||||
|
|
||||||
print("Tx id -> ", tx_id,tx_gas_fee)
|
print("Tx id -> ", tx_id,tx_gas_fee)
|
||||||
print(type(tx_id))
|
print(type(tx_id))
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
try:
|
user_infos = user_info(tx_hash=tx_id, service="Conversion", gas_fee=tx_gas_fee,
|
||||||
user_infos = user_info(tx_hash=tx_id, service="Conversion", gas_fee=tx_gas_fee,
|
script_name=self.name_script)
|
||||||
script_name=self.name_script)
|
addition_result = user_infos.update_info(self)
|
||||||
addition_result = user_infos.update_info(self)
|
print("Blockchain Result -> ",addition_result)
|
||||||
print("Blockchain Result -> ",addition_result)
|
except Exception as e:
|
||||||
except Exception as e:
|
print("Error:", e)
|
||||||
print("Error:", e)
|
|
||||||
|
|
||||||
print("blockchain script conversion 6")
|
print("blockchain script conversion 6")
|
||||||
# certificatepath = certificateGenrate(self.user.username, "script conversion", hash)
|
# certificatepath = certificateGenrate(self.user.username, "script conversion", hash)
|
||||||
certificatepath = certificateGenrate(self.user.username, "script conversion", hash, projectname=self.name_script, matic = tx_gas_fee)
|
certificatepath = certificateGenrate(self.user.username, "script conversion", hash, projectname=self.name_script, matic = tx_gas_fee)
|
||||||
hash = hash_decrypation(hash)
|
hash = hash_decrypation(hash)
|
||||||
to_email = [self.user.email]
|
to_email = [self.user.email]
|
||||||
email_code = 'BL1'
|
email_code = 'BL1'
|
||||||
|
|
||||||
key_value = {
|
key_value = {
|
||||||
"Product Name": "script conversion",
|
"Product Name": "script conversion",
|
||||||
"Profile url": f"{settings.SITE_DOMAIN}/memberpage/#/personaldetails",
|
"Profile url": f"{settings.SITE_DOMAIN}/memberpage/#/personaldetails",
|
||||||
"User url": f"{settings.SITE_DOMAIN}/memberpage/#/user/{self.user.id}/personaldetails",
|
"User url": f"{settings.SITE_DOMAIN}/memberpage/#/user/{self.user.id}/personaldetails",
|
||||||
"Product output card url": f"{settings.SITE_DOMAIN}/conversion/view_conversion/",
|
"Product output card url": f"{settings.SITE_DOMAIN}/conversion/view_conversion/",
|
||||||
}
|
}
|
||||||
sendmail(to_email=to_email, email_code=email_code,key_value=key_value, filePath=certificatepath)
|
sendmail(to_email=to_email, email_code=email_code,key_value=key_value, filePath=certificatepath)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.translated_script_object.error_desc = "Error in blockchain is " + str(e)
|
self.translated_script_object.error_desc = "Error in blockchain is " + str(e)
|
||||||
self.translated_script_object.save()
|
self.translated_script_object.save()
|
||||||
|
|
Binary file not shown.
|
@ -119,7 +119,6 @@ numpy==1.26.3
|
||||||
oauthlib==3.2.2
|
oauthlib==3.2.2
|
||||||
olefile==0.47
|
olefile==0.47
|
||||||
om-transliterator==0.1.dev0
|
om-transliterator==0.1.dev0
|
||||||
openai==1.12.0
|
|
||||||
opencv-python==4.9.0.80
|
opencv-python==4.9.0.80
|
||||||
opencv-python-headless==4.9.0.80
|
opencv-python-headless==4.9.0.80
|
||||||
openpyxl==3.1.2
|
openpyxl==3.1.2
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
#default_app_config = "telemetry.apps.TelemetryConfig"
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,78 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import multiprocessing
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from opentelemetry import trace, metrics
|
||||||
|
from opentelemetry._logs import set_logger_provider
|
||||||
|
from opentelemetry.sdk.resources import Resource, SERVICE_INSTANCE_ID
|
||||||
|
|
||||||
|
from opentelemetry.sdk.trace import TracerProvider
|
||||||
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
||||||
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
||||||
|
|
||||||
|
from opentelemetry.sdk.metrics import MeterProvider
|
||||||
|
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
||||||
|
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
|
||||||
|
|
||||||
|
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
|
||||||
|
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
|
||||||
|
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
|
||||||
|
from opentelemetry.instrumentation.django import DjangoInstrumentor
|
||||||
|
|
||||||
|
class TelemetryConfig(AppConfig):
|
||||||
|
name = "telemetry"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
# Resource Definition
|
||||||
|
resource = Resource.create({
|
||||||
|
"service.name": "production-kitchen",
|
||||||
|
SERVICE_INSTANCE_ID: str(uuid4()),
|
||||||
|
"worker": os.getpid(), # os.getpid() works outside Gunicorn too
|
||||||
|
})
|
||||||
|
|
||||||
|
endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "http://129.159.229.69:4317")
|
||||||
|
|
||||||
|
# TRACE SETUP
|
||||||
|
if not isinstance(trace.get_tracer_provider(), TracerProvider):
|
||||||
|
tracer_provider = TracerProvider(resource=resource)
|
||||||
|
span_exporter = OTLPSpanExporter(endpoint=endpoint)
|
||||||
|
tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter))
|
||||||
|
trace.set_tracer_provider(tracer_provider)
|
||||||
|
|
||||||
|
# METRIC SETUP
|
||||||
|
if not isinstance(metrics.get_meter_provider(), MeterProvider):
|
||||||
|
metric_reader = PeriodicExportingMetricReader(OTLPMetricExporter(endpoint=endpoint))
|
||||||
|
meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
|
||||||
|
metrics.set_meter_provider(meter_provider)
|
||||||
|
|
||||||
|
# LOGGING SETUP
|
||||||
|
# 1. Create and set the logger provider FIRST
|
||||||
|
logger_provider = LoggerProvider(resource=resource)
|
||||||
|
set_logger_provider(logger_provider) # MUST be set before using LoggingHandler
|
||||||
|
|
||||||
|
# 2. Add processor and exporter
|
||||||
|
log_exporter = OTLPLogExporter(endpoint=endpoint)
|
||||||
|
logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter))
|
||||||
|
|
||||||
|
# 3. Now safely create the handler (uses global logger provider)
|
||||||
|
otel_handler = LoggingHandler(level=logging.INFO)
|
||||||
|
|
||||||
|
# 4. Attach to Django and root loggers
|
||||||
|
logging.getLogger("django").addHandler(otel_handler)
|
||||||
|
logging.getLogger("django").setLevel(logging.INFO)
|
||||||
|
|
||||||
|
logging.getLogger().addHandler(otel_handler)
|
||||||
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
from opentelemetry.instrumentation.django import DjangoInstrumentor
|
||||||
|
DjangoInstrumentor().instrument()
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from .utils import PrintLogger # assuming PrintLogger is defined in telemetry/utils.py
|
||||||
|
|
||||||
|
# Redirect print() and errors to logger so they appear in SigNoz
|
||||||
|
sys.stdout = PrintLogger(logging.INFO)
|
||||||
|
sys.stderr = PrintLogger(logging.ERROR)
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -0,0 +1,16 @@
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class PrintLogger:
|
||||||
|
def __init__(self, level=logging.INFO):
|
||||||
|
self.logger = logging.getLogger("stdout_redirect")
|
||||||
|
self.level = level
|
||||||
|
self.terminal = sys.__stdout__ # Save original stdout
|
||||||
|
|
||||||
|
def write(self, message):
|
||||||
|
message = message.strip()
|
||||||
|
if message: # avoid empty lines
|
||||||
|
self.logger.log(self.level, message)
|
||||||
|
self.terminal.write(message + '\n') # Echo to terminal
|
||||||
|
def flush(self):
|
||||||
|
self.terminal.flush()
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
Loading…
Reference in New Issue