diff --git a/final project/__pycache__/app.cpython-310.pyc b/final project/__pycache__/app.cpython-310.pyc new file mode 100644 index 0000000..4b53f4d Binary files /dev/null and b/final project/__pycache__/app.cpython-310.pyc differ diff --git a/final project/__pycache__/blockchain.cpython-310.pyc b/final project/__pycache__/blockchain.cpython-310.pyc new file mode 100644 index 0000000..f0775eb Binary files /dev/null and b/final project/__pycache__/blockchain.cpython-310.pyc differ diff --git a/final project/__pycache__/forms.cpython-310.pyc b/final project/__pycache__/forms.cpython-310.pyc new file mode 100644 index 0000000..83fbdc0 Binary files /dev/null and b/final project/__pycache__/forms.cpython-310.pyc differ diff --git a/final project/__pycache__/sqlhelpers.cpython-310.pyc b/final project/__pycache__/sqlhelpers.cpython-310.pyc new file mode 100644 index 0000000..def287f Binary files /dev/null and b/final project/__pycache__/sqlhelpers.cpython-310.pyc differ diff --git a/final project/app.py b/final project/app.py new file mode 100644 index 0000000..8f9faab --- /dev/null +++ b/final project/app.py @@ -0,0 +1,179 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#import flask dependencies for web GUI +from flask import Flask, render_template, flash, redirect, url_for, session, request, logging +from passlib.hash import sha256_crypt +from flask_mysqldb import MySQL +from functools import wraps + +#import other functions and classes +from sqlhelpers import * +from forms import * + +#other dependencies +import time + +#initialize the app +app = Flask(__name__) + +#configure mysql +app.config['MYSQL_HOST'] = 'localhost' +app.config['MYSQL_USER'] = 'root' +app.config['MYSQL_PASSWORD'] = 'Meloni@137' +app.config['MYSQL_DB'] = 'new5' +app.config['MYSQL_CURSORCLASS'] = 'DictCursor' + +#initialize mysql +mysql = MySQL(app) + +#wrap to define if the user is currently logged in from session +def is_logged_in(f): + @wraps(f) + def wrap(*args, **kwargs): + if 'logged_in' in session: + return f(*args, **kwargs) + else: + flash("Unauthorized, please login.", "danger") + return redirect(url_for('login')) + return wrap + +#log in the user by updating session +def log_in_user(username): + users = Table("users", "name", "email", "username", "password") + user = users.getone("username", username) + + session['logged_in'] = True + session['username'] = username + session['name'] = user.get('name') + session['email'] = user.get('email') + +#Registration page +@app.route("/register", methods = ['GET', 'POST']) +def register(): + form = RegisterForm(request.form) + users = Table("users", "name", "email", "username", "password") + + #if form is submitted + if request.method == 'POST' and form.validate(): + #collect form data + username = form.username.data + email = form.email.data + name = form.name.data + + #make sure user does not already exist + if isnewuser(username): + #add the user to mysql and log them in + password = sha256_crypt.encrypt(form.password.data) + users.insert(name,email,username,password) + log_in_user(username) + return redirect(url_for('dashboard')) + else: + flash('User already exists', 'danger') + return redirect(url_for('register')) + + return render_template('register.html', form=form) + +#Login page +@app.route("/login", methods = ['GET', 'POST']) +def login(): + #if form is submitted + if request.method == 'POST': + #collect form data + username = request.form['username'] + candidate = request.form['password'] + + #access users table to get the user's actual password + users = Table("users", "name", "email", "username", "password") + user = users.getone("username", username) + accPass = user.get('password') + + #if the password cannot be found, the user does not exist + if accPass is None: + flash("Username is not found", 'danger') + return redirect(url_for('login')) + else: + #verify that the password entered matches the actual password + if sha256_crypt.verify(candidate, accPass): + #log in the user and redirect to Dashboard page + log_in_user(username) + flash('You are now logged in.', 'success') + return redirect(url_for('dashboard')) + else: + #if the passwords do not match + flash("Invalid password", 'danger') + return redirect(url_for('login')) + + return render_template('login.html') + +#Transaction page +@app.route("/transaction", methods = ['GET', 'POST']) +@is_logged_in +def transaction(): + form = SendMoneyForm(request.form) + balance = get_balance(session.get('username')) + + #if form is submitted + if request.method == 'POST': + try: + #attempt to execute the transaction + send_money(session.get('username'), form.username.data, form.amount.data) + flash("Money Sent!", "success") + except Exception as e: + flash(str(e), 'danger') + + return redirect(url_for('transaction')) + + return render_template('transaction.html', balance=balance, form=form, page='transaction') + +#Buy page +@app.route("/buy", methods = ['GET', 'POST']) +@is_logged_in +def buy(): + form = BuyForm(request.form) + balance = get_balance(session.get('username')) + + if request.method == 'POST': + #attempt to buy amount + try: + send_money("BANK", session.get('username'), form.amount.data) + flash("Purchase Successful!", "success") + except Exception as e: + flash(str(e), 'danger') + + return redirect(url_for('dashboard')) + + return render_template('buy.html', balance=balance, form=form, page='buy') + +#logout the user. Ends current session +@app.route("/logout") +@is_logged_in +def logout(): + session.clear() + flash("Logout success", "success") + return redirect(url_for('login')) + +#Dashboard page +@app.route("/dashboard") +@is_logged_in +def dashboard(): + balance = get_balance(session.get('username')) + blockchain = get_blockchain().chain + ct = time.strftime("%I:%M %p") + return render_template('dashboard.html', balance=balance, session=session, ct=ct, blockchain=blockchain, page='dashboard') + +#Index page +@app.route("/") +@app.route("/index") +def index(): + return render_template('index.html') + +#about us +@app.route("/") +@app.route("/aboutUs") +def aboutUs(): + return render_template('aboutUs.html') +#Run app +if __name__ == '__main__': + app.secret_key = 'secret123' + app.run(debug = True) diff --git a/final project/blockchain.py b/final project/blockchain.py new file mode 100644 index 0000000..b806855 --- /dev/null +++ b/final project/blockchain.py @@ -0,0 +1,99 @@ +from hashlib import sha256 +from datetime import datetime + +now = datetime.now() +time = now.strftime("%d/%m/%Y %H:%M:%S") + +#Takes in any number of arguments and produces a sha256 hash as a result +def updatehash(*args): + hashing_text = ""; h = sha256() + + #loop through each argument and hash + for arg in args: + hashing_text += str(arg) + + h.update(hashing_text.encode('utf-8')) + return h.hexdigest() + +#The "node" of the blockchain. Points to the previous block by its unique hash in previous_hash. +class Block(): + + #default data for block defined in constructor. Minimum specified should be number and data. + def __init__(self,number=0, previous_hash="0"*64, sender=None,recipient=None,amount=None,nonce=0): + self.sender = sender + self.recipient = recipient + self.amount = amount + self.number = number + self.previous_hash = previous_hash + self.nonce = nonce + + #returns a sha256 hash for the block's data. Function instead of variable in constructor + #to avoid corruption of the variable. + def hash(self): + return updatehash( + self.number, + self.previous_hash, + self.sender, + self.recipient, + self.amount, + self.nonce + ) + + #returns a string of the block's data. Useful for diagnostic print statements. + def __str__(self): + return str("Block#: %s\nHash: %s\nPrevious: %s\nSender: %s\nRecipient: %s\nAmount: %s\nNonce: %s\n" %( + self.number, + self.hash(), + self.previous_hash, + self.sender, + self.recipient, + self.amount, + self.nonce + ) + ) + + +#The "LinkedList" of the blocks-- a chain of blocks. +class Blockchain(): + #the number of zeros in front of each hash + difficulty = 4 + + #restarts a new blockchain or the existing one upon initialization + def __init__(self): + self.chain = [] + + #add a new block to the chain + def add(self, block): + self.chain.append(block) + + #remove a block from the chain + def remove(self, block): + self.chain.remove(block) + + #find the nonce of the block that satisfies the difficulty and add to chain + def mine(self, block): + #attempt to get the hash of the previous block. + #this should raise an IndexError if this is the first block. + try: block.previous_hash = self.chain[-1].hash() + except IndexError: pass + + #loop until nonce that satisifeis difficulty is found + while True: + if block.hash()[:self.difficulty] == "0" * self.difficulty: + self.add(block); break + else: + #increase the nonce by one and try again + block.nonce += 1 + + #check if blockchain is valid + def isValid(self): + #loop through blockchain + for i in range(1,len(self.chain)): + _previous = self.chain[i].previous_hash + _current = self.chain[i-1].hash() + #compare the previous hash to the actual hash of the previous block + if _previous != _current or _current[:self.difficulty] != "0"*self.difficulty: + return False + + return True + diff --git a/final project/forms.py b/final project/forms.py new file mode 100644 index 0000000..e42def4 --- /dev/null +++ b/final project/forms.py @@ -0,0 +1,18 @@ +from wtforms import Form, StringField, DecimalField, IntegerField, TextAreaField, PasswordField, validators + +#form used on Register page +class RegisterForm(Form): + name = StringField('Full Name', [validators.Length(min=1,max=50)]) + username = StringField('Username', [validators.Length(min=4,max=25)]) + email = StringField('Email', [validators.Length(min=6,max=50)]) + password = PasswordField('Password', [validators.DataRequired(), validators.EqualTo('confirm', message='Passwords do not match')]) + confirm = PasswordField('Confirm Password') + +#form used on the Transactions page +class SendMoneyForm(Form): + username = StringField('Username', [validators.Length(min=4,max=25)]) + amount = StringField('Amount', [validators.Length(min=1,max=5)]) + +#form used on the Buy page +class BuyForm(Form): + amount = StringField('Amount', [validators.Length(min=1,max=5)]) diff --git a/final project/sqlhelpers.py b/final project/sqlhelpers.py new file mode 100644 index 0000000..46b93ea --- /dev/null +++ b/final project/sqlhelpers.py @@ -0,0 +1,161 @@ +from app import mysql, session +from blockchain import Block, Blockchain + +#custom exceptions for transaction errors +class InvalidTransactionException(Exception): pass +class InsufficientFundsException(Exception): pass + +#what a mysql table looks like. Simplifies access to the database 'crypto' +class Table(): + #specify the table name and columns + #EXAMPLE table: + # blockchain + # number hash previous data nonce + # -data- -data- -data- -data- -data- + # + #EXAMPLE initialization: ...Table("blockchain", "number", "hash", "previous", "data", "nonce") + def __init__(self, table_name, *args): + self.table = table_name + self.columns = "(%s)" %",".join(args) + self.columnsList = args + + #if table does not already exist, create it. + if isnewtable(table_name): + create_data = "" + for column in self.columnsList: + create_data += "%s varchar(100)," %column + + cur = mysql.connection.cursor() #create the table + cur.execute("CREATE TABLE %s(%s)" %(self.table, create_data[:len(create_data)-1])) + cur.close() + + #get all the values from the table + def getall(self): + cur = mysql.connection.cursor() + result = cur.execute("SELECT * FROM %s" %self.table) + data = cur.fetchall(); return data + + #get one value from the table based on a column's data + #EXAMPLE using blockchain: ...getone("hash","00003f73gh93...") + def getone(self, search, value): + data = {}; cur = mysql.connection.cursor() + result = cur.execute("SELECT * FROM %s WHERE %s = \"%s\"" %(self.table, search, value)) + if result > 0: data = cur.fetchone() + cur.close(); return data + + #delete a value from the table based on column's data + def deleteone(self, search, value): + cur = mysql.connection.cursor() + cur.execute("DELETE from %s where %s = \"%s\"" %(self.table, search, value)) + mysql.connection.commit(); cur.close() + + #delete all values from the table. + def deleteall(self): + self.drop() #remove table and recreate + self.__init__(self.table, *self.columnsList) + + #remove table from mysql + def drop(self): + cur = mysql.connection.cursor() + cur.execute("DROP TABLE %s" %self.table) + cur.close() + + #insert values into the table + def insert(self, *args): + data = "" + for arg in args: #convert data into string mysql format + data += "\"%s\"," %(arg) + + cur = mysql.connection.cursor() + cur.execute("INSERT INTO %s%s VALUES(%s)" %(self.table, self.columns, data[:len(data)-1])) + mysql.connection.commit() + cur.close() + +#execute mysql code from python +def sql_raw(execution): + cur = mysql.connection.cursor() + cur.execute(execution) + mysql.connection.commit() + cur.close() + +#check if table already exists +def isnewtable(tableName): + cur = mysql.connection.cursor() + + try: #attempt to get data from table + result = cur.execute("SELECT * from %s" %tableName) + cur.close() + except: + return True + else: + return False + +#check if user already exists +def isnewuser(username): + #access the users table and get all values from column "username" + users = Table("users", "name", "email", "username", "password") + data = users.getall() + usernames = [user.get('username') for user in data] + + return False if username in usernames else True + +#send money from one user to another +def send_money(sender, recipient, amount): + #verify that the amount is an integer or floating value + try: amount = float(amount) + except ValueError: + raise InvalidTransactionException("Invalid Transaction.") + + #verify that the user has enough money to send (exception if it is the BANK) + if amount > get_balance(sender) and sender != "BANK": + raise InsufficientFundsException("Insufficient Funds.") + + #verify that the user is not sending money to themselves or amount is less than or 0 + elif sender == recipient or amount <= 0.00: + raise InvalidTransactionException("Invalid Transaction.") + + #verify that the recipient exists + elif isnewuser(recipient): + raise InvalidTransactionException("User Does Not Exist.") + + #update the blockchain and sync to mysql + blockchain = get_blockchain() + number = len(blockchain.chain) + 1 + data1 = "From: %s" %(sender) + data2 = "To: %s"%(recipient) + data3 = "Amount: %s"%(amount) + blockchain.mine(Block(number, sender=data1, recipient=data2, amount=data3)) + sync_blockchain(blockchain) + +#get the balance of a user +def get_balance(username): + balance = 0.00 + blockchain = get_blockchain() + + #loop through the blockchain and update balance + for block in blockchain.chain: + data1 = block.sender.split(" ") + data2 = block.recipient.split(" ") + data3 = block.amount.split(" ") + if username == data1[1]: + balance -= float(data3[1]) + elif username == data2[1]: + balance += float(data3[1]) + return balance + +#get the blockchain from mysql and convert to Blockchain object +def get_blockchain(): + blockchain = Blockchain() + blockchain_sql = Table("blockchain", "number", "hash", "previous", "sender", "recipient", "amount", "nonce") + for b in blockchain_sql.getall(): + blockchain.add(Block(int(b.get('number')), b.get('previous'), b.get('sender'), b.get('recipient'), b.get('amount'), int(b.get('nonce')))) + + return blockchain + +#update blockchain in mysql table +def sync_blockchain(blockchain): + blockchain_sql = Table("blockchain", "number", "hash", "previous", "sender", "recipient", "amount", "nonce") + blockchain_sql.deleteall() + + for block in blockchain.chain: + blockchain_sql.insert(str(block.number), block.hash(), block.previous_hash, block.sender, block.recipient, block.amount, block.nonce) diff --git a/final project/static/css/aboutUs.css b/final project/static/css/aboutUs.css new file mode 100644 index 0000000..ec7f3fe --- /dev/null +++ b/final project/static/css/aboutUs.css @@ -0,0 +1,9 @@ +body{ + text-align: center; +} +h2{ + text-align: center; +} +p{ + text-align: center; +} \ No newline at end of file diff --git a/final project/static/css/index.css b/final project/static/css/index.css new file mode 100644 index 0000000..fc6dd7f --- /dev/null +++ b/final project/static/css/index.css @@ -0,0 +1,63 @@ +body{ + margin: 0%; + font-family: 'Montserrat', sans-serif; +} +nav{ + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + height: 63px; + box-shadow: 0 8px 6px -6px #999; + background: linear-gradient( + 135deg,rgb(229, 255, 0), #eeb310); +} +nav img{ + width: 120px; + height: 80px; + display: inline; + padding-left: 40px; +} +nav ol{ + padding-right: 50px; +} +nav ol li{ + display: inline; + margin:0px 15px; + font-size: 18px; + text-shadow: 1px 1.5px rgb(89,89,83,0.75); + +} +nav ol li a{ + text-decoration: none; + color: white; + font-weight: 600; +} +nav button:hover a{ + color: white; +} +main{ + text-align: center; +} +#sec1{ + width:600px; + background-color: rgb(241, 210, 34, 0.9); + color: black; + margin: auto; + padding: 15px; + border-radius: 7px; + box-shadow: 0 10px 8px 8px #000; + margin-top: 4cm; +} +#sec1 p{ + font-size: 18px; + font-weight: 600; +} +#gsn a{ + color: black; + font-weight: 600; + font-size: 20px; +} +#gsn a:hover{ + color: blue; +} \ No newline at end of file diff --git a/final project/static/css/layout.css b/final project/static/css/layout.css new file mode 100644 index 0000000..04281be --- /dev/null +++ b/final project/static/css/layout.css @@ -0,0 +1,83 @@ +body{ + margin: 0%; + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.topnav { + background: linear-gradient( + 135deg,rgb(229, 255, 0), #eeb310); + overflow: hidden; + width: 100%; + height: 67px; + display: flex; + justify-content: space-between; + align-items: center; + color: rgb(0, 0, 0); +} + +/* Style the links inside the navigation bar */ +.topnav a { + float: left; + color: #000000; + text-align: center; + padding: 0px 16px; + text-decoration: none; + font-size: 17px; + margin: 0%; +} + +/* Change the color of links on hover */ +.topnav ul li a:hover { + background-color: #ddd; + color: black; +} +#logo:hover { + background:none; +} +nav img{ + width: 120px; + height: 80px; + display: inline; + padding: 0%; + margin-top: 0%; +} + +/* Add a color to the active/current link */ +footer{ + color: white; + background-color: black; +} +.topnav ul{ +list-style: none; +display: inline-flex; +} +.sub-menu{ +display: none; +} +.topnav ul li:hover .sub-menu{ +display: block; +position: absolute; +background: rgb(255, 255, 255); +color: white; +} +.topnav ul li:hover .sub-menu ul{ +display: block; +} +.topnav ul{ +display: flex; +align-items: center; +} +.sub-menu ul, .sub-menu ul a{ +padding: 0%; +padding: 20px 10px; +} +.sub-menu ul li{ +text-align: center; +} +.sub-menu{ +padding-bottom: 20px; +width: 100%; +transform: translateY(-5px); +} \ No newline at end of file diff --git a/final project/static/css/login.css b/final project/static/css/login.css new file mode 100644 index 0000000..eb0b680 --- /dev/null +++ b/final project/static/css/login.css @@ -0,0 +1,98 @@ +body{ + display: flex; + flex-direction: column; + background: linear-gradient( + 135deg, #0047ab,cyan); + background-repeat: no-repeat; + background-size: 100%; + height: 97.4vh; + align-items: center; + font-family: 'Varela Round',roboto; +} +#form_body{ + background: rgb(241, 210, 34, 0.87); + backdrop-filter: blur(10px); + border-radius: 10px; + border: 1px solid rgba(255,255,255,0.2); + width: 500px; + border-radius: 7px; + text-align: center; + padding: 30px 0px; + display: block; + box-shadow: 0 9px 8px 8px #000; + margin-top: 4cm; +} +.line{ + width: 145px; + height: 2px; + background-color: rgb(0, 0,0, 0.5); + display: inline-block; + margin-bottom: 10px; + margin-right: 4px; + margin-left: 4px; +} +h1{ + display: block; + margin: 20px 0px; + font-family: 'Montserrat', sans-serif; + letter-spacing: 2.5px; +} +#form_body input{ + margin: 15px 0px; +} +#form_body img{ + width: 30px; + height: 30px; + text-align: left !important; + margin-top: 5px; + margin-left: 5px; +} +button{ + margin: 10px 34px; + width: 117px; + height: 32px; + border:2px solid white; + border-radius: 3px; + color: black; + background-color: white; + font-weight: 600; + letter-spacing: 2px; + box-shadow: 0 8px 6px -10px #000; +} +button:hover{ + transform: translateY(-0.10em); + box-shadow: 0 8px 6px -6px #000; + background-color: #505050; + border: 2px solid #505050; + color: white; +} +form input{ + margin:10px 0px; + width: 300px; + height: 30px; + background-color: rgba(255,255,255,0); + backdrop-filter: blur(10px); + border: 1px solid rgba(0,0,0,0.1); + border-radius: 6px; +} +.already{ + color: #000; + font-size: 12px; + font-family: 'Montserrat', sans-serif; +} +h5{ + display: inline; + font-weight: 500; +} +.already span{ + border-bottom: #000; +} +.already span:hover{ + color: blue; + border-bottom: blue; +} +img{ + width: 120px; + height: 80px; + display: inline; +} \ No newline at end of file diff --git a/final project/static/css/register.css b/final project/static/css/register.css new file mode 100644 index 0000000..3938873 --- /dev/null +++ b/final project/static/css/register.css @@ -0,0 +1,97 @@ +body{ + display: flex; + justify-content: center; + background: linear-gradient( + 135deg, #0047ab,cyan); + background-repeat: no-repeat; + background-size: 100%; + height: 100vh; + align-items: center; + font-family: 'Varela Round',roboto; +} +#body_area{ + background: rgb(241, 210, 34, 0.9); + backdrop-filter: blur(10px); + border-radius: 10px; + border: 1px solid rgba(255,255,255,0.2); + width: 500px; + border-radius: 7px; +} +#body_area img{ + width: 30px; + height: 30px; + text-align: left !important; + margin-top: 5px; + margin-left: 5px; +} +.line{ + width: 140px; + height: 2px; + background-color: rgb(0, 0,0, 0.5); + display: inline-block; + margin-bottom: 10px; + margin-right: 4px; + margin-left: 4px; +} +h1{ + color: rgb(0, 0,0, 0.8); + text-align: center; + margin-left: 2px; + margin-right: 2px; + letter-spacing: 2.5px; + font-family: 'Montserrat', sans-serif; + margin-top: 0%; +} +h4{ + color: rgb(0, 0,0, 0.5); + text-align: center; + font-size: 18px; + letter-spacing: 1.5px; +} +form{ + text-align: center; +} +form input{ + margin:10px 0px; + width: 300px; + height: 30px; + background-color: rgba(255,255,255,0); + backdrop-filter: blur(10px); + border: 1px solid rgba(0,0,0,0.1); + border-radius: 6px; +} +button{ + margin: 10px 34px; + width: 117px; + height: 32px; + border:2px solid white; + border-radius: 3px; + color: black; + background-color: white; + font-weight: 600; + letter-spacing: 2px; + box-shadow: 0 8px 6px -10px #000; +} +button:hover{ + transform: translateY(-0.10em); + box-shadow: 0 8px 6px -6px #000; + background-color: #505050; + border: 2px solid #505050; + color: white; +} +h5{ + display: inline; + font-weight: 500; +} +.already{ + color: #000; + font-size: 12px; + font-family: 'Montserrat', sans-serif; +} +.already span{ + border-bottom: #000; +} +.already span:hover{ + color: blue; + border-bottom: blue; +} \ No newline at end of file diff --git a/final project/static/images/background.jpeg b/final project/static/images/background.jpeg new file mode 100644 index 0000000..393a6de Binary files /dev/null and b/final project/static/images/background.jpeg differ diff --git a/final project/static/images/buy.png b/final project/static/images/buy.png new file mode 100644 index 0000000..59c0af8 Binary files /dev/null and b/final project/static/images/buy.png differ diff --git a/final project/static/images/favicon.ico b/final project/static/images/favicon.ico new file mode 100644 index 0000000..eb1b919 Binary files /dev/null and b/final project/static/images/favicon.ico differ diff --git a/final project/static/images/favicon2.png b/final project/static/images/favicon2.png new file mode 100644 index 0000000..0ad6678 Binary files /dev/null and b/final project/static/images/favicon2.png differ diff --git a/final project/static/images/home.png b/final project/static/images/home.png new file mode 100644 index 0000000..f642c2d Binary files /dev/null and b/final project/static/images/home.png differ diff --git a/final project/static/images/profile.png b/final project/static/images/profile.png new file mode 100644 index 0000000..9dd21a8 Binary files /dev/null and b/final project/static/images/profile.png differ diff --git a/final project/templates/aboutUs.html b/final project/templates/aboutUs.html new file mode 100644 index 0000000..2a3a48a --- /dev/null +++ b/final project/templates/aboutUs.html @@ -0,0 +1,44 @@ + + + + + + + + About Us + + +{% extends 'layout.html' %} + +{% block body %} + + +

About Us

+

We are a team of 4, curious about blockchain technology. We started building this project under the + inheritance mentorship program at VJTI in September 2021.

+

About Blockchain

+

Blockchain is a system of recording information in a way that makes it difficult or impossible to change, hack, + or cheat the system.

+

A blockchain is essentially a digital ledger of transactions that is duplicated and distributed across the entire + network of computer systems on the blockchain. Each block in the chain contains a number of transactions, and + every time a new transaction occurs on the blockchain, a record of that transaction is added to every + participant’s ledger. The decentralised database managed by multiple participants is known as Distributed Ledger + Technology (DLT).

+

Blockchain is a type of DLT in which transactions are recorded with an immutable cryptographic signature called a + hash.

+

This means if one block in one chain was changed, it would be immediately apparent it had been tampered with. If + hackers wanted to corrupt a blockchain system, they would have to change every block in the chain, across all of + the distributed versions of the chain.

+

About VJTI

+

VJTI Mumbai (estd. in 1887 as Victoria Jubilee Technical Institute) has pioneered India’s Engineering education, + research and training ecosystem. Pre-independence, VJTI had been instrumental in driving industrial growth + throughout united India. Post-independence, VJTI played a pivotal role in setting up IITs and RECs of India and + strengthened technology excellence of country. In 1997, VJTI changed its name to Veermata Jijabai Technological + Institute to honor mother of Chhatrapati Shivaji Maharaj. Located in South Mumbai, VJTI is an autonomous + institution owned by Maharashtra State Government. The institute offers programs in engineering and technology + at the diploma, degree, post-graduate and doctoral levels. VJTI is known for its high quality teaching, + collaborative research, industry connect and strong alumni network.

+ +{% endblock %} + + \ No newline at end of file diff --git a/final project/templates/buy.html b/final project/templates/buy.html new file mode 100644 index 0000000..ce10f42 --- /dev/null +++ b/final project/templates/buy.html @@ -0,0 +1,16 @@ +{% extends 'layout.html' %} + +{% block body %} +{% include 'includes/_messages.html' %} + +

Your current balance is {{ balance }} RC

+{% from "includes/_formhelpers.html" import render_field %} +
+
+
+ {{render_field(form.amount, class_="form-control")}} +
+
+ +
+{% endblock %} diff --git a/final project/templates/dashboard.html b/final project/templates/dashboard.html new file mode 100644 index 0000000..e5c5a17 --- /dev/null +++ b/final project/templates/dashboard.html @@ -0,0 +1,83 @@ +{% extends 'layout.html' %} + + + + +{% block body %} + + + + + + +

Welcome!

+ + + + +
+
+
+ +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/final project/templates/handlers/404.html b/final project/templates/handlers/404.html new file mode 100644 index 0000000..3adf14f --- /dev/null +++ b/final project/templates/handlers/404.html @@ -0,0 +1,10 @@ +{% extends 'layout.html' %} + +{% block body %} + +

404

+

Page not found. You can + go back + to the previous page, or + return home.

+{% endblock %} diff --git a/final project/templates/includes/_formhelpers.html b/final project/templates/includes/_formhelpers.html new file mode 100644 index 0000000..bf7b4d7 --- /dev/null +++ b/final project/templates/includes/_formhelpers.html @@ -0,0 +1,9 @@ +{% macro render_field(field) %} + {{ field.label }} + {{ field(**kwargs) |safe }} + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} +{% endmacro %} diff --git a/final project/templates/includes/_messages.html b/final project/templates/includes/_messages.html new file mode 100644 index 0000000..27ad1ed --- /dev/null +++ b/final project/templates/includes/_messages.html @@ -0,0 +1,16 @@ +{% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
{{ message }}
+ + {% endfor %} + {% endif %} +{% endwith %} + +{% if error %} +
+{% endif %} + +{% if msg %} +
+{% endif %} diff --git a/final project/templates/index.html b/final project/templates/index.html new file mode 100644 index 0000000..48ed8b4 --- /dev/null +++ b/final project/templates/index.html @@ -0,0 +1,38 @@ + + + + + + + + R-Cell + + + + + + + + +
+
+

R-Cell is a Crypto currency developed by students at VJTI, Mumbai as a part of learning and + implementing the technology.

+

R-Cell was implemented using Flask framework and Python.

+

Get started now

+
+ +
+ + \ No newline at end of file diff --git a/final project/templates/layout.html b/final project/templates/layout.html new file mode 100644 index 0000000..c864e9a --- /dev/null +++ b/final project/templates/layout.html @@ -0,0 +1,52 @@ + + + + + + R-Cell - Dashboard + + + + + + +
+ +
+
+
+ {% block body %} + + {% endblock %} + +
+
+
+
+ Copyright © R-Cell 2021 +
+
+ +
+ + + + diff --git a/final project/templates/login.html b/final project/templates/login.html new file mode 100644 index 0000000..a85072d --- /dev/null +++ b/final project/templates/login.html @@ -0,0 +1,48 @@ + + + + + + + + R-Cell - Login + + + + + + + + + + + +
+ +

LOGIN

+ + {% include 'includes/_messages.html' %} +
+ +
+ +
+ +
+
+
Don't have an account?
+ Register +
+
+ + + + \ No newline at end of file diff --git a/final project/templates/register.html b/final project/templates/register.html new file mode 100644 index 0000000..1a5e384 --- /dev/null +++ b/final project/templates/register.html @@ -0,0 +1,45 @@ + + + + + + + Registration + + + + + + + + {% include 'includes/_messages.html' %} + {% from "includes/_formhelpers.html" import render_field %} +
+ +

REGISTER

+

Create an account today.

+
+ +
+ +
+ +
+ +
+ +
+ + +
+
Already have an account?
+ Login +
+
+
+
+ + + \ No newline at end of file diff --git a/final project/templates/transaction.html b/final project/templates/transaction.html new file mode 100644 index 0000000..541888a --- /dev/null +++ b/final project/templates/transaction.html @@ -0,0 +1,17 @@ +{% extends 'layout.html' %} + +{% block body %} +{% include 'includes/_messages.html' %} +

Your current balance is {{ balance }} RC

+{% from "includes/_formhelpers.html" import render_field %} +
+
+ {{render_field(form.username, class_="form-control")}} +
+
+ {{render_field(form.amount, class_="form-control")}} +
+
+

+
+{% endblock %}