feat: Add promo codes
All checks were successful
Build Docker / Build Image (push) Successful in 21s
All checks were successful
Build Docker / Build Image (push) Successful in 21s
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,3 +6,5 @@ __pycache__/
|
|||||||
used.json
|
used.json
|
||||||
|
|
||||||
payments.json
|
payments.json
|
||||||
|
|
||||||
|
promo.json
|
||||||
|
|||||||
22
account.py
Normal file
22
account.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import os
|
||||||
|
import dotenv
|
||||||
|
import random
|
||||||
|
|
||||||
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
|
EMAIL = os.getenv('LOGIN_EMAIL')
|
||||||
|
PASSWORD = os.getenv('LOGIN_PASSWORD')
|
||||||
|
|
||||||
|
tokens = []
|
||||||
|
|
||||||
|
def login(email, password):
|
||||||
|
if email == EMAIL and password == PASSWORD:
|
||||||
|
token = str(random.randint(100000, 999999))
|
||||||
|
tokens.append(token)
|
||||||
|
return token
|
||||||
|
return False
|
||||||
|
|
||||||
|
def token(token):
|
||||||
|
if token in tokens:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
74
payments.py
74
payments.py
@@ -29,6 +29,10 @@ else:
|
|||||||
with open(path+'used.json', 'w') as f:
|
with open(path+'used.json', 'w') as f:
|
||||||
json.dump(used, f, indent=4)
|
json.dump(used, f, indent=4)
|
||||||
|
|
||||||
|
if not os.path.exists(path+'promo.json'):
|
||||||
|
with open(path+'promo.json', 'w') as f:
|
||||||
|
json.dump([], f, indent=4)
|
||||||
|
|
||||||
HNSaddress = os.getenv('ADDRESS')
|
HNSaddress = os.getenv('ADDRESS')
|
||||||
|
|
||||||
names = {
|
names = {
|
||||||
@@ -37,7 +41,7 @@ names = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def generate_payment(name,email,mobile,address,country,cart,hns):
|
def generate_payment(name,email,mobile,address,country,cart,hns,promo=False):
|
||||||
# Generate a payment object
|
# Generate a payment object
|
||||||
payment_id = generate_payment_id()
|
payment_id = generate_payment_id()
|
||||||
if payment_id == "ERROR":
|
if payment_id == "ERROR":
|
||||||
@@ -50,6 +54,11 @@ def generate_payment(name,email,mobile,address,country,cart,hns):
|
|||||||
if item['name'] in names:
|
if item['name'] in names:
|
||||||
item['name'] = names[item['name']]
|
item['name'] = names[item['name']]
|
||||||
|
|
||||||
|
if promo:
|
||||||
|
promo = promo["id"]
|
||||||
|
usePromo(promo)
|
||||||
|
|
||||||
|
|
||||||
payment = {
|
payment = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"email": email,
|
"email": email,
|
||||||
@@ -59,6 +68,7 @@ def generate_payment(name,email,mobile,address,country,cart,hns):
|
|||||||
"hns": hns,
|
"hns": hns,
|
||||||
"ID": finalPrice,
|
"ID": finalPrice,
|
||||||
"cart": cart,
|
"cart": cart,
|
||||||
|
"promo": promo,
|
||||||
"status": "Pending"
|
"status": "Pending"
|
||||||
}
|
}
|
||||||
finalPriceDolarydoo = float(finalPrice) * 1000000
|
finalPriceDolarydoo = float(finalPrice) * 1000000
|
||||||
@@ -134,6 +144,68 @@ def generate_payment_id():
|
|||||||
|
|
||||||
if id > 99:
|
if id > 99:
|
||||||
return "ERROR"
|
return "ERROR"
|
||||||
|
|
||||||
|
|
||||||
|
def getPromo(code):
|
||||||
|
with open(path+'promo.json', 'r') as f:
|
||||||
|
promos = json.load(f)
|
||||||
|
for promo in promos:
|
||||||
|
if promo['id'] == code:
|
||||||
|
return promo
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def getPromos():
|
||||||
|
with open(path+'promo.json', 'r') as f:
|
||||||
|
promos = json.load(f)
|
||||||
|
return promos
|
||||||
|
|
||||||
|
def addPromo(id, constant, percent, uses):
|
||||||
|
with open(path+'promo.json', 'r') as f:
|
||||||
|
promos = json.load(f)
|
||||||
|
|
||||||
|
for promo in promos:
|
||||||
|
if promo['id'] == id:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
promos.append({
|
||||||
|
"id": id,
|
||||||
|
"constant": constant,
|
||||||
|
"percent": percent,
|
||||||
|
"uses": uses
|
||||||
|
})
|
||||||
|
with open(path+'promo.json', 'w') as f:
|
||||||
|
json.dump(promos, f, indent=4)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def deletePromo(id):
|
||||||
|
with open(path+'promo.json', 'r') as f:
|
||||||
|
promos = json.load(f)
|
||||||
|
for promo in promos:
|
||||||
|
if promo['id'] == id:
|
||||||
|
promos.remove(promo)
|
||||||
|
with open(path+'promo.json', 'w') as f:
|
||||||
|
json.dump(promos, f, indent=4)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def usePromo(id):
|
||||||
|
with open(path+'promo.json', 'r') as f:
|
||||||
|
promos = json.load(f)
|
||||||
|
for promo in promos:
|
||||||
|
if promo['id'] == id:
|
||||||
|
if promo['uses'] == "1":
|
||||||
|
promos.remove(promo)
|
||||||
|
elif promo['uses'] == "-1":
|
||||||
|
return True
|
||||||
|
|
||||||
|
uses = int(promo['uses'])
|
||||||
|
uses -= 1
|
||||||
|
promo['uses'] = str(uses)
|
||||||
|
with open(path+'promo.json', 'w') as f:
|
||||||
|
json.dump(promos, f, indent=4)
|
||||||
|
return True
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
|
|||||||
37
render.py
37
render.py
@@ -68,7 +68,7 @@ def cart_total(cert):
|
|||||||
price = prices[path]
|
price = prices[path]
|
||||||
else:
|
else:
|
||||||
name = path
|
name = path
|
||||||
image = "tech/image2.jpg"
|
image = "pins/pack1.jpg"
|
||||||
price = 45
|
price = 45
|
||||||
|
|
||||||
hns = usdToHNS(price, True)
|
hns = usdToHNS(price, True)
|
||||||
@@ -122,7 +122,7 @@ def usdToHNS(usd, returnInt=False):
|
|||||||
return hns
|
return hns
|
||||||
|
|
||||||
|
|
||||||
def total_usd(cert):
|
def total_usd(cert,promo):
|
||||||
total = 0
|
total = 0
|
||||||
for item in cert:
|
for item in cert:
|
||||||
path = item['name']
|
path = item['name']
|
||||||
@@ -130,18 +130,33 @@ def total_usd(cert):
|
|||||||
total += prices[path] * int(item['quantity'])
|
total += prices[path] * int(item['quantity'])
|
||||||
else:
|
else:
|
||||||
total += 45 * int(item['quantity'])
|
total += 45 * int(item['quantity'])
|
||||||
|
|
||||||
|
if promo:
|
||||||
|
if promo["constant"]:
|
||||||
|
total -= int(promo["constant"])
|
||||||
|
else:
|
||||||
|
total = total - (total * int(promo["percent"]) / 100)
|
||||||
|
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def total_hns(cert, returnInt=False):
|
def total_hns(cert, promo, returnInt=False):
|
||||||
total = 0
|
total = total_usd(cert, promo)
|
||||||
for item in cert:
|
total = usdToHNS(total,True)
|
||||||
path = item['name']
|
|
||||||
if path in prices:
|
|
||||||
total += usdToHNS(prices[path],True) * int(item['quantity'])
|
|
||||||
else:
|
|
||||||
total += usdToHNS(45,True) * int(item['quantity'])
|
|
||||||
|
|
||||||
if returnInt:
|
if returnInt:
|
||||||
return int(total)
|
return int(total)
|
||||||
total ="{:,}".format(total)
|
total ="{:,}".format(total)
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
|
||||||
|
def promoList(promo):
|
||||||
|
html = '<ul class="list-group">'
|
||||||
|
for item in promo:
|
||||||
|
discount = 0
|
||||||
|
if item['constant']:
|
||||||
|
discount = "$"+item['constant']
|
||||||
|
else:
|
||||||
|
discount = item['percent'] + '%'
|
||||||
|
html += f'<li class="list-group-item"><span>Code: {item["id"]} | {discount} off (Uses Left {item["uses"]})</span><a class="btn btn-primary align-right" role="button" href="/promo/delete/{item["id"]}">Delete</a></li>'
|
||||||
|
html += '</ul>'
|
||||||
|
return html
|
||||||
127
server.py
127
server.py
@@ -7,6 +7,7 @@ import json
|
|||||||
import render
|
import render
|
||||||
import payments
|
import payments
|
||||||
import threading
|
import threading
|
||||||
|
import account
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
@@ -170,13 +171,41 @@ def cart():
|
|||||||
else:
|
else:
|
||||||
cart = '[]'
|
cart = '[]'
|
||||||
|
|
||||||
|
promo_message = ''
|
||||||
|
if 'promo' in cookies:
|
||||||
|
promo = cookies['promo']
|
||||||
|
else:
|
||||||
|
promo = ''
|
||||||
|
|
||||||
cart = json.loads(cart)
|
cart = json.loads(cart)
|
||||||
cartHtml = render.cart(cart)
|
cartHtml = render.cart(cart)
|
||||||
|
|
||||||
total_usd = render.total_usd(cart)
|
if promo != '':
|
||||||
total_hns = render.total_hns(cart)
|
promo = payments.getPromo(promo)
|
||||||
|
if not promo:
|
||||||
|
promo_message = 'Invalid promo code'
|
||||||
|
promo = ''
|
||||||
|
else:
|
||||||
|
promo_message = f'Promo code {promo["id"]} applied'
|
||||||
|
|
||||||
return render_template('cart.html', year=year, cart=cartHtml, total_usd=total_usd, total_hns=total_hns)
|
total_usd = render.total_usd(cart,promo)
|
||||||
|
total_hns = render.total_hns(cart,promo)
|
||||||
|
promoCode = ''
|
||||||
|
if promo:
|
||||||
|
promoCode = promo["id"]
|
||||||
|
else:
|
||||||
|
total_usd = render.total_usd(cart, False)
|
||||||
|
total_hns = render.total_hns(cart, False)
|
||||||
|
promoCode = ''
|
||||||
|
|
||||||
|
return render_template('cart.html', year=year, cart=cartHtml, total_usd=total_usd, total_hns=total_hns,promo=promoCode, promo_message=promo_message)
|
||||||
|
|
||||||
|
@app.route('/cart/promo', methods=['POST'])
|
||||||
|
def cart_promo():
|
||||||
|
data = request.form
|
||||||
|
response = make_response(redirect('/cart'))
|
||||||
|
response.set_cookie('promo', data['promo'])
|
||||||
|
return response
|
||||||
|
|
||||||
@app.route('/payment')
|
@app.route('/payment')
|
||||||
def payment():
|
def payment():
|
||||||
@@ -194,8 +223,17 @@ def payment():
|
|||||||
cart = json.loads(cart)
|
cart = json.loads(cart)
|
||||||
cartHtml = render.cart_total(cart)
|
cartHtml = render.cart_total(cart)
|
||||||
|
|
||||||
total_usd = render.total_usd(cart)
|
if 'promo' in cookies:
|
||||||
total_hns = render.total_hns(cart)
|
promo = cookies['promo']
|
||||||
|
promo = payments.getPromo(promo)
|
||||||
|
total_usd = render.total_usd(cart,promo)
|
||||||
|
total_hns = render.total_hns(cart,promo)
|
||||||
|
else:
|
||||||
|
promo = ''
|
||||||
|
total_usd = render.total_usd(cart, False)
|
||||||
|
total_hns = render.total_hns(cart, False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render_template('payment.html', year=year, cart=cartHtml, total_usd=total_usd, total_hns=total_hns)
|
return render_template('payment.html', year=year, cart=cartHtml, total_usd=total_usd, total_hns=total_hns)
|
||||||
|
|
||||||
@@ -212,8 +250,16 @@ def payment_post():
|
|||||||
return redirect('/cart')
|
return redirect('/cart')
|
||||||
|
|
||||||
cart = json.loads(cart)
|
cart = json.loads(cart)
|
||||||
total_usd = render.total_usd(cart)
|
if 'promo' in cookies:
|
||||||
total_hns = render.total_hns(cart)
|
promo = cookies['promo']
|
||||||
|
promo = payments.getPromo(promo)
|
||||||
|
total_usd = render.total_usd(cart,promo)
|
||||||
|
total_hns = render.total_hns(cart,promo)
|
||||||
|
else:
|
||||||
|
promo = False
|
||||||
|
total_usd = render.total_usd(cart, False)
|
||||||
|
total_hns = render.total_hns(cart, False)
|
||||||
|
|
||||||
|
|
||||||
data = request.form
|
data = request.form
|
||||||
if 'email' in data:
|
if 'email' in data:
|
||||||
@@ -242,15 +288,13 @@ def payment_post():
|
|||||||
|
|
||||||
cartHtml = render.cart_total(cart)
|
cartHtml = render.cart_total(cart)
|
||||||
|
|
||||||
|
|
||||||
if email == '' or address == '' or name == '' or country == '' or mobile == '':
|
if email == '' or address == '' or name == '' or country == '' or mobile == '':
|
||||||
return render_template('payment.html', error='Please fill all fields',
|
return render_template('payment.html', error='Please fill all fields',
|
||||||
email=email, address=address, name=name, mobile=mobile, country=country,
|
email=email, address=address, name=name, mobile=mobile, country=country,
|
||||||
cart=cartHtml, total_usd=total_usd, total_hns=total_hns)
|
cart=cartHtml, total_usd=total_usd, total_hns=total_hns)
|
||||||
|
|
||||||
|
|
||||||
# All good, check out
|
# All good, check out
|
||||||
payment = payments.generate_payment(name, email, mobile,address,country, cart, render.total_hns(cart, True))
|
payment = payments.generate_payment(name, email, mobile,address,country, cart, render.total_hns(cart, promo,True), promo)
|
||||||
|
|
||||||
if payment == False:
|
if payment == False:
|
||||||
return render_template('payment.html', error='There was an error processing your payment', email=email, address=address, name=name,
|
return render_template('payment.html', error='There was an error processing your payment', email=email, address=address, name=name,
|
||||||
@@ -265,9 +309,67 @@ def payment_post():
|
|||||||
|
|
||||||
responce = make_response(render_template('payment_info.html',cart=cartHtml, total_hns=finalPrice,address=HNSaddress, year=datetime.datetime.now().year, qr=qr))
|
responce = make_response(render_template('payment_info.html',cart=cartHtml, total_hns=finalPrice,address=HNSaddress, year=datetime.datetime.now().year, qr=qr))
|
||||||
responce.set_cookie('cart', '[]')
|
responce.set_cookie('cart', '[]')
|
||||||
|
|
||||||
return responce
|
return responce
|
||||||
|
|
||||||
|
|
||||||
|
# Promo routes
|
||||||
|
@app.route('/promo')
|
||||||
|
def promo():
|
||||||
|
year = datetime.datetime.now().year
|
||||||
|
# Check user is logged in
|
||||||
|
token = request.cookies.get('token')
|
||||||
|
if not token:
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
if not account.token(token):
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
promos = payments.getPromos()
|
||||||
|
promos = render.promoList(promos)
|
||||||
|
|
||||||
|
return render_template('promo.html', year=year, promos=promos)
|
||||||
|
|
||||||
|
@app.route('/promo', methods=['POST'])
|
||||||
|
def promo_post():
|
||||||
|
data = request.form
|
||||||
|
token = request.cookies.get('token')
|
||||||
|
if not token:
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
if not account.token(token):
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
id = data['code']
|
||||||
|
constant = data['constant']
|
||||||
|
percent = data['percent']
|
||||||
|
uses = data['uses']
|
||||||
|
payments.addPromo(id, constant, percent, uses)
|
||||||
|
|
||||||
|
return redirect('/promo')
|
||||||
|
|
||||||
|
@app.route('/promo/delete/<path:path>')
|
||||||
|
def promo_delete(path):
|
||||||
|
token = request.cookies.get('token')
|
||||||
|
if not token:
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
if not account.token(token):
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
payments.deletePromo(path)
|
||||||
|
return redirect('/promo')
|
||||||
|
|
||||||
|
@app.route('/login', methods=['POST'])
|
||||||
|
def login():
|
||||||
|
data = request.form
|
||||||
|
token = account.login(data['email'], data['password'])
|
||||||
|
if token:
|
||||||
|
response = make_response(redirect('/promo'))
|
||||||
|
response.set_cookie('token', token)
|
||||||
|
return response
|
||||||
|
return redirect('/login')
|
||||||
|
|
||||||
|
|
||||||
# Main routes
|
# Main routes
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
@@ -305,7 +407,4 @@ def check_payments():
|
|||||||
payments.check_payments()
|
payments.check_payments()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Set timer for payments
|
|
||||||
|
|
||||||
repeat_check_payments()
|
|
||||||
app.run(debug=True, port=5000, host='0.0.0.0')
|
app.run(debug=True, port=5000, host='0.0.0.0')
|
||||||
10
templates/assets/css/vanilla-zoom.min.css
vendored
10
templates/assets/css/vanilla-zoom.min.css
vendored
@@ -39,3 +39,13 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
position: absolute;
|
||||||
|
right: 1px;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
font-size: medium !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
<div class="col-md-12 col-lg-4">
|
<div class="col-md-12 col-lg-4">
|
||||||
<div class="bg-body-tertiary summary">
|
<div class="bg-body-tertiary summary">
|
||||||
<h3>Summary</h3>
|
<h3>Summary</h3>
|
||||||
|
<form style="margin-bottom: 25px;" method="post" action="/cart/promo"><label class="form-label" for="promo">Promo Code</label><input class="form-control" type="text" placeholder="Promo Code" name="promo" value="{{promo}}"><span>{{promo_message}}</span></form>
|
||||||
<h4 class="border-primary-subtle" style="border-color: var(--bs-primary-border-subtle);"><span class="text">Total USD</span><span class="price">US${{total_usd}}</span></h4>
|
<h4 class="border-primary-subtle" style="border-color: var(--bs-primary-border-subtle);"><span class="text">Total USD</span><span class="price">US${{total_usd}}</span></h4>
|
||||||
<h4><span class="text">Total</span><span class="price">{{total_hns}} HNS</span></h4><a class="btn btn-primary btn-lg d-block w-100" role="button" href="/payment">Checkout</a>
|
<h4><span class="text">Total</span><span class="price">{{total_hns}} HNS</span></h4><a class="btn btn-primary btn-lg d-block w-100" role="button" href="/payment">Checkout</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
109
templates/login.html
Normal file
109
templates/login.html
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Login - HNSAU</title>
|
||||||
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
<link rel="canonical" href="https://hns.au/login">
|
||||||
|
<meta property="og:url" content="https://hns.au/login">
|
||||||
|
<meta name="twitter:image" content="https://hns.au/assets/img/HNSAUbanner.png">
|
||||||
|
<meta name="twitter:description" content="The home of Australians using the decentralized web, built on Handshake.">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta property="og:description" content="The home of Australians using the decentralized web, built on Handshake.">
|
||||||
|
<meta name="description" content="Handshake Australia">
|
||||||
|
<meta property="og:title" content="HNS AU">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="twitter:title" content="HNS AU">
|
||||||
|
<meta property="og:image" content="https://hns.au/assets/img/HNSAUbanner.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png" media="(prefers-color-scheme: dark)">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png" media="(prefers-color-scheme: dark)">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:400,400i,700,700i,600,600i&display=swap">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.10.0/baguetteBox.min.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/vanilla-zoom.min.css">
|
||||||
|
<!-- Matomo -->
|
||||||
|
<script>
|
||||||
|
var _paq = window._paq = window._paq || [];
|
||||||
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
|
_paq.push(['trackPageView']);
|
||||||
|
_paq.push(['enableLinkTracking']);
|
||||||
|
(function() {
|
||||||
|
var u="https://analytics.woodburn.au/";
|
||||||
|
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||||
|
_paq.push(['setSiteId', '8']);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<!-- End Matomo Code -->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg fixed-top bg-dark clean-navbar navbar-light" data-bs-theme="dark">
|
||||||
|
<div class="container-fluid"><a class="navbar-brand logo" href="/" style="width: 50%;"><img src="/assets/img/favicon.png" style="height: 50px;margin-right: 10px;">HNSAU</a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/blog">Blog</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/links">Links</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/about">About Us</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="https://domains.hns.au">Domains</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/pins">Pins</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/contact">Contact</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<main class="page login-page">
|
||||||
|
<section class="clean-block clean-form dark">
|
||||||
|
<div class="container">
|
||||||
|
<div class="block-heading">
|
||||||
|
<h2 class="text-info">Log In</h2>
|
||||||
|
</div>
|
||||||
|
<form method="post">
|
||||||
|
<div class="mb-3"><label class="form-label" for="email">Email</label><input class="form-control item" type="email" id="email" data-bs-theme="light" name="email"></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="password">Password</label><input class="form-control" type="password" id="password" data-bs-theme="light" name="password"></div><button class="btn btn-primary" type="submit">Log In</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="page-footer dark">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<h5>Get started</h5>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
<li><a href="/links">Links</a></li>
|
||||||
|
<li><a href="/domains" target="_blank">Domains</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<h5>Contact</h5>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://discord.gg/WJ6vpjuQv5" target="_blank">Discord</a></li>
|
||||||
|
<li><a href="/email" target="_blank">Email</a></li>
|
||||||
|
<li><a href="/about">About Us</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-copyright">
|
||||||
|
<p>© {{year}} Handshake AU</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.10.0/baguetteBox.min.js"></script>
|
||||||
|
<script src="/assets/js/vanilla-zoom.js"></script>
|
||||||
|
<script src="/assets/js/theme.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
114
templates/promo.html
Normal file
114
templates/promo.html
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Login - HNSAU</title>
|
||||||
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
<link rel="canonical" href="https://hns.au/promo">
|
||||||
|
<meta property="og:url" content="https://hns.au/promo">
|
||||||
|
<meta name="twitter:image" content="https://hns.au/assets/img/HNSAUbanner.png">
|
||||||
|
<meta name="twitter:description" content="The home of Australians using the decentralized web, built on Handshake.">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta property="og:description" content="The home of Australians using the decentralized web, built on Handshake.">
|
||||||
|
<meta name="description" content="Handshake Australia">
|
||||||
|
<meta property="og:title" content="HNS AU">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="twitter:title" content="HNS AU">
|
||||||
|
<meta property="og:image" content="https://hns.au/assets/img/HNSAUbanner.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png" media="(prefers-color-scheme: dark)">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png" media="(prefers-color-scheme: dark)">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:400,400i,700,700i,600,600i&display=swap">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.10.0/baguetteBox.min.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/vanilla-zoom.min.css">
|
||||||
|
<!-- Matomo -->
|
||||||
|
<script>
|
||||||
|
var _paq = window._paq = window._paq || [];
|
||||||
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
|
_paq.push(['trackPageView']);
|
||||||
|
_paq.push(['enableLinkTracking']);
|
||||||
|
(function() {
|
||||||
|
var u="https://analytics.woodburn.au/";
|
||||||
|
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||||
|
_paq.push(['setSiteId', '8']);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<!-- End Matomo Code -->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg fixed-top bg-dark clean-navbar navbar-light" data-bs-theme="dark">
|
||||||
|
<div class="container-fluid"><a class="navbar-brand logo" href="/" style="width: 50%;"><img src="/assets/img/favicon.png" style="height: 50px;margin-right: 10px;">HNSAU</a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/blog">Blog</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/links">Links</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/about">About Us</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="https://domains.hns.au">Domains</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/pins">Pins</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/contact">Contact</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<main class="page login-page">
|
||||||
|
<section class="clean-block clean-form dark">
|
||||||
|
<div class="container">
|
||||||
|
<div class="block-heading">
|
||||||
|
<h2 class="text-info">Create Promo Code</h2>
|
||||||
|
</div>
|
||||||
|
<form method="post">
|
||||||
|
<div style="margin-bottom: 16px;"><label class="form-label" for="code">Code</label><input class="form-control" type="text" data-bs-theme="light" name="code" placeholder="Promo Code"></div>
|
||||||
|
<div style="margin-bottom: 16px;"><label class="form-label" for="constant">US$ Off</label><input class="form-control" type="text" data-bs-theme="light" name="constant" placeholder="10"></div>
|
||||||
|
<div style="margin-bottom: 16px;"><label class="form-label" for="percent">% Off</label><input class="form-control" type="text" data-bs-theme="light" name="percent" placeholder="25"></div>
|
||||||
|
<div style="margin-bottom: 16px;"><label class="form-label" for="uses">Uses</label><input class="form-control" type="text" data-bs-theme="light" name="uses" placeholder="1"><span>Enter -1 for unlimited uses</span></div><button class="btn btn-primary" type="submit">Create</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div style="margin: auto;margin-top: 25px;max-width: 700px;">
|
||||||
|
<h3 class="text-center">Existing Promo Codes</h3>{{promos | safe}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="page-footer dark">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<h5>Get started</h5>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
<li><a href="/links">Links</a></li>
|
||||||
|
<li><a href="/domains" target="_blank">Domains</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<h5>Contact</h5>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://discord.gg/WJ6vpjuQv5" target="_blank">Discord</a></li>
|
||||||
|
<li><a href="/email" target="_blank">Email</a></li>
|
||||||
|
<li><a href="/about">About Us</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-copyright">
|
||||||
|
<p>© {{year}} Handshake AU</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.10.0/baguetteBox.min.js"></script>
|
||||||
|
<script src="/assets/js/vanilla-zoom.js"></script>
|
||||||
|
<script src="/assets/js/theme.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
<url>
|
<url>
|
||||||
<loc>https://hns.au/links</loc>
|
<loc>https://hns.au/links</loc>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://hns.au/login</loc>
|
||||||
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hns.au/payment</loc>
|
<loc>https://hns.au/payment</loc>
|
||||||
</url>
|
</url>
|
||||||
@@ -48,6 +51,9 @@
|
|||||||
<url>
|
<url>
|
||||||
<loc>https://hns.au/pins</loc>
|
<loc>https://hns.au/pins</loc>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://hns.au/promo</loc>
|
||||||
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://hns.au/uv</loc>
|
<loc>https://hns.au/uv</loc>
|
||||||
</url>
|
</url>
|
||||||
|
|||||||
Reference in New Issue
Block a user