File tree Expand file tree Collapse file tree 5 files changed +69
-4
lines changed
Expand file tree Collapse file tree 5 files changed +69
-4
lines changed Original file line number Diff line number Diff line change @@ -42,3 +42,8 @@ header .user-info h5 {
4242header .user-info h5 {
4343 font-weight : 500 ;
4444}
45+
46+ header .user-info h5 > a {
47+ cursor : pointer;
48+ font-weight : 600 ;
49+ }
Original file line number Diff line number Diff line change 11import "./Header.css" ;
2+ import { useMutation , useQueryClient } from "@tanstack/react-query" ;
23import type { User } from "../types" ;
34
45function 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+
2042function 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 ) }
Original file line number Diff line number Diff 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+ }
Original file line number Diff line number Diff 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.
2734async fn remove_expired_tokens ( db : & mut SqliteConnection ) {
2835 log:: info!( "Removing expired Anilist tokens..." ) ;
Original file line number Diff line number Diff 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,
You can’t perform that action at this time.
0 commit comments