Add forms for changing username, email and password
Signed-off-by: Aelita4 <kontakt@mikorosa.pl>
This commit is contained in:
parent
eafea0c1f5
commit
2945828935
|
@ -2,8 +2,21 @@
|
|||
"Header": {
|
||||
"user": "user {}"
|
||||
},
|
||||
"Label": {
|
||||
"userCreationDate": "Account created at {}",
|
||||
"newUsernamePlaceholder": "new username",
|
||||
"newEmailPlaceholder": "new email",
|
||||
"newPasswordPlaceholder": "new password",
|
||||
"newPasswordVerifyPlaceholder": "verify",
|
||||
"passwordPlaceholder": "password",
|
||||
"oldPasswordPlaceholder": "old password"
|
||||
},
|
||||
"Link": {
|
||||
"logout": "Log out",
|
||||
"build": "[build]"
|
||||
"build": "[build]",
|
||||
|
||||
"changeUsername": "Change username",
|
||||
"changeEmail": "Change email",
|
||||
"changePassword": "Change password",
|
||||
"logout": "[log out]"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
import type { ObjectId } from "mongodb";
|
||||
import { Users } from "../../../../lib/db/mongodb";
|
||||
import { getUserById, getUserByNickOrEmail } from "../../../../lib/db/users";
|
||||
import validateAccessToken from "../../../../lib/utils/validateAccessToken";
|
||||
import { hash, compare } from "bcrypt";
|
||||
|
||||
if(Astro.request.method === "PATCH") {
|
||||
const response = await validateAccessToken(Astro.request);
|
||||
if(response instanceof Response) return response;
|
||||
|
||||
const { path } = Astro.params;
|
||||
|
||||
const body = await Astro.request.json();
|
||||
|
||||
if(!body || !body['password']) return new Response(
|
||||
JSON.stringify({
|
||||
code: 400,
|
||||
message: "Bad Request"
|
||||
}), { status: 400 }
|
||||
);
|
||||
|
||||
const user = await getUserById(response.user as ObjectId);
|
||||
if(!user) return new Response(
|
||||
JSON.stringify({
|
||||
code: 404,
|
||||
message: "Not Found"
|
||||
}), { status: 404 }
|
||||
);
|
||||
|
||||
if(!(await compare(body['password'], user.password))) return new Response(
|
||||
JSON.stringify({
|
||||
code: 401,
|
||||
message: "Unauthorized"
|
||||
}), { status: 401 }
|
||||
);
|
||||
|
||||
switch(path) {
|
||||
case 'username':
|
||||
if(!body['newUsername']) return new Response(
|
||||
JSON.stringify({
|
||||
code: 400,
|
||||
message: "Bad Request"
|
||||
}), { status: 400 }
|
||||
);
|
||||
|
||||
if(await getUserByNickOrEmail(body['newUsername'])) return new Response(
|
||||
JSON.stringify({
|
||||
code: 409,
|
||||
message: "Conflict"
|
||||
}), { status: 409 }
|
||||
);
|
||||
|
||||
(await Users()).updateOne({ _id: user._id }, { $set: { username: body['newUsername'] } })
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
code: 200,
|
||||
message: "OK"
|
||||
})
|
||||
);
|
||||
case 'email':
|
||||
if(!body['newEmail']) return new Response(
|
||||
JSON.stringify({
|
||||
code: 400,
|
||||
message: "Bad Request"
|
||||
}), { status: 400 }
|
||||
);
|
||||
|
||||
if(await getUserByNickOrEmail(body['newEmail'])) return new Response(
|
||||
JSON.stringify({
|
||||
code: 409,
|
||||
message: "Conflict"
|
||||
}), { status: 409 }
|
||||
);
|
||||
|
||||
(await Users()).updateOne({ _id: user._id }, { $set: { email: body['newEmail'] } })
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
code: 200,
|
||||
message: "OK"
|
||||
})
|
||||
);
|
||||
case 'password':
|
||||
if(!body['newPassword']) return new Response(
|
||||
JSON.stringify({
|
||||
code: 400,
|
||||
message: "Bad Request"
|
||||
}), { status: 400 }
|
||||
);
|
||||
|
||||
const newPassword = await hash(body['newPassword'], 10);
|
||||
|
||||
(await Users()).updateOne({ _id: user._id }, { $set: { password: newPassword } })
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
code: 200,
|
||||
message: "OK"
|
||||
})
|
||||
);
|
||||
default:
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
code: 400,
|
||||
message: "Bad Request"
|
||||
}), { status: 400 }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
code: 405,
|
||||
message: "Method Not Allowed"
|
||||
}), { status: 405 }
|
||||
);
|
||||
}
|
||||
---
|
|
@ -0,0 +1,230 @@
|
|||
---
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
import NavBar from '../../components/NavBar.astro';
|
||||
import { getUserByNickOrEmail, getUserResources, updateUserResources } from '../../lib/db/users';
|
||||
import { getHighestWeightedLanguage, getLocales } from '../../lib/lang/langDriver';
|
||||
import ResourceBar from '../../components/ResourceBar.astro';
|
||||
import format from '../../lib/utils/format';
|
||||
|
||||
const loggedToken = Astro.cookies.get('sessionToken')?.value ?? null;
|
||||
const username = Astro.cookies.get('username')?.value ?? "";
|
||||
|
||||
if(loggedToken === null || username === "") return Astro.redirect('/');
|
||||
|
||||
const locale = getHighestWeightedLanguage(Astro.request.headers.get('accept-language'));
|
||||
|
||||
const user = await getUserByNickOrEmail(username);
|
||||
|
||||
const langGame = await getLocales(locale, 'game');
|
||||
---
|
||||
|
||||
<Layout title="Profile">
|
||||
<NavBar loggedIn="true" active="profile" />
|
||||
<ResourceBar loggedIn="true" />
|
||||
|
||||
<div class="wrapper">
|
||||
<h3>{format(langGame['Label_userCreationDate'], user?.createdAt.toISOString().slice(0, 19).replace(/-/g, "/").replace("T", " ").toString() ?? "")}</h3>
|
||||
<a href="/logout" class="a-button">{langGame['Link_logout']}</a>
|
||||
</div>
|
||||
<form id="changeUsernameForm" class="data-form">
|
||||
<input class="data-form-input" type="text" name="username" placeholder={langGame['Label_newUsernamePlaceholder']} />
|
||||
<input class="data-form-input" type="password" name="password" placeholder={langGame['Label_passwordPlaceholder']} />
|
||||
<input class="data-form-button" type="button" value={langGame['Link_changeUsername']} />
|
||||
</form>
|
||||
<form id="changeEmailForm" class="data-form">
|
||||
<input class="data-form-input" type="email" name="email" placeholder={langGame['Label_newEmailPlaceholder']} />
|
||||
<input class="data-form-input" type="password" name="password" placeholder={langGame['Label_passwordPlaceholder']} />
|
||||
<input class="data-form-button" type="button" value={langGame['Link_changeEmail']} />
|
||||
</form>
|
||||
<form id="changePasswordForm" class="data-form">
|
||||
<input class="data-form-input" type="password" name="oldPassword" placeholder={langGame['Label_oldPasswordPlaceholder']} />
|
||||
<input class="data-form-input" type="password" name="password1" placeholder={langGame['Label_newPasswordPlaceholder']} />
|
||||
<input class="data-form-input" type="password" name="password2" placeholder={langGame['Label_newPasswordVerifyPlaceholder']} />
|
||||
<input class="data-form-button" type="button" value={langGame['Link_changePassword']} />
|
||||
</form>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.data-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.data-form-input {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.data-form-button {
|
||||
color: red;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 2rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: auto;
|
||||
padding: 1rem;
|
||||
width: 800px;
|
||||
max-width: calc(100% - 2rem);
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.astro-a {
|
||||
position: absolute;
|
||||
top: -32px;
|
||||
left: 50%;
|
||||
transform: translatex(-50%);
|
||||
width: 220px;
|
||||
height: auto;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.text-gradient {
|
||||
background-image: var(--accent-gradient);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-size: 400%;
|
||||
background-position: 0%;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
margin-bottom: 2rem;
|
||||
border: 1px solid rgba(var(--accent-light), 25%);
|
||||
background: linear-gradient(rgba(var(--accent-dark), 66%), rgba(var(--accent-dark), 33%));
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.instructions code {
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
background: rgba(var(--accent-light), 12%);
|
||||
color: rgb(var(--accent-light));
|
||||
border-radius: 4px;
|
||||
padding: 0.3em 0.4em;
|
||||
}
|
||||
|
||||
.instructions strong {
|
||||
color: rgb(var(--accent-light));
|
||||
}
|
||||
|
||||
.link-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
||||
gap: 2rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.a-button {
|
||||
text-decoration: none;
|
||||
color: green;
|
||||
}
|
||||
|
||||
.a-button:hover {
|
||||
color: lime;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
const changeUsernameForm = document.getElementById('changeUsernameForm');
|
||||
if(changeUsernameForm === null) console.error("changeUsernameForm is null");
|
||||
else {
|
||||
changeUsernameForm.querySelector('input[type="button"]')?.addEventListener("click", async () => {
|
||||
const newUsername = (changeUsernameForm.querySelector('input[name="username"]') as HTMLInputElement).value;
|
||||
const password = (changeUsernameForm.querySelector('input[name="password"]') as HTMLInputElement).value;
|
||||
|
||||
const request = await fetch('/api/auth/changeUserData/username', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
newUsername,
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
const response = await request.json();
|
||||
console.log(response);
|
||||
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const changeEmailForm = document.getElementById('changeEmailForm');
|
||||
if(changeEmailForm === null) console.error("changeEmailForm is null");
|
||||
else {
|
||||
changeEmailForm.querySelector('input[type="button"]')?.addEventListener("click", async () => {
|
||||
const newEmail = (changeEmailForm.querySelector('input[name="email"]') as HTMLInputElement).value;
|
||||
const password = (changeEmailForm.querySelector('input[name="password"]') as HTMLInputElement).value;
|
||||
|
||||
const request = await fetch('/api/auth/changeUserData/email', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
newEmail,
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
const response = await request.json();
|
||||
console.log(response);
|
||||
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const changePasswordForm = document.getElementById('changePasswordForm');
|
||||
if(changePasswordForm === null) console.error("changePasswordForm is null");
|
||||
else {
|
||||
changePasswordForm.querySelector('input[type="button"]')?.addEventListener("click", async () => {
|
||||
const oldPassword = (changePasswordForm.querySelector('input[name="oldPassword"]') as HTMLInputElement).value;
|
||||
const password1 = (changePasswordForm.querySelector('input[name="password1"]') as HTMLInputElement).value;
|
||||
const password2 = (changePasswordForm.querySelector('input[name="password2"]') as HTMLInputElement).value;
|
||||
|
||||
if(password1 !== password2) return alert("Passwords don't match");
|
||||
else {
|
||||
const request = await fetch('/api/auth/changeUserData/password', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
password: oldPassword,
|
||||
newPassword: password1
|
||||
})
|
||||
});
|
||||
|
||||
const response = await request.json();
|
||||
console.log(response);
|
||||
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue