Skip to content

Commit a5a2a8d

Browse files
committed
Add log out button
1 parent a2b3c78 commit a5a2a8d

File tree

5 files changed

+69
-4
lines changed

5 files changed

+69
-4
lines changed

frontend/src/components/Header.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ header .user-info h5 {
4242
header .user-info h5 {
4343
font-weight: 500;
4444
}
45+
46+
header .user-info h5 > a {
47+
cursor: pointer;
48+
font-weight: 600;
49+
}

frontend/src/components/Header.tsx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import "./Header.css";
2+
import { useMutation, useQueryClient } from "@tanstack/react-query";
23
import type { User } from "../types";
34

45
function ExpiryText({ expiry }: { expiry: number }) {
@@ -17,16 +18,39 @@ function ExpiryText({ expiry }: { expiry: number }) {
1718
return <span className="warn">{daysUntilExpiry} days</span>;
1819
}
1920

21+
function LogoutButton() {
22+
const queryClient = useQueryClient();
23+
24+
const { mutate } = useMutation({
25+
mutationFn: async () => {
26+
const response = await fetch("/api/user", {
27+
method: "DELETE",
28+
});
29+
if (!response.ok) {
30+
const data = await response.json();
31+
throw Error(data.error);
32+
}
33+
},
34+
onSuccess: () => {
35+
queryClient.invalidateQueries({ queryKey: ["user"] });
36+
},
37+
});
38+
39+
return <a onClick={() => mutate()}>Log out.</a>;
40+
}
41+
2042
function UserInfo({ user }: { user: User | null }) {
2143
return (
2244
<div className="user-info">
2345
<h4>{user ? user.name : "No Anilist token set"}</h4>
2446

2547
{user ? (
26-
<h5>
27-
Token will expire in approximately <ExpiryText expiry={user.expiry} />
28-
.
29-
</h5>
48+
<>
49+
<h5>
50+
Token will expire in approximately{" "}
51+
<ExpiryText expiry={user.expiry} />. <LogoutButton />
52+
</h5>
53+
</>
3054
) : (
3155
<h5>Token must be set in order to use anifunnel</h5>
3256
)}

src/api.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,31 @@ pub async fn user_post(
183183
}
184184
Ok(status::Accepted(()))
185185
}
186+
187+
#[delete("/api/user")]
188+
/// Clear the authentication data from the database and application state.
189+
pub async fn user_delete(
190+
mut db: Connection<db::AnifunnelDatabase>,
191+
state: &rocket::State<state::Global>,
192+
) -> Result<status::Accepted<()>, responders::ErrorResponder> {
193+
match db::clear_authentication(&mut db).await {
194+
Ok(_) => {
195+
info!("Authentication data cleared from the database");
196+
}
197+
Err(err) => {
198+
error!("Error while trying to clear authentication: {}", err);
199+
return Err(responders::ErrorResponder::with_message(
200+
"Error while clearing authentication data".into(),
201+
));
202+
}
203+
}
204+
205+
// Update the state to clear the client.
206+
let anifunnel_state: &state::Global = state.inner();
207+
{
208+
let mut writer = anifunnel_state.anilist_client.write().await;
209+
*writer = None;
210+
info!("Application state cleared");
211+
}
212+
Ok(status::Accepted(()))
213+
}

src/db.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ impl AnimeOverride {
2323
}
2424
}
2525

26+
/// Clear all authentication data from the database.
27+
pub async fn clear_authentication(
28+
db: &mut SqliteConnection,
29+
) -> Result<SqliteQueryResult, sqlx::Error> {
30+
sqlx::query("DELETE FROM authentication").execute(db).await
31+
}
32+
2633
/// Clean up expired tokens on start-up.
2734
async fn remove_expired_tokens(db: &mut SqliteConnection) {
2835
log::info!("Removing expired Anilist tokens...");

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ fn build_server(
215215
scrobble,
216216
api::user_get,
217217
api::user_post,
218+
api::user_delete,
218219
api::anime_get,
219220
api::anime_override,
220221
favicon_svg,

0 commit comments

Comments
 (0)