mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
Added deletion of users and export of data. GDPR..
This commit is contained in:
1 parent
1d8587744c
commit
2ea195475e
4 files changed
+335
No files matched your search
@@ -231,6 +231,40 @@ $PageSection = "Guide";
|
||||
has it can load the same Garden account and mess stuff up.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="Privacy"
|
||||
class="GuideSection"
|
||||
>
|
||||
<h2>Privacy and your data</h2>
|
||||
|
||||
<p>
|
||||
The Garden API stores the data needed to keep your
|
||||
account synchronized, including your Garden save,
|
||||
username, profile colour, Dew totals, and the time
|
||||
the server save was last updated. The server identifies
|
||||
the account using a one-way hash derived from your
|
||||
Account Key rather than storing the Account Key itself.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This browser stores your Account Key and a local copy
|
||||
of your Garden save so the same account can keep working
|
||||
between visits. If you set a username, some profile
|
||||
information and statistics can also appear on the
|
||||
public leaderboard.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/Pages/Profile.html#Account">Profile</a>
|
||||
page lets you export a JSON copy of the account data
|
||||
stored on the server, or permanently delete the account.
|
||||
Deleting removes the server account and clears the
|
||||
Account Key and local save from the browser where you
|
||||
perform the deletion. Other devices have their own local
|
||||
browser storage and cannot be cleared remotely.
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script src="/Scripts/Garden/PlantImages.js"></script>
|
||||
|
||||
@@ -320,6 +320,48 @@ $PageTitle = "Profile";
|
||||
></p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
||||
<h3>Account data</h3>
|
||||
|
||||
<p>
|
||||
Download a JSON copy of the Garden account
|
||||
data currently stored on the server. The
|
||||
Account Key is not included in this export.
|
||||
</p>
|
||||
|
||||
<div class="ProfileButtonRow">
|
||||
<button
|
||||
id="ExportAccountDataButton"
|
||||
type="button"
|
||||
>
|
||||
Export account data
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Delete account</h3>
|
||||
|
||||
<p class="ProfileDangerText">
|
||||
Permanently delete this Garden account from
|
||||
the server and clear its Account Key and save
|
||||
from this browser. This cannot be undone.
|
||||
</p>
|
||||
|
||||
<div class="ProfileButtonRow">
|
||||
<button
|
||||
id="DeleteAccountButton"
|
||||
class="ProfileDangerButton"
|
||||
type="button"
|
||||
>
|
||||
Delete account
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p
|
||||
id="AccountDataMessage"
|
||||
class="ProfileMessage"
|
||||
></p>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,16 @@ function StartAccount() {
|
||||
"ExportAccountKeyButton"
|
||||
);
|
||||
|
||||
const ExportDataButton =
|
||||
document.getElementById(
|
||||
"ExportAccountDataButton"
|
||||
);
|
||||
|
||||
const DeleteAccountButton =
|
||||
document.getElementById(
|
||||
"DeleteAccountButton"
|
||||
);
|
||||
|
||||
const ImportForm =
|
||||
document.getElementById(
|
||||
"ImportAccountForm"
|
||||
@@ -45,6 +55,16 @@ function StartAccount() {
|
||||
ExportAccountKey
|
||||
);
|
||||
|
||||
ExportDataButton.addEventListener(
|
||||
"click",
|
||||
ExportAccountData
|
||||
);
|
||||
|
||||
DeleteAccountButton.addEventListener(
|
||||
"click",
|
||||
DeleteAccount
|
||||
);
|
||||
|
||||
ImportForm.addEventListener(
|
||||
"submit",
|
||||
SubmitAccountImport
|
||||
@@ -272,6 +292,231 @@ function ExportAccountKey() {
|
||||
}
|
||||
|
||||
|
||||
async function ExportAccountData() {
|
||||
const Message =
|
||||
document.getElementById(
|
||||
"AccountDataMessage"
|
||||
);
|
||||
|
||||
const Button =
|
||||
document.getElementById(
|
||||
"ExportAccountDataButton"
|
||||
);
|
||||
|
||||
|
||||
Message.textContent =
|
||||
"Preparing account data...";
|
||||
|
||||
Button.disabled = true;
|
||||
|
||||
|
||||
try {
|
||||
const Result =
|
||||
await RequestAccountData(
|
||||
"Export"
|
||||
);
|
||||
|
||||
if (
|
||||
Result.Exists !== true ||
|
||||
Result.Data === undefined
|
||||
) {
|
||||
Message.textContent =
|
||||
"No server account data exists to export.";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const File =
|
||||
new Blob(
|
||||
[
|
||||
JSON.stringify(
|
||||
Result.Data,
|
||||
null,
|
||||
4
|
||||
) + "\n"
|
||||
],
|
||||
{
|
||||
type:
|
||||
"application/json;charset=utf-8"
|
||||
}
|
||||
);
|
||||
|
||||
const FileUrl =
|
||||
URL.createObjectURL(
|
||||
File
|
||||
);
|
||||
|
||||
const Link =
|
||||
document.createElement(
|
||||
"a"
|
||||
);
|
||||
|
||||
Link.href = FileUrl;
|
||||
Link.download =
|
||||
"SarahtoninGardenAccountData.json";
|
||||
|
||||
|
||||
document.body.appendChild(
|
||||
Link
|
||||
);
|
||||
|
||||
Link.click();
|
||||
Link.remove();
|
||||
|
||||
|
||||
URL.revokeObjectURL(
|
||||
FileUrl
|
||||
);
|
||||
|
||||
|
||||
Message.textContent =
|
||||
"Account data exported.";
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't export account data:",
|
||||
Error
|
||||
);
|
||||
|
||||
Message.textContent =
|
||||
"Couldn't export account data right now.";
|
||||
} finally {
|
||||
Button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function DeleteAccount() {
|
||||
const Message =
|
||||
document.getElementById(
|
||||
"AccountDataMessage"
|
||||
);
|
||||
|
||||
const Button =
|
||||
document.getElementById(
|
||||
"DeleteAccountButton"
|
||||
);
|
||||
|
||||
|
||||
const Confirmation =
|
||||
window.prompt(
|
||||
"Permanently delete this Garden account?\n\n" +
|
||||
"The server save and this browser's local " +
|
||||
"Account Key/save will be removed. This cannot " +
|
||||
"be undone.\n\n" +
|
||||
"Type DELETE to continue."
|
||||
);
|
||||
|
||||
|
||||
if (Confirmation !== "DELETE") {
|
||||
Message.textContent =
|
||||
Confirmation === null
|
||||
? "Account deletion cancelled."
|
||||
: "Account deletion cancelled: type DELETE exactly.";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Message.textContent =
|
||||
"Deleting account...";
|
||||
|
||||
Button.disabled = true;
|
||||
|
||||
|
||||
try {
|
||||
await RequestAccountData(
|
||||
"Delete",
|
||||
{
|
||||
Confirm: "DELETE"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
localStorage.removeItem(
|
||||
LocalSaveName
|
||||
);
|
||||
|
||||
localStorage.removeItem(
|
||||
SaveKeyName
|
||||
);
|
||||
|
||||
|
||||
Message.textContent =
|
||||
"Account deleted. Returning home...";
|
||||
|
||||
|
||||
window.location.replace(
|
||||
"/"
|
||||
);
|
||||
} catch (Error) {
|
||||
console.error(
|
||||
"Couldn't delete account:",
|
||||
Error
|
||||
);
|
||||
|
||||
Message.textContent =
|
||||
"Couldn't delete the account. Nothing was cleared locally.";
|
||||
|
||||
Button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function RequestAccountData(
|
||||
Action,
|
||||
ExtraData = {}
|
||||
) {
|
||||
const Response =
|
||||
await fetch(
|
||||
ApiUrl + "/AccountData.php",
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
headers: {
|
||||
"Content-Type":
|
||||
"application/json"
|
||||
},
|
||||
|
||||
body: JSON.stringify({
|
||||
SaveKey: GetSaveKey(),
|
||||
Action: Action,
|
||||
...ExtraData
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let Result;
|
||||
|
||||
try {
|
||||
Result =
|
||||
await Response.json();
|
||||
} catch (Error) {
|
||||
throw new Error(
|
||||
"Account data API returned an invalid response."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!Response.ok ||
|
||||
Result.Success !== true
|
||||
) {
|
||||
throw new Error(
|
||||
Result.Error ??
|
||||
(
|
||||
"Account data API returned HTTP " +
|
||||
Response.status
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
async function SubmitAccountImport(
|
||||
Event
|
||||
) {
|
||||
|
||||
@@ -973,6 +973,20 @@ input, button, textarea, select {
|
||||
color: var(--Subtext1);
|
||||
}
|
||||
|
||||
.ProfileDangerText {
|
||||
color: var(--Red);
|
||||
}
|
||||
|
||||
.ProfileSection .ProfileDangerButton {
|
||||
color: var(--Red);
|
||||
border-color: var(--Red);
|
||||
}
|
||||
|
||||
.ProfileSection .ProfileDangerButton:hover {
|
||||
color: var(--Red);
|
||||
border-color: var(--Red);
|
||||
}
|
||||
|
||||
.ProfileStatistics {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
Reference in new issue
Block a user