diff --git a/app/config/directory.py b/app/config/directory.py index 9f2c2d2..3228804 100644 --- a/app/config/directory.py +++ b/app/config/directory.py @@ -1,7 +1,8 @@ from bottle import Bottle, get, static_file page = { - 'public' :'pages/public' + 'public' :'pages/public', + 'email' :'pages/email' } app = Bottle() @@ -12,6 +13,10 @@ app = Bottle() def static(filepath): return static_file(filepath, root="./static/css") +@app.get("/js/") +def static(filepath): + return static_file(filepath, root="./static/js") + # Template staticdir: plain @app.get("/templates/plain/css/") diff --git a/app/handler.py b/app/handler.py index 9930452..86912b4 100644 --- a/app/handler.py +++ b/app/handler.py @@ -5,22 +5,51 @@ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. -from bottle import Bottle, route, request +from bottle import Bottle, route, request, response +import json from config import directory import templates.plain.main as template_public +import templates.postcard.main as template_email import modules.public.home as public_home +import modules.public.register as public_register + +import modules.api.auth as api_auth app = Bottle() @app.route('/') def index(): - params = { "mako":{ "website" : template_public.main(directory.page["public"], "home") } } - return public_home.main().html(params) + return public_home.home().html(params) + +@app.route('/register/') +def index(roles): + params = { + "roles" :roles, + "mako" :{ + "website" : template_public.main(directory.page["public"], "register") + } + } + return public_register.register().html(params) + + +@app.route('/api/auth/registration/register/', method='POST') +def index(roles): + try: + params = request.json + params["roles" ] = roles + params["mako" ] = { + "email" : template_email.main(directory.page["email"], "verification") + } + response.content_type = 'application/json' + return json.dumps(api_auth.auth().register(params), indent = 2).encode() + except Exception as e: + print(str(e)) + return json.dumps({}, indent = 2).encode() diff --git a/app/modules/api/auth.py b/app/modules/api/auth.py index 6afcf04..a4f17cc 100644 --- a/app/modules/api/auth.py +++ b/app/modules/api/auth.py @@ -2,27 +2,19 @@ import mysql.connector as mariadb from mako.template import Template from bottle import request -import config.database as database -import config.globalvar as globalvar +from config import database, globalvar import bcrypt import re import datetime -import scripts.googly as googly -import scripts.saltedkey as saltedkey -import scripts.loggorilla as loggorilla -import scripts.sendwave as sendwave -import scripts.tokenguard as tokenguard -import scripts.paperplease as paperplease +from scripts import loggorilla, saltedkey, googly, tokenguard, sendwave class auth: def __init__(self): - # TODO: set database - self.db_main = mariadb.connect(**database.db_main) - self.cursor = self.db_main.cursor(dictionary=True) - # TODO: Config your SMTP + self.db_main = mariadb.connect(**database.db_main) + self.cursor = self.db_main.cursor(dictionary=True) self.smtpconfig = globalvar.smtpconfig def register(self, params): @@ -39,13 +31,10 @@ class auth: loggorilla.prcss(APIADDR, "Process parameters") hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() token = saltedkey.token(username, hashed) - # TODO: set production/development version if globalvar.production == True: - # TODO: set reCAPTCHA['server'] captcha_r = googly.recaptcha(captcha, globalvar.reCAPTCHA['server']) score = captcha_r["score"] else: - # For localhost reCAPTCHA['server'] captcha_r = 'dev mode' score = 0.9 loggorilla.prcss(APIADDR, "Get dependency data") @@ -55,7 +44,6 @@ class auth: result_username = self.cursor.fetchone() self.cursor.execute(f"SELECT COUNT(*) AS `count` FROM auth_profile_verification INNER JOIN auth_profile ON auth_profile.id = auth_profile_verification.auth_profile WHERE auth_profile.email = %s AND auth_profile_verification.type = 'email' AND auth_profile_verification.verified = 0 ; ", (email,) ) result_unverified = self.cursor.fetchone() - # TODO: set roles self.cursor.execute(f"SELECT id, name FROM `auth_roles` WHERE auth_roles.name = %s ; ", (roles,) ) result_roles = self.cursor.fetchone() loggorilla.prcss(APIADDR, "Validation") @@ -123,14 +111,12 @@ class auth: self.cursor.execute("INSERT INTO `auth_profile_verification` VALUES (DEFAULT, %s, 'email', 0, NOW(), NULL);", (auth_profile_lastrowid,) ) self.cursor.execute("INSERT INTO `auth_profile_roles` VALUES (DEFAULT, %s, %s, NOW(), NULL);", (auth_profile_lastrowid, result_roles['id']) ) loggorilla.prcss(APIADDR, "Generate URL") - # TODO: set expired time expired = datetime.datetime.now() + datetime.timedelta(minutes=30) # Can be hours or minutes expired_isoformat = expired.isoformat() payload = { "token" : token, "expired": expired_isoformat } - # TODO: Config SSH key for tokenguard and set verification URL token_encrypt = tokenguard.encode(payload, globalvar.ssh['key']['private'], globalvar.ssh['passphrase']) verification_url = globalvar.verification_url(token_encrypt) notme_url = globalvar.notme_url(token_encrypt) @@ -138,14 +124,14 @@ class auth: self.smtpconfig['subject' ] = f"{globalvar.title} email verification" self.smtpconfig['to' ] = email self.smtpconfig['text' ] = f"Please visit this link to complete the registration: {verification_url}. You are not registering this? report on this: {notme_url}." - self.smtpconfig['html' ] = Template(params["mako"]["email"]['template']).render( + self.smtpconfig['html' ] = Template(params["mako"]["email"]['index']).render( title = globalvar.title, - heading = self.smtpconfig['subject'], - image = "https://colorlib.com/etc/email-template/10/images/email.png", - unsubscribe = "#", + header = globalvar.title, + copyright = globalvar.copyright, container = Template(params["mako"]["email"]['container']).render( - verify = verification_url, - notme = notme_url + header = self.smtpconfig['subject'], + verify = verification_url, + notme = notme_url ) ) sendwave.smtp(self.smtpconfig) @@ -199,7 +185,7 @@ class auth: self.smtpconfig['subject' ] = f"{globalvar.title} email verification" self.smtpconfig['to' ] = email self.smtpconfig['text' ] = f"Please visit this link to complete the registration: {verification_url}. You are not registering this? report on this: {notme_url}." - self.smtpconfig['html' ] = Template(params["mako"]["email"]['template']).render( + self.smtpconfig['html' ] = Template(params["mako"]["email"]['index']).render( title = globalvar.title, heading = self.smtpconfig['subject'], image = "https://colorlib.com/etc/email-template/10/images/email.png", diff --git a/app/modules/public/home.py b/app/modules/public/home.py index 49a7c1d..a11f96b 100644 --- a/app/modules/public/home.py +++ b/app/modules/public/home.py @@ -1,19 +1,25 @@ -from mako.template import Template -from config import globalvar +import mysql.connector as mariadb +from mako.template import Template +from config import globalvar, database -class main: +class home: def __init__(self): - pass + self.db_main = mariadb.connect(**database.db_main) + self.cursor = self.db_main.cursor(dictionary=True) + self.user_roles = [0] # Cari user roles disini def html(self, params): + + active_page = "Home" + return Template(params["mako"]["website"]['index']).render( title = globalvar.title, - header = "Welcome to CostaPy", + header = globalvar.header, navbar = Template(params["mako"]["website"]['navbar']).render( menu = globalvar.menu['public']['navbar'], - user_roles = [0], - active_page = "Home" + user_roles = self.user_roles, + active_page = active_page ), footer = Template(params["mako"]["website"]['footer']).render( copyright = globalvar.copyright, diff --git a/app/modules/public/register.py b/app/modules/public/register.py new file mode 100644 index 0000000..afe2b2b --- /dev/null +++ b/app/modules/public/register.py @@ -0,0 +1,34 @@ +import mysql.connector as mariadb +from mako.template import Template +from config import globalvar, database + +class register: + + def __init__(self): + self.db_main = mariadb.connect(**database.db_main) + self.cursor = self.db_main.cursor(dictionary=True) + self.user_roles = [0] # Cari user roles disini + + def html(self, params): + + roles = params["roles"] + active_page = "Register" + + return Template(params["mako"]["website"]['index']).render( + title = globalvar.title, + header = globalvar.header, + navbar = Template(params["mako"]["website"]['navbar']).render( + menu = globalvar.menu['public']['navbar'], + user_roles = self.user_roles, + active_page = active_page + ), + footer = Template(params["mako"]["website"]['footer']).render( + copyright = globalvar.copyright, + ), + container = Template(params["mako"]["website"]['container']).render( + title = globalvar.title, + reCAPTCHA_client = globalvar.reCAPTCHA['client'], + roles = roles, + production = globalvar.production + ) + ) diff --git a/app/pages/email/verification.html b/app/pages/email/verification.html new file mode 100644 index 0000000..96142c2 --- /dev/null +++ b/app/pages/email/verification.html @@ -0,0 +1,11 @@ +

${header}

+ +

Thanks for signing up! This is the start of an exciting journey and you’re just one step away from completing your account setup to start using your profile.

+

Click the button below to verify your account and get started.

+ + Verify email address + +
+
+

You are not registering this? I'm not registering this

+
diff --git a/app/pages/public/register.html b/app/pages/public/register.html new file mode 100644 index 0000000..fe0aea3 --- /dev/null +++ b/app/pages/public/register.html @@ -0,0 +1,32 @@ +

Register

+ +% if production: + +% endif + + + + +
+
+
+ +% if production: + +% else: + +% endif + + + + + +
+ + +

Message here

+
+ + diff --git a/app/static/js/auth/register.js b/app/static/js/auth/register.js new file mode 100644 index 0000000..3bdacfd --- /dev/null +++ b/app/static/js/auth/register.js @@ -0,0 +1,68 @@ +function flushResponse() { + document.getElementById("alert-response" ).style.display = 'none'; + document.getElementById("resend-div" ).style.display = 'none'; + document.getElementById("alert-response" ).classList.remove('alert-success' ); + document.getElementById("alert-response" ).classList.remove('alert-danger' ); + document.getElementById("alert-response" ).classList.remove('alert-primary' ); +} + +function loadingResponse() { + flushResponse(); + document.getElementById("alert-status" ).innerHTML = "Loading..."; + document.getElementById("alert-desc" ).innerHTML = "Please wait..."; + document.getElementById("alert-response").classList.add('alert-primary'); + document.getElementById("alert-response").style.display = 'block'; +} + +function responseAlert(response) { + flushResponse(); + const obj = JSON.parse(response); + if (obj.status == "success" ) document.getElementById("alert-response").classList.add('alert-success' ); + if (obj.status == "failed" ) document.getElementById("alert-response").classList.add('alert-danger' ); + if (obj.desc == "check email for verification") { + document.getElementById("resend-email" ).value = document.getElementById("form-email").value; + document.getElementById("resend-message" ).innerHTML = obj.data.message; + document.getElementById("resend-link" ).setAttribute('href', obj.data.resend); + document.getElementById("resend-div" ).style.display = 'block'; + } + document.getElementById("alert-status" ).innerHTML = obj.status; + document.getElementById("alert-desc" ).innerHTML = obj.desc; + document.getElementById("alert-response").style.display = 'block'; +} + +function onSubmit(token) { + loadingResponse(); + var email = document.getElementById("form-email" ).value; + var username = document.getElementById("form-username" ).value; + var password = document.getElementById("form-password" ).value; + var roles = document.getElementById("roles" ).value; + var url = "/api/auth/registration/register/"+roles; + var payload = { + "email" : email, + "username" : username, + "password" : password + }; + payload.captcha = token; // Add response from reCAPTCHA + sendHttpRequest(url, "POST", payload, function (error, response) { + if (error) console.error("Error:", error); + else { + console.log("JSON Response:", response); + responseAlert(response); + } + }, "application/json"); +} + +function resending() { + loadingResponse(); + var email = document.getElementById("resend-email").value; + var url = "/api/auth/registration/resend?email="+email; + sendHttpRequest(url, "GET", null, function (error, response) { + if (error) console.error("Error:", error); + else { + console.log("JSON Response:", response); + responseAlert(response); + } + }, "multipart/form-data"); +} + +flushResponse(); diff --git a/app/static/js/carrack.js b/app/static/js/carrack.js new file mode 100644 index 0000000..7752eea --- /dev/null +++ b/app/static/js/carrack.js @@ -0,0 +1,18 @@ +function sendHttpRequest(url, method, data, callback, contentType = "multipart/form-data") { + var xhr = new XMLHttpRequest(); + xhr.open(method, url, true); + xhr.setRequestHeader("Content-Type", contentType); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + var response = xhr.responseText; + callback(null, response); + } + else callback(xhr.status, null); + } + }; + var requestData; + if (contentType === "application/json") requestData = JSON.stringify(data); + else requestData = data; + xhr.send(requestData); +}