mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-14 10:48:12 +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.
|
has it can load the same Garden account and mess stuff up.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</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>
|
</main>
|
||||||
|
|
||||||
<script src="/Scripts/Garden/PlantImages.js"></script>
|
<script src="/Scripts/Garden/PlantImages.js"></script>
|
||||||
|
|||||||
@@ -320,6 +320,48 @@ $PageTitle = "Profile";
|
|||||||
></p>
|
></p>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</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>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,16 @@ function StartAccount() {
|
|||||||
"ExportAccountKeyButton"
|
"ExportAccountKeyButton"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ExportDataButton =
|
||||||
|
document.getElementById(
|
||||||
|
"ExportAccountDataButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
const DeleteAccountButton =
|
||||||
|
document.getElementById(
|
||||||
|
"DeleteAccountButton"
|
||||||
|
);
|
||||||
|
|
||||||
const ImportForm =
|
const ImportForm =
|
||||||
document.getElementById(
|
document.getElementById(
|
||||||
"ImportAccountForm"
|
"ImportAccountForm"
|
||||||
@@ -45,6 +55,16 @@ function StartAccount() {
|
|||||||
ExportAccountKey
|
ExportAccountKey
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ExportDataButton.addEventListener(
|
||||||
|
"click",
|
||||||
|
ExportAccountData
|
||||||
|
);
|
||||||
|
|
||||||
|
DeleteAccountButton.addEventListener(
|
||||||
|
"click",
|
||||||
|
DeleteAccount
|
||||||
|
);
|
||||||
|
|
||||||
ImportForm.addEventListener(
|
ImportForm.addEventListener(
|
||||||
"submit",
|
"submit",
|
||||||
SubmitAccountImport
|
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(
|
async function SubmitAccountImport(
|
||||||
Event
|
Event
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -973,6 +973,20 @@ input, button, textarea, select {
|
|||||||
color: var(--Subtext1);
|
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 {
|
.ProfileStatistics {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in new issue
Block a user