feat: Add HNSChat linking
This commit is contained in:
parent
e5a0560f2c
commit
2d152de2f4
@ -22,6 +22,7 @@ services:
|
|||||||
DB_PASSWORD: your-db-password
|
DB_PASSWORD: your-db-password
|
||||||
DB_NAME: main
|
DB_NAME: main
|
||||||
CITY_DOMAIN: exampledomainnathan1
|
CITY_DOMAIN: exampledomainnathan1
|
||||||
|
VARO: <your-varo-apikey>
|
||||||
WORKERS: 2 # number of workers to run (should be 2 * number of cores)
|
WORKERS: 2 # number of workers to run (should be 2 * number of cores)
|
||||||
|
|
||||||
sites:
|
sites:
|
||||||
|
35
main.py
35
main.py
@ -8,6 +8,7 @@ import time
|
|||||||
from email_validator import validate_email, EmailNotValidError
|
from email_validator import validate_email, EmailNotValidError
|
||||||
import accounts
|
import accounts
|
||||||
import db
|
import db
|
||||||
|
import varo
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
@ -175,6 +176,8 @@ def send_edit():
|
|||||||
data['text_colour'] = request.form['text_colour']
|
data['text_colour'] = request.form['text_colour']
|
||||||
data['email'] = request.form['email']
|
data['email'] = request.form['email']
|
||||||
|
|
||||||
|
|
||||||
|
varo.update_avatar(data['avatar'],user['domain'])
|
||||||
# Convert to json
|
# Convert to json
|
||||||
data = json.dumps(data)
|
data = json.dumps(data)
|
||||||
db.update_website_data_raw(user['domain'],data)
|
db.update_website_data_raw(user['domain'],data)
|
||||||
@ -199,6 +202,38 @@ def claim():
|
|||||||
domain = request.args.get('domain')
|
domain = request.args.get('domain')
|
||||||
return redirect('/signup?domain=' + domain)
|
return redirect('/signup?domain=' + domain)
|
||||||
|
|
||||||
|
@app.route('/hnschat')
|
||||||
|
def hnschat():
|
||||||
|
token = request.cookies['token']
|
||||||
|
if not accounts.validate_token(token):
|
||||||
|
return error('Invalid token')
|
||||||
|
# Verify token
|
||||||
|
user = accounts.validate_token(token)
|
||||||
|
if not user:
|
||||||
|
# Remove cookie
|
||||||
|
resp = make_response(redirect('/login'))
|
||||||
|
resp.set_cookie('token', '', expires=0)
|
||||||
|
return resp
|
||||||
|
record = varo.get_auth(user['domain'])
|
||||||
|
return render_template('hnschat.html',account=user['email'],account_link="account",account_link_name="Account",CITY_DOMAIN=CITY_DOMAIN,domain=user['domain'],hnschat=record)
|
||||||
|
|
||||||
|
@app.route('/hnschat', methods=['POST'])
|
||||||
|
def save_hnschat():
|
||||||
|
token = request.cookies['token']
|
||||||
|
if not accounts.validate_token(token):
|
||||||
|
return error('Invalid token')
|
||||||
|
# Verify token
|
||||||
|
user = accounts.validate_token(token)
|
||||||
|
if not user:
|
||||||
|
# Remove cookie
|
||||||
|
resp = make_response(redirect('/login'))
|
||||||
|
resp.set_cookie('token', '', expires=0)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
record = request.form['hnschat']
|
||||||
|
varo.update_auth(record,user['domain'])
|
||||||
|
|
||||||
|
return redirect('/hnschat')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<path:path>')
|
@app.route('/<path:path>')
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
<section style="margin-top: 50px;text-align: center;">
|
<section style="margin-top: 50px;text-align: center;">
|
||||||
<h1>Welcome to ShakeCities</h1>
|
<h1>Welcome to ShakeCities</h1>
|
||||||
<p>Congratulations your site is ready for use.<br><br></p>
|
<p>Congratulations your site is ready for use.<br><br></p>
|
||||||
<div style="max-width: 10em;margin: auto;"><a class="btn btn-primary" role="button" href="https://{{site}}" style="display: block;margin: 10px;" target="_blank">Visit your site</a><a class="btn btn-primary" role="button" href="/edit" style="display: block;margin: 10px;">Edit your site</a><a class="btn btn-primary" role="button" href="/logout" style="display: block;margin: 10px;">Logout</a></div>
|
<div style="max-width: 10em;margin: auto;"><a class="btn btn-primary" role="button" href="https://{{site}}" style="display: block;margin: 10px;" target="_blank">Visit your site</a><a class="btn btn-primary" role="button" href="/edit" style="display: block;margin: 10px;">Edit your site</a><a class="btn btn-primary" role="button" href="/hnschat" style="display: block;margin: 10px;">Link HNSChat</a><a class="btn btn-primary" role="button" href="/logout" style="display: block;margin: 10px;">Logout</a></div>
|
||||||
</section>
|
</section>
|
||||||
<section style="margin: 20px;height: 40px;text-align: center;margin-top: 40px;">
|
<section style="margin: 20px;height: 40px;text-align: center;margin-top: 40px;">
|
||||||
<div>
|
<div>
|
||||||
|
50
templates/hnschat.html
Normal file
50
templates/hnschat.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="light" lang="en" style="background: #000000;">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>ShakeCities</title>
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNS.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNSW.png" media="(prefers-color-scheme: dark)">
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNS.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNSW.png" media="(prefers-color-scheme: dark)">
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNS.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNS.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="670x700" href="assets/img/HNS.png">
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/styles.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="background: #000000;color: #ffffff;width: 95%;margin: auto;">
|
||||||
|
<section>
|
||||||
|
<section style="height: 15vh;background: url("assets/img/alexander-slattery-LI748t0BK8w-unsplash.webp") bottom / cover no-repeat;min-height: 130px;"></section>
|
||||||
|
<section class="d-print-none d-lg-none d-xl-none d-xxl-none" style="width: 30vw;border-radius: 50%;background: #000000;padding: 20px;height: 30vw;margin: auto;margin-top: -15vw;display: flex;"><a href="/"><img class="img-fluid" src="assets/img/HNSW.png" width="100%"></a></section>
|
||||||
|
<section class="d-print-none d-lg-none d-xl-none d-xxl-none" style="display: block;width: 100%;text-align: center;margin-top: 10px;">
|
||||||
|
<div style="display: inline-block;margin: auto;"><a class="btn btn-primary" role="button" style="margin: 10px;" href="/signup">Create your page</a><a class="btn btn-primary" role="button" style="margin: 10px;" href="/{{account_link}}">{{account_link_name}}</a></div>
|
||||||
|
</section>
|
||||||
|
<section class="d-none d-print-block d-lg-block d-xl-block d-xxl-block" style="display: block;">
|
||||||
|
<div style="width: 100%;text-align: right;margin-top: -4em;"><a class="btn btn-primary" role="button" style="margin: 10px;" href="/signup">Create a new page</a><a class="btn btn-primary" role="button" style="margin: 10px;" href="/{{account_link}}">{{account_link_name}}</a></div>
|
||||||
|
</section>
|
||||||
|
<section class="d-none d-print-block d-lg-block d-xl-block d-xxl-block" style="width: 15vw;border-radius: 50%;background: #000000;padding: 20px;height: 15vw;margin: auto;display: flex;margin-top: -6vw;"><a href="/"><img class="img-fluid" src="assets/img/HNSW.png" width="100%"></a></section>
|
||||||
|
<section class="d-none d-print-block d-lg-block d-xl-block d-xxl-block" style="height: 3em;"></section>
|
||||||
|
</section>
|
||||||
|
<section style="margin-top: 50px;">
|
||||||
|
<h1 style="text-align: center;margin-bottom: 30px;">HNSChat</h1>
|
||||||
|
</section>
|
||||||
|
<section style="width: 80%;margin: auto;">
|
||||||
|
<p>Link your domain to HNSChat using Varo Auth.<br>1. Click Authenticate with Varo Auth<br>2. Enter {{domain}}<br>3. Copy TXT record (including the varo= part) into the below box and save<br>4. Verify your domain (it might take a few minutes for the cache to clear)</p>
|
||||||
|
<form method="post"><input class="form-control" type="text" style="margin-top: 10px;" name="hnschat" value="{{hnschat}}" placeholder="varo=....." required="" minlength="5">
|
||||||
|
<div style="text-align: center;"><input class="btn btn-primary" type="submit" style="margin-top: 10px;"></div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<section style="margin: 20px;height: 40px;text-align: center;margin-top: 40px;">
|
||||||
|
<div>
|
||||||
|
<p style="color: #ffffff;">Copyright © ShakeCities 2023</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/script.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
168
varo.py
Normal file
168
varo.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import requests
|
||||||
|
import os
|
||||||
|
import dotenv
|
||||||
|
|
||||||
|
dotenv.load_dotenv()
|
||||||
|
zone = ""
|
||||||
|
varo_api = os.getenv('VARO')
|
||||||
|
city_domain = os.getenv('CITY_DOMAIN')
|
||||||
|
|
||||||
|
|
||||||
|
def update_auth(auth,domain):
|
||||||
|
print("TXT: " + auth, "DOMAIN: " + domain, flush=True)
|
||||||
|
|
||||||
|
record = get_auth_id(domain)
|
||||||
|
if record == "":
|
||||||
|
data = {
|
||||||
|
"action": "addRecord",
|
||||||
|
"zone": zone,
|
||||||
|
"type": "TXT",
|
||||||
|
"name": domain,
|
||||||
|
"content": auth,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
data = {
|
||||||
|
"action": "updateRecord",
|
||||||
|
"zone": zone,
|
||||||
|
"record": record,
|
||||||
|
"column": "content",
|
||||||
|
"value": auth
|
||||||
|
}
|
||||||
|
if auth == "" and record == "":
|
||||||
|
return
|
||||||
|
if auth == "" and record != "":
|
||||||
|
data = {
|
||||||
|
"action": "deleteRecord",
|
||||||
|
"zone": zone,
|
||||||
|
"record": record
|
||||||
|
}
|
||||||
|
# Update TXT record
|
||||||
|
url = "https://reg.woodburn.au/api"
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer '+varo_api,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
r = requests.put(url, headers=headers, json=data)
|
||||||
|
return r.text
|
||||||
|
|
||||||
|
|
||||||
|
def get_auth_id(domain):
|
||||||
|
if zone == "":
|
||||||
|
get_zone()
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"action": "getRecords",
|
||||||
|
"zone": zone,
|
||||||
|
"name": "",
|
||||||
|
"type": "TXT",
|
||||||
|
"content": ""
|
||||||
|
}
|
||||||
|
url = "https://reg.woodburn.au/api"
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer '+varo_api,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
r = requests.post(url, headers=headers, json=data)
|
||||||
|
r = r.json()
|
||||||
|
for record in r['data']:
|
||||||
|
if record['name'] == domain + "." + city_domain:
|
||||||
|
if 'profile avatar=' not in record['content']:
|
||||||
|
return record['uuid']
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_auth(domain):
|
||||||
|
if zone == "":
|
||||||
|
get_zone()
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"action": "getRecords",
|
||||||
|
"zone": zone,
|
||||||
|
"name": "",
|
||||||
|
"type": "TXT",
|
||||||
|
"content": ""
|
||||||
|
}
|
||||||
|
url = "https://reg.woodburn.au/api"
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer '+varo_api,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
r = requests.post(url, headers=headers, json=data)
|
||||||
|
r = r.json()
|
||||||
|
for record in r['data']:
|
||||||
|
if record['name'] == domain + "." + city_domain:
|
||||||
|
if 'profile avatar=' not in record['content']:
|
||||||
|
return record['content']
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_zone():
|
||||||
|
global zone
|
||||||
|
url = "https://reg.woodburn.au/api"
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer '+varo_api,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"action": "getZones"
|
||||||
|
}
|
||||||
|
r = requests.post(url, headers=headers, json=data)
|
||||||
|
r = r.json()
|
||||||
|
for domain in r['data']:
|
||||||
|
if domain['name'] == city_domain:
|
||||||
|
zone = domain['id']
|
||||||
|
return domain['id']
|
||||||
|
|
||||||
|
def update_avatar(avatar,domain):
|
||||||
|
if zone == "":
|
||||||
|
get_zone()
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"action": "getRecords",
|
||||||
|
"zone": zone,
|
||||||
|
"name": "",
|
||||||
|
"type": "TXT",
|
||||||
|
"content": ""
|
||||||
|
}
|
||||||
|
url = "https://reg.woodburn.au/api"
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer '+varo_api,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
r = requests.post(url, headers=headers, json=data)
|
||||||
|
r = r.json()
|
||||||
|
record_id = ""
|
||||||
|
for record in r['data']:
|
||||||
|
if record['name'] == domain + "." + city_domain:
|
||||||
|
if 'profile avatar=' in record['content']:
|
||||||
|
if record['content'].split("profile avatar=")[1] == avatar:
|
||||||
|
print("Avatar already set", flush=True)
|
||||||
|
return "Avatar already set"
|
||||||
|
record_id = record['uuid']
|
||||||
|
|
||||||
|
if record_id == "":
|
||||||
|
data = {
|
||||||
|
"action": "addRecord",
|
||||||
|
"zone": zone,
|
||||||
|
"type": "TXT",
|
||||||
|
"name": domain,
|
||||||
|
"content": "profile avatar=" + avatar,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
data = {
|
||||||
|
"action": "updateRecord",
|
||||||
|
"zone": zone,
|
||||||
|
"record": record,
|
||||||
|
"column": "content",
|
||||||
|
"value": "profile avatar=" + avatar
|
||||||
|
}
|
||||||
|
if avatar == "" and record_id == "":
|
||||||
|
return
|
||||||
|
if avatar == "" and record_id != "":
|
||||||
|
data = {
|
||||||
|
"action": "deleteRecord",
|
||||||
|
"zone": zone,
|
||||||
|
"record": record_id
|
||||||
|
}
|
||||||
|
|
||||||
|
r = requests.post(url, headers=headers, json=data)
|
||||||
|
return r.text
|
||||||
|
|
Loading…
Reference in New Issue
Block a user