Skip to content

Commit

Permalink
Merge pull request #14 from MaddyGuthridge/maddy-password-change-ui
Browse files Browse the repository at this point in the history
Implement UI for changing auth information
  • Loading branch information
MaddyGuthridge authored Sep 29, 2024
2 parents 061bc58 + 7ddf8aa commit 728690b
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 122 deletions.
36 changes: 23 additions & 13 deletions src/components/navbar/Navbar.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts">
import { dev } from '$app/environment';
import { goto } from '$app/navigation';
import api from '$endpoints';
import type { ConfigJson } from '$lib/server/data/config';
import Separator from '$components/Separator.svelte';
import { dev } from "$app/environment";
import { goto } from "$app/navigation";
import api from "$endpoints";
import type { ConfigJson } from "$lib/server/data/config";
import Separator from "$components/Separator.svelte";
export let path: { url: string, txt: string }[];
export let path: { url: string; txt: string }[];
export let config: ConfigJson;
/** Whether the user is logged in. Set to undefined if auth is disabled */
export let loggedIn: boolean | undefined;
Expand All @@ -16,16 +16,26 @@
location.reload();
}
/**
* Go to the login page, with the from parameter determining the origin page.
*/
async function gotoLogin() {
await goto(`/admin/login?from=${window.location.pathname}`);
}
/** Clear all data, and take the user to the firstrun page */
async function clear() {
await api().debug.clear();
await goto('/admin/firstrun');
await goto("/admin/firstrun");
}
// This function needs to accept `path` as an input, otherwise the links
// stop being reactive due to cacheing or something
function pathTo(path: { url: string, txt: string }[], i: number) {
return path.slice(0, i + 1).map(p => p.url).join('/');
function pathTo(path: { url: string; txt: string }[], i: number) {
return path
.slice(0, i + 1)
.map((p) => p.url)
.join("/");
}
</script>

Expand All @@ -38,7 +48,7 @@
<a href="/">{config.siteShortName}</a> /
{#each path.slice(0, -1) as p, i}
<a href="/{pathTo(path, i)}">{p.txt}</a>
{'/ '}
{"/ "}
{/each}
{path[path.length - 1].txt}
</h1>
Expand All @@ -48,14 +58,14 @@
<!-- Control buttons -->
<span id="control-buttons">
{#if loggedIn}
<button on:click={() => goto('/admin')}> Admin </button>
<button on:click={() => goto("/admin")}> Admin </button>
<button on:click={logOut}> Log out </button>
{:else if loggedIn !== undefined}
<!-- Only include a login button if logging in is enabled -->
<button on:click={() => goto('/admin/login')}> Log in </button>
<button on:click={gotoLogin}> Log in </button>
{/if}
<!-- About button navigates to about page -->
<button on:click={() => goto('/about')}> About </button>
<button on:click={() => goto("/about")}> About </button>
<!-- In dev mode, add a quick shortcut to delete everything -->
{#if dev}
<Separator />
Expand Down
107 changes: 18 additions & 89 deletions src/routes/admin/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
<script lang="ts">
import api from '$endpoints';
import Background from '$components/Background.svelte';
import Navbar from '$components/navbar';
import Paper from '$components/Paper.svelte';
import consts from '$lib/consts';
export let data: import('./$types').PageData;
// Git setup
let gitUrl = '';
async function submitSwitchToGit() {
await api().admin.git.init(gitUrl);
}
// Git controls
let commitMessage = '';
async function gitCommit() {
await api().admin.git.commit(commitMessage);
}
import Background from "$components/Background.svelte";
import Navbar from "$components/navbar";
import Paper from "$components/Paper.svelte";
import consts from "$lib/consts";
import GitSettings from "./GitSettings.svelte";
import ChangePassword from "./ChangePassword.svelte";
import ReloadData from "./ReloadData.svelte";
import LogOutAll from "./LogOutAll.svelte";
export let data: import("./$types").PageData;
</script>

<svelte:head>
<title>Admin - {data.globals.config.siteName}</title>
<meta name="generator" content="{consts.APP_NAME}">
<meta name="theme-color" content="{data.globals.config.color}">
<meta name="generator" content={consts.APP_NAME} />
<meta name="theme-color" content={data.globals.config.color} />
<!-- Prevent web crawlers from indexing the admin page -->
<meta name="robots" content="noindex">
<meta name="robots" content="noindex" />
</svelte:head>

<Navbar
path={[{ txt: 'Admin', url: 'admin' }]}
path={[{ txt: "Admin", url: "admin" }]}
config={data.globals.config}
loggedIn={true}
/>
Expand All @@ -42,70 +31,10 @@
<div id="paper-container">
<Paper>
<div id="contents">
<div>
{#if data.repo}
<h2>Git status</h2>
<p>Current branch: {data.repo.branch}</p>
<p>Current commit: {data.repo.commit}</p>
<p>
{#if data.repo.behind}
{data.repo.behind} commits behind.
{/if}
{#if data.repo.ahead}
{data.repo.ahead} commits ahead.
{/if}
</p>

<!-- Push/pull -->
{#if data.repo.behind}
<button on:click={() => api().admin.git.push()}>Push</button>
{:else if data.repo.ahead}
<button on:click={() => api().admin.git.pull()}>Pull</button>
{/if}

<!-- Commit -->
{#if !data.repo.clean}

<h3>Changes</h3>

<ul>
{#each data.repo.changes as change}
{#if change.from}
<li>Rename {change.from} to ({change.path})</li>
{:else if change.index === '?'}
<li>Create {change.path}</li>
{:else if change.index === 'D'}
<li>Delete {change.path}</li>
{:else}
<li>Update {change.path}</li>
{/if}
{/each}
</ul>

<form on:submit|preventDefault={gitCommit}>
<input required type="text" name="commit-message" id="commit-message" placeholder="Commit message" bind:value={commitMessage}>
<input type="submit" value="Commit changes">
</form>
{/if}

{:else}
<h2>Git is currently not in use</h2>

You can use a Git repository to back up your portfolio data. Enter the
clone URL for an empty Git repository and it will be set up for you.

<form on:submit|preventDefault={submitSwitchToGit}>
<input required type="text" name="git-url" id="git-url" placeholder="git@github.com:MaddyGuthridge/Minifolio.git" bind:value={gitUrl}>
<input type="submit" value="Switch to a Git repository">
</form>
{/if}
</div>
<div>
<h2>Reload data from disk</h2>
If you have edited your data manually, you can use this button to
refresh it.
<button on:click={() => api().admin.data.refresh()}>Refresh data</button>
</div>
<GitSettings {data} />
<ChangePassword username={"admin"} />
<LogOutAll />
<ReloadData />
</div>
</Paper>
</div>
Expand Down
63 changes: 63 additions & 0 deletions src/routes/admin/ChangePassword.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<script lang="ts">
import api from "$endpoints";
export let username: string;
let originalPassword = "";
let newPassword = "";
let repeatNewPassword = "";
async function submitChangePassword() {
await api().admin.auth.change(username, originalPassword, newPassword);
originalPassword = "";
newPassword = "";
repeatNewPassword = "";
}
</script>

<div>
<h2>Change authentication</h2>
<form on:submit={submitChangePassword}>
<p>
Username
<br />
<input placeholder="Your account username" bind:value={username} />
</p>
<p>
Original password
<br />
<input
type="password"
placeholder="Your original password"
bind:value={originalPassword}
/>
</p>
<p>
New password
<br />
<input
type="password"
placeholder="A unique and secure password"
bind:value={newPassword}
/>
</p>
<p>
Repeat new password
<br />
<input
type="password"
placeholder="Your new password again"
bind:value={repeatNewPassword}
/>
</p>
{#if newPassword != repeatNewPassword}
<p>New passwords much match</p>
{/if}
<p>
<input
type="submit"
value="Change password"
disabled={newPassword != repeatNewPassword}
/>
</p>
</form>
</div>
93 changes: 93 additions & 0 deletions src/routes/admin/GitSettings.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<script lang="ts">
import api from "$endpoints";
export let data: import("./$types").PageData;
// Git setup
let gitUrl = "";
async function submitSwitchToGit() {
await api().admin.git.init(gitUrl);
}
// Git controls
let commitMessage = "";
async function gitCommit() {
await api().admin.git.commit(commitMessage);
}
</script>

<div>
{#if data.repo}
<h2>Git status</h2>
<p>Current branch: {data.repo.branch}</p>
<p>Current commit: {data.repo.commit}</p>
<p>
{#if data.repo.behind}
{data.repo.behind} commits behind.
{/if}
{#if data.repo.ahead}
{data.repo.ahead} commits ahead.
{/if}
</p>

<!-- Push/pull -->
{#if data.repo.behind}
<button on:click={() => api().admin.git.push()}>Push</button>
{:else if data.repo.ahead}
<button on:click={() => api().admin.git.pull()}>Pull</button>
{/if}

<!-- Commit -->
{#if data.repo.clean}
<h3>Changes</h3>
Working tree clean.
{:else}
<h3>Changes</h3>

<ul>
{#each data.repo.changes as change}
{#if change.from}
<li>Rename {change.from} to ({change.path})</li>
{:else if change.index === "?"}
<li>Create {change.path}</li>
{:else if change.index === "D"}
<li>Delete {change.path}</li>
{:else}
<li>Update {change.path}</li>
{/if}
{/each}
</ul>

<form on:submit|preventDefault={gitCommit}>
<input
required
type="text"
name="commit-message"
id="commit-message"
placeholder="Commit message"
bind:value={commitMessage}
/>
<input type="submit" value="Commit changes" />
</form>
{/if}
{:else}
<h2>Git is currently not in use</h2>

You can use a Git repository to back up your portfolio data. Enter the clone
URL for an empty Git repository and it will be set up for you.

<form on:submit|preventDefault={submitSwitchToGit}>
<input
required
type="text"
name="git-url"
id="git-url"
placeholder="git@github.com:MaddyGuthridge/Minifolio.git"
bind:value={gitUrl}
/>
<input type="submit" value="Switch to a Git repository" />
</form>
{/if}
</div>
15 changes: 15 additions & 0 deletions src/routes/admin/LogOutAll.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import { goto } from "$app/navigation";
import api from "$endpoints";
async function logOut() {
await api().admin.auth.revoke();
goto("/admin/login");
}
</script>

<div>
<h2>Log out of all sessions</h2>
<p>This will sign you out on all of your devices (including this one).</p>
<button on:click={logOut}>Log out of all sessions</button>
</div>
9 changes: 9 additions & 0 deletions src/routes/admin/ReloadData.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import api from "$endpoints";
</script>

<div>
<h2>Reload data from disk</h2>
If you have edited your data manually, you can use this button to refresh it.
<button on:click={() => api().admin.data.refresh()}>Refresh data</button>
</div>
3 changes: 2 additions & 1 deletion src/routes/admin/login/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export async function load(req) {
loggedIn = true;
} catch { /* empty */ }
if (loggedIn) {
redirect(303, '/admin');
// If they are logged in, redirect them to the `from` URL if it exists.
redirect(303, req.url.searchParams.get("from") || '/');
}
const globals = await getPortfolioGlobals();
return { globals };
Expand Down
Loading

0 comments on commit 728690b

Please sign in to comment.