[] Fixes + Normal account registration

This commit is contained in:
Anthony 2022-11-24 15:13:53 +00:00
parent 4a2512d103
commit b881a650a6
8 changed files with 155 additions and 95 deletions

View File

@ -17,7 +17,6 @@
<title>Apexie's Hub</title> <title>Apexie's Hub</title>
<link rel="stylesheet" href="/assets/css/style.css"> <link rel="stylesheet" href="/assets/css/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>
</head> </head>
@ -27,7 +26,7 @@
<div class="container"> <div class="container">
<a class="navbar-brand" href="#"> <a class="navbar-brand" href="#">
<img src="assets/img/favicon.png" alt="" width="30" height="30" class="d-inline-block align-text-top"> <img src="assets/img/favicon.png" alt="" width="30" height="30" class="d-inline-block align-text-top">
Apexie's Home Apexie's Hub
</a> </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
@ -37,21 +36,21 @@
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto"> <ul class="navbar-nav ms-auto">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a> <a class="nav-link active" aria-current="page" href="#"><i class="bi bi-house"></i> Home</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="https://github.com/apexiedev">GitHub</a> <a class="nav-link" href="https://github.com/apexiedev"><i class="bi bi-github"></i> GitHub</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="https://dsc.gg/apexie">Discord</a> <a class="nav-link" href="https://dsc.gg/apexie"><i class="bi bi-discord"></i> Discord</a>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
aria-expanded="false"> aria-expanded="false">
Projects <i class="bi bi-braces"></i> Projects
</a> </a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown"> <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#osustream">osu!stream revived</a></li> <li><a class="dropdown-item" href="#osustream">osu!restream</a></li>
<li><a class="dropdown-item" href="#plenus">Plenus</a></li> <li><a class="dropdown-item" href="#plenus">Plenus</a></li>
<li> <li>
<hr class="dropdown-divider"> <hr class="dropdown-divider">
@ -68,7 +67,7 @@
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
aria-expanded="false"> aria-expanded="false">
Profile <i class="bi bi-person-circle"></i> Profile
</a> </a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown"> <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" id="login_button" data-bs-toggle="modal" <li><a class="dropdown-item" id="login_button" data-bs-toggle="modal"
@ -91,11 +90,15 @@
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Login to the Apexie World</h1> <h1 class="modal-title fs-5" id="loginModalLabel">Login to your Apexie ID</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body" id="loginModalBody">
<form> <form>
<div class="mb-3" id="account-username-fill" hidden>
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="account-username">
</div>
<div class="mb-3"> <div class="mb-3">
<label for="account-email" class="form-label">Email address</label> <label for="account-email" class="form-label">Email address</label>
<input type="email" class="form-control" id="account-email" aria-describedby="emailHelp"> <input type="email" class="form-control" id="account-email" aria-describedby="emailHelp">
@ -105,17 +108,18 @@
<label for="account-password" class="form-label">Password</label> <label for="account-password" class="form-label">Password</label>
<input type="password" class="form-control" id="account-password"> <input type="password" class="form-control" id="account-password">
</div> </div>
<div class="mb-3" id="account-confirm-password-fill" hidden>
<label for="account-confirm-password" class="form-label">Confirm Password</label>
<input type="password" class="form-control" id="account-confirm-password">
</div>
</form> </form>
<div id="login-error"></div> <div id="login-error"></div>
<div id="verification-alert"></div>
<ul id="login-list"> <ul id="login-list">
<li>Loading OAuth2 providers...</li> <li>Loading OAuth2 providers...</li>
</ul> </ul>
</div> </div>
<div class="modal-footer"> <div class="modal-footer" id="loginModalFooter">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" id="account-register" class="btn btn-primary">Register</button>
<button type="submit" id="account-login" class="btn btn-primary">Login</button>
</div> </div>
</div> </div>
</div> </div>
@ -150,33 +154,6 @@
</div> </div>
</div> </div>
<div class="modal fade" id="sessionexpired" tabindex="-2" aria-labelledby="logintime" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="expiredLabel">Login expired</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p class="lead">Hi, it seems like your Discord session on this website has expired, would you like
to login again?</p>
</div>
<div class="modal-footer">
<!-- Yes -->
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="login-yes">
Yes
</button>
<!-- No -->
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="login-no">
No
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="login-dont-show">
Don't show this again
</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="gdprconsent" tabindex="-2" aria-labelledby="gdpr" aria-hidden="true"> <div class="modal fade" id="gdprconsent" tabindex="-2" aria-labelledby="gdpr" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
@ -202,10 +179,8 @@
</div> </div>
</div> </div>
</div> </div>
<div id="main-app"></div> <div id="main-app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
<script type="module" src="/src/homepage.ts"></script>
</body> </body>
</html> </html>

View File

@ -12,6 +12,7 @@
"@types/bootstrap": "^5.2.6", "@types/bootstrap": "^5.2.6",
"@types/jquery": "^3.5.14", "@types/jquery": "^3.5.14",
"bootstrap": "^5.2.3", "bootstrap": "^5.2.3",
"bootstrap-icons": "^1.10.2",
"pocketbase": "^0.8.0", "pocketbase": "^0.8.0",
"sass": "^1.56.1", "sass": "^1.56.1",
"typescript": "^4.6.4", "typescript": "^4.6.4",

6
pnpm-lock.yaml generated
View File

@ -5,6 +5,7 @@ specifiers:
'@types/bootstrap': ^5.2.6 '@types/bootstrap': ^5.2.6
'@types/jquery': ^3.5.14 '@types/jquery': ^3.5.14
bootstrap: ^5.2.3 bootstrap: ^5.2.3
bootstrap-icons: ^1.10.2
pocketbase: ^0.8.0 pocketbase: ^0.8.0
sass: ^1.56.1 sass: ^1.56.1
typescript: ^4.6.4 typescript: ^4.6.4
@ -17,6 +18,7 @@ devDependencies:
'@types/bootstrap': 5.2.6 '@types/bootstrap': 5.2.6
'@types/jquery': 3.5.14 '@types/jquery': 3.5.14
bootstrap: 5.2.3_@popperjs+core@2.11.6 bootstrap: 5.2.3_@popperjs+core@2.11.6
bootstrap-icons: 1.10.2
pocketbase: 0.8.0 pocketbase: 0.8.0
sass: 1.56.1 sass: 1.56.1
typescript: 4.9.3 typescript: 4.9.3
@ -74,6 +76,10 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/bootstrap-icons/1.10.2:
resolution: {integrity: sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA==}
dev: true
/bootstrap/5.2.3_@popperjs+core@2.11.6: /bootstrap/5.2.3_@popperjs+core@2.11.6:
resolution: {integrity: sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==} resolution: {integrity: sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==}
peerDependencies: peerDependencies:

View File

@ -6,39 +6,6 @@
</head> </head>
<body> <body>
<pre id="content">Authenticating...</pre> <pre id="content">Authenticating...</pre>
<script type="module" src="/src/pages/redirect.ts"></script>
<script src="https://cdn.jsdelivr.net/gh/pocketbase/js-sdk@master/dist/pocketbase.umd.js"></script>
<script type="text/javascript">
const pb = new PocketBase("https://imlighty-redesigned-enigma-75x56qwx6rhrv7v-8090.preview.app.github.dev/");
const redirectUrl = 'https://imlighty-redesigned-enigma-75x56qwx6rhrv7v-5173.preview.app.github.dev/redirect.html';
// parse the query parameters from the redirected url
const params = (new URL(window.location)).searchParams;
// load the previously stored provider's data
const provider = JSON.parse(localStorage.getItem('provider'))
// compare the redirect's state param and the stored provider's one
if (provider.state !== params.get('state')) {
throw "State parameters don't match.";
}
// authenticate
pb.collection('users').authWithOAuth2(
provider.name,
params.get('code'),
provider.codeVerifier,
redirectUrl,
// pass optional user create data
{
emailVisibility: false,
}
).then((authData) => {
// document.getElementById('content').innerText = JSON.stringify(authData, null, 2);
window.location = '/'
}).catch((err) => {
document.getElementById('content').innerText = "Failed to exchange code.\n" + err;
});
</script>
</body> </body>
</html> </html>

View File

@ -1,4 +1,5 @@
import './scss/styles.scss' import './scss/styles.scss'
import 'bootstrap-icons/font/bootstrap-icons.css'
import * as bootstrap from 'bootstrap' import * as bootstrap from 'bootstrap'
import pocketbase from 'pocketbase' import pocketbase from 'pocketbase'
@ -12,15 +13,47 @@ console.log("%cWARNING!!!" +
"color: red; font-size: 30px;", "color: red; font-size: 30px;",
"color: black; font-size: 15px;") "color: black; font-size: 15px;")
const params = (new URL(window.location.toString())).searchParams
if (params.get('confirm_token')) {
await pb.collection('users').confirmVerification(params.get('confirm_token')!).then(() => {
prepareLoginModal(false)
$('#loginModal').modal('show')
$('#verification-alert').html(`
<div class="alert alert-success alert-dismissible fade show" role="alert">
<strong>Success!</strong> Your email address has been verified.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
`)
}).catch((err) => {
prepareLoginModal(false)
$('#loginModal').modal('show')
$('#verification-alert').html(`
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Error!</strong> ${err}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
`)
})
}
if (params.get('page')) {
} else {
const homepage = await import('./pages/homepage')
homepage.default()
}
let gdprConsent = localStorage.getItem("apexie-gdprconsent")! let gdprConsent = localStorage.getItem("apexie-gdprconsent")!
let gdprConsentModal = new bootstrap.Modal(document.getElementById("gdprconsent")!) let gdprConsentModal = new bootstrap.Modal(document.getElementById("gdprconsent")!)
async function loadLinks() { async function loadLinks(register?: boolean) {
const authMethods = await pb.collection('users').listAuthMethods() const authMethods = await pb.collection('users').listAuthMethods()
const listItems: any = [] const listItems: any = []
for (const provider of authMethods.authProviders) { for (const provider of authMethods.authProviders) {
const $li = $(`<li><a>Login with ${provider.name}</a></li>`) let $li = $(`<li><a>Login with ${provider.name}</a></li>`)
if (register) $li = $(`<li><a>Register with ${provider.name}</a></li>`)
$li.find('a') $li.find('a')
.attr('href', provider.authUrl + redirectUrl) .attr('href', provider.authUrl + redirectUrl)
@ -37,17 +70,61 @@ async function loadLinks() {
} }
document.getElementById('login_button')!.addEventListener('click', () => loadLinks()) async function prepareLoginModal(register: boolean) {
if (register) {
document.querySelector<HTMLHeadingElement>('#loginModalLabel')!.innerText = 'Create your Apexie ID'
document.querySelector<HTMLDivElement>('#loginModalFooter')!.innerHTML = `
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="account-register-submit">Register</button>
`
document.querySelector<HTMLButtonElement>('#account-register-submit')!.addEventListener('click', async () => {
const data = {
"username": document.querySelector<HTMLInputElement>('#account-username')!.value,
"email": document.querySelector<HTMLInputElement>('#account-email')!.value,
"emailVisibility": false,
"password": document.querySelector<HTMLInputElement>('#account-password')!.value,
"passwordConfirm": document.querySelector<HTMLInputElement>('#account-confirm-password')!.value,
"name": document.querySelector<HTMLInputElement>('#account-username')!.value,
}
let login_error = document.querySelector<HTMLDivElement>('#login-error')! await pb.collection('users').create(data);
document.getElementById('account-login')!.addEventListener('click', async () => { await pb.collection('users').requestVerification(data.email)
$('#verification-alert').html(`
<div class="alert alert-success alert-dismissible fade show" role="alert">
<strong>Verification email sent!</strong> Please check your inbox and click the link to verify your email address.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
`)
})
} else {
document.querySelector<HTMLHeadingElement>('#loginModalLabel')!.innerText = 'Login to your Apexie ID'
document.querySelector<HTMLDivElement>('#loginModalFooter')!.innerHTML = `
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" id="account-register" class="btn btn-primary">Register</button>
<button type="submit" id="account-login" class="btn btn-primary">Login</button>
`
}
document.querySelector<HTMLDivElement>('#account-username-fill')!.hidden = !register
document.querySelector<HTMLDivElement>('#account-confirm-password-fill')!.hidden = !register
document.getElementById('account-register')!.addEventListener('click', () => prepareLoginModal(true))
document.getElementById('account-login')!.addEventListener('click', async () => {
login_error.innerHTML = '' login_error.innerHTML = ''
await pb.collection('users').authWithPassword((<HTMLInputElement>document.getElementById('account-email')!).value, (<HTMLInputElement>document.getElementById('account-password')!).value).catch((err) => { await pb.collection('users').authWithPassword((<HTMLInputElement>document.getElementById('account-email')!).value, (<HTMLInputElement>document.getElementById('account-password')!).value).catch(() => {
login_error.innerHTML = 'Failed to authenticate. Please try again.<p>' login_error.innerHTML = 'Failed to authenticate. Please try again.<p>'
document.querySelector<HTMLInputElement>('#account-password')!.value = '' document.querySelector<HTMLInputElement>('#account-password')!.value = ''
}) })
}) })
loadLinks(register)
}
document.getElementById('login_button')!.addEventListener('click', () => prepareLoginModal(false))
let login_error = document.querySelector<HTMLDivElement>('#login-error')!
if (!gdprConsent) { if (!gdprConsent) {
gdprConsentModal.show() gdprConsentModal.show()

View File

@ -1,6 +1,7 @@
import './scss/styles.scss' import '../scss/styles.scss'
document.querySelector<HTMLDivElement>('#main-app')!.innerHTML = ` export default function () {
document.querySelector<HTMLDivElement>('#main-app')!.innerHTML = `
<section class="bg-dark text-light p-5 p-lg-0 pt-lg-5 text-center text-sm-start"> <section class="bg-dark text-light p-5 p-lg-0 pt-lg-5 text-center text-sm-start">
<div class="container"> <div class="container">
<div class="d-sm-flex align-items-center justify-content-between"> <div class="d-sm-flex align-items-center justify-content-between">
@ -81,7 +82,7 @@ document.querySelector<HTMLDivElement>('#main-app')!.innerHTML = `
<img src="assets/img/osu!stream.jpg" class="img-fluid" alt="" /> <img src="assets/img/osu!stream.jpg" class="img-fluid" alt="" />
</div> </div>
<div class="col-md p-5"> <div class="col-md p-5">
<h2>osu!stream revived</h2> <h2>osu!restream</h2>
<p class="lead"> <p class="lead">
The best take on an osu!stream port The best take on an osu!stream port
that you can find. that you can find.
@ -139,4 +140,5 @@ document.querySelector<HTMLDivElement>('#main-app')!.innerHTML = `
</a> </a>
</div> </div>
</footer> </footer>
` `
}

32
src/pages/redirect.ts Normal file
View File

@ -0,0 +1,32 @@
import PocketBase from 'pocketbase'
const pb = new PocketBase("https://imlighty-redesigned-enigma-75x56qwx6rhrv7v-8090.preview.app.github.dev/")
const redirectUrl = 'https://imlighty-redesigned-enigma-75x56qwx6rhrv7v-5173.preview.app.github.dev/redirect.html'
// parse the query parameters from the redirected url
const params = (new URL(window.location.toString())).searchParams
// load the previously stored provider's data
const provider = JSON.parse(localStorage.getItem('provider')!)
// compare the redirect's state param and the stored provider's one
if (provider.state !== params.get('state')) {
throw "State parameters don't match."
}
// authenticate
pb.collection('users').authWithOAuth2(
provider.name,
params.get('code')!,
provider.codeVerifier,
redirectUrl,
// pass optional user create data
{
emailVisibility: false,
}
).then(() => {
// document.getElementById('content').innerText = JSON.stringify(authData, null, 2);
new Location().assign('/')
}).catch((err) => {
document.getElementById('content')!.innerText = "Failed to exchange code.\n" + err
})

View File

@ -3,7 +3,7 @@ import path from 'path'
export default { export default {
resolve: { resolve: {
alias: { alias: {
'~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap'), '~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap')
} }
}, },
server: { server: {