Repository: IgnisDa/ryot (language: rust)

Issue:
 [FEATURE REQUEST] Romaji titles from anilist
              Anilist has three options for anime and manga names: Native (which seems to be the current one), English (which also seems available as an option in Ryot) and Romaji.

Romaji is English transliteration of Japanese text. So in the above case, it should return the full transliterated title of "Mushoku Tensei: Isekai Ittara Honki Dasu", or "Shingeki no Kyojin" if it were "Attack on Titan".

Looking at the issue description, Ryot used to use Romaji but the fix for this issue made it so that only Native and English are now available.

_Originally posted by @mufeedali in https://github.com/IgnisDa/ryot/issues/866#issuecomment-2235222025_
            


Discussion / hints:

Fix patch:
diff --git a/apps/backend/src/entities/user.rs b/apps/backend/src/entities/user.rs
index e1e0af6f32..d414fb49a1 100644
--- a/apps/backend/src/entities/user.rs
+++ b/apps/backend/src/entities/user.rs
@@ -29,6 +29,7 @@ pub struct Model {
     pub created_on: DateTimeUtc,
     pub is_demo: Option<bool>,
     pub lot: UserLot,
+    pub is_disabled: Option<bool>,
     #[graphql(skip)]
     pub preferences: UserPreferences,
     #[graphql(skip)]
diff --git a/apps/backend/src/miscellaneous/resolver.rs b/apps/backend/src/miscellaneous/resolver.rs
index aeb7b1407e..bdb4f60a3a 100644
--- a/apps/backend/src/miscellaneous/resolver.rs
+++ b/apps/backend/src/miscellaneous/resolver.rs
@@ -216,8 +216,6 @@ struct PasswordUserInput {
     username: String,
     #[graphql(secret)]
     password: String,
-    /// If provided, that means an admin tried to create an account.
-    creator_user_id: Option<String>,
 }
 
 #[derive(Debug, InputObject, Serialize, Deserialize, Clone)]
@@ -233,13 +231,11 @@ enum AuthUserInput {
     Oidc(OidcUserInput),
 }
 
-impl AuthUserInput {
-    fn creator_user_id(&self) -> Option<String> {
-        match self {
-            Self::Password(p) => p.creator_user_id.clone(),
-            _ => None,
-        }
-    }
+#[derive(Debug, InputObject)]
+struct RegisterUserInput {
+    data: AuthUserInput,
+    /// If registration is disabled, this can be used to override it.
+    admin_access_token: Option<String>,
 }
 
 #[derive(Enum, Clone, Debug, Copy, PartialEq, Eq)]
@@ -261,6 +257,7 @@ enum RegisterResult {
 
 #[derive(Enum, Clone, Debug, Copy, PartialEq, Eq)]
 enum LoginErrorVariant {
+    AccountDisabled,
     UsernameDoesNotExist,
     CredentialsMismatch,
     IncorrectProviderChosen,
@@ -284,10 +281,14 @@ enum LoginResult {
 
 #[derive(Debug, InputObject)]
 struct UpdateUserInput {
-    username: Option<String>,
+    user_id: String,
+    is_disabled: Option<bool>,
+    lot: Option<UserLot>,
     #[graphql(secret)]
     password: Option<String>,
+    username: Option<String>,
     extra_information: Option<serde_json::Value>,
+    admin_access_token: Option<String>,
 }
 
 #[derive(Debug, InputObject)]
@@ -1252,7 +1253,7 @@ impl MiscellaneousMutation {
     async fn register_user(
         &self,
         gql_ctx: &Context<'_>,
-        input: AuthUserInput,
+        input: RegisterUserInput,
     ) -> Result<RegisterResult> {
         let service = gql_ctx.data_unchecked::<Arc<MiscellaneousService>>();
         service.register_user(input).await
@@ -1271,7 +1272,7 @@ impl MiscellaneousMutation {
         input: UpdateUserInput,
     ) -> Result<StringIdObject> {
         let service = gql_ctx.data_unchecked::<Arc<MiscellaneousService>>();
-        let user_id = self.user_id_from_ctx(gql_ctx).await?;
+        let user_id = self.user_id_from_ctx(gql_ctx).await.ok();
         service.update_user(user_id, input).await
     }
 
@@ -3715,9 +3716,13 @@ impl MiscellaneousService {
                 .await,
             ),
             MediaSource::Tmdb => Box::new(self.get_tmdb_non_media_service().await?),
-            MediaSource::Anilist => {
-                Box::new(NonMediaAnilistService::new(self.config.frontend.page_size).await)
-            }
+            MediaSource::Anilist => Box::new(
+                NonMediaAnilistService::new(
+                    &self.config.anime_and_manga.anilist,
+                    self.config.frontend.page_size,
+                )
+                .await,
+            ),
             MediaSource::Mal => Box::new(NonMediaMalService::new().await),
             MediaSource::Custom => return err(),
         };
@@ -4854,24 +4859,24 @@ impl MiscellaneousService {
         Ok(())
     }
 
-    async fn register_user(&self, input: AuthUserInput) -> Result<RegisterResult> {
-        if let Some(user_id) = input.creator_user_id() {
-            self.admin_account_guard(&user_id).await?;
-        } else if !self.config.users.allow_registration {
+    async fn register_user(&self, input: RegisterUserInput) -> Result<RegisterResult> {
+        if !self.config.users.allow_registration
+            && input.admin_access_token.unwrap_or_default() != self.config.server.admin_access_token
+        {
             return Ok(RegisterResult::Error(RegisterError {
                 error: RegisterErrorVariant::Disabled,
             }));
         }
-        let (filter, username, password) = match input.clone() {
-            AuthUserInput::Oidc(input) => (
-                user::Column::OidcIssuerId.eq(&input.issuer_id),
-                input.email,
+        let (filter, username, password) = match input.data.clone() {
+            AuthUserInput::Oidc(data) => (
+                user::Column::OidcIssuerId.eq(&data.issuer_id),
+                data.email,
                 None,
             ),
-            AuthUserInput::Password(input) => (
-                user::Column::Name.eq(&input.username),
-                input.username,
-                Some(input.password),
+            AuthUserInput::Password(data) => (
+                user::Column::Name.eq(&data.username),
+                data.username,
+                Some(data.password),
             ),
         };
         if User::find().filter(filter).count(&self.db).await.unwrap() != 0 {
@@ -4879,8 +4884,8 @@ impl MiscellaneousService {
                 error: RegisterErrorVariant::IdentifierAlreadyExists,
             }));
         };
-        let oidc_issuer_id = match input {
-            AuthUserInput::Oidc(input) => Some(input.issuer_id),
+        let oidc_issuer_id = match input.data {
+            AuthUserInput::Oidc(data) => Some(data.issuer_id),
             AuthUserInput::Password(_) => None,
         };
         let lot = if User::find().count(&self.db).await.unwrap() == 0 {
@@ -4914,6 +4919,11 @@ impl MiscellaneousService {
                 error: LoginErrorVariant::UsernameDoesNotExist,
             })),
             Some(user) => {
+                if user.is_disabled.unwrap_or_default() {
+                    return Ok(LoginResult::Error(LoginError {
+                        error: LoginErrorVariant::AccountDisabled,
+                    }));
+                }
                 if self.config.users.validate_password {
                     if let AuthUserInput::Password(PasswordUserInput { password, .. }) = input {
                         if let Some(hashed_password) = user.password {
@@ -4958,8 +4968,17 @@ impl MiscellaneousService {
         Ok(())
     }
 
-    async fn update_user(&self, user_id: String, input: UpdateUserInput) -> Result<StringIdObject> {
-        let mut user_obj: user::ActiveModel = User::find_by_id(user_id.to_owned())
+    async fn update_user(
+        &self,
+        user_id: Option<String>,
+        input: UpdateUserInput,
+    ) -> Result<StringIdObject> {
+        if user_id.unwrap_or_default() != input.user_id
+            && input.admin_access_token.unwrap_or_default() != self.config.server.admin_access_token
+        {
+            return Err(Error::new("Admin access token mismatch".to_owned()));
+        }
+        let mut user_obj: user::ActiveModel = User::find_by_id(input.user_id)
             .one(&self.db)
             .await
             .unwrap()
@@ -4974,6 +4993,12 @@ impl MiscellaneousService {
         if let Some(i) = input.extra_information {
             user_obj.extra_information = ActiveValue::Set(Some(i));
         }
+        if let Some(l) = input.lot {
+            user_obj.lot = ActiveValue::Set(l);
+        }
+        if let Some(d) = input.is_disabled {
+            user_obj.is_disabled = ActiveValue::Set(Some(d));
+        }
         let user_obj = user_obj.update(&self.db).await.unwrap();
         Ok(StringIdObject { id: user_obj.id })
     }
@@ -5791,19 +5816,20 @@ impl MiscellaneousService {
     async fn admin_account_guard(&self, user_id: &String) -> Result<()> {
         let main_user = user_by_id(&self.db, user_id).await?;
         if main_user.lot != UserLot::Admin {
-            return Err(Error::new("Only admins can perform this operation."));
+            return Err(Error::new(BackendError::AdminOnlyAction.to_string()));
         }
         Ok(())
     }
 
     async fn users_list(&self, query: Option<String>) -> Result<Vec<user::Model>> {
-        Ok(User::find()
+        let users = User::find()
             .apply_if(query, |query, value| {
                 query.filter(Expr::col(user::Column::Name).ilike(ilike_sql(&value)))
             })
             .order_by_asc(user::Column::Name)
             .all(&self.db)
-            .await?)
+            .await?;
+        Ok(users)
     }
 
     async fn delete_user(&self, to_delete_user_id: String) -> Result<bool> {
diff --git a/apps/backend/src/models.rs b/apps/backend/src/models.rs
index 8dfcaeab3a..2897f7c28c 100644
--- a/apps/backend/src/models.rs
+++ b/apps/backend/src/models.rs
@@ -56,9 +56,10 @@ pub enum EntityLot {
 #[derive(Enum, Clone, Debug, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, Display)]
 #[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
 pub enum BackendError {
-    NoAuthToken,
     NoUserId,
+    NoAuthToken,
     SessionExpired,
+    AdminOnlyAction,
     MutationNotAllowed,
 }
 
diff --git a/apps/backend/src/providers/anilist/media_details.graphql b/apps/backend/src/providers/anilist/media_details.graphql
index 9e8dc0cb6b..531faba920 100644
--- a/apps/backend/src/providers/anilist/media_details.graphql
+++ b/apps/backend/src/providers/anilist/media_details.graphql
@@ -4,6 +4,7 @@ query MediaDetailsQuery($id: Int!) {
     title {
       english
       native
+      romaji
     }
     isAdult
     episodes
@@ -50,6 +51,7 @@ query MediaDetailsQuery($id: Int!) {
           title {
             english
             native
+            romaji
           }
           coverImage {
             extraLarge
diff --git a/apps/backend/src/providers/anilist/media_search.graphql b/apps/backend/src/providers/anilist/media_search.graphql
index f5601c8500..57c71c552f 100644
--- a/apps/backend/src/providers/anilist/media_search.graphql
+++ b/apps/backend/src/providers/anilist/media_search.graphql
@@ -13,6 +13,7 @@ query MediaSearchQuery(
       title {
         english
         native
+        romaji
       }
       coverImage {
         extraLarge
diff --git a/apps/backend/src/providers/anilist/mod.rs b/apps/backend/src/providers/anilist/mod.rs
index 93b6a5b31e..3777d2108e 100644
--- a/apps/backend/src/providers/anilist/mod.rs
+++ b/apps/backend/src/providers/anilist/mod.rs
@@ -1,6 +1,7 @@
 use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use chrono::NaiveDate;
+use config::AnilistPreferredLanguage;
 use database::{MediaLot, MediaSource};
 use graphql_client::{GraphQLQuery, Response};
 use itertools::Itertools;
@@ -11,8 +12,8 @@ use crate::{
     models::{
         media::{
             AnimeSpecifics, MangaSpecifics, MediaDetails, MetadataImageForMediaDetails,
-             MetadataPerson, MetadataSearchItem, MetadataVideo,
-            MetadataVideoSource, PartialMetadataPerson, PartialMetadataWithoutId, PeopleSearchItem,
+            MetadataPerson, MetadataSearchItem, MetadataVideo, MetadataVideoSource,
+            PartialMetadataPerson, PartialMetadataWithoutId, PeopleSearchItem,
             PersonSourceSpecifics,
         },
         SearchDetails, SearchResults, StoredUrl,
@@ -81,8 +82,8 @@ struct StudioQuery;
 #[derive(Debug, Clone)]
 pub struct AnilistService {
     client: Client,
-    prefer_english: bool,
-    page_limit: i32,
+    preferred_language: AnilistPreferredLanguage,
+    page_size: i32,
 }
 
 impl MediaProviderLanguages for AnilistService {
@@ -95,20 +96,31 @@ impl MediaProviderLanguages for AnilistService {
     }
 }
 
+impl AnilistService {
+    async fn new(page_size: i32, config: &config::AnilistConfig) -> Self {
+        let client = get_client_config(URL).await;
+        let preferred_language = if config.prefer_english {
+            AnilistPreferredLanguage::English
+        } else {
+            config.preferred_language.clone()
+        };
+        Self {
+            client,
+            preferred_language,
+            page_size,
+        }
+    }
+}
+
 #[derive(Debug, Clone)]
 pub struct NonMediaAnilistService {
     base: AnilistService,
 }
 
 impl NonMediaAnilistService {
-    pub async fn new(page_limit: i32) -> Self {
-        let client = get_client_config(URL).await;
+    pub async fn new(config: &config::AnilistConfig, page_size: i32) -> Self {
         Self {
-            base: AnilistService {
-                client,
-                prefer_english: false,
-                page_limit,
-            },
+            base: AnilistService::new(page_size, config).await,
         }
     }
 }
@@ -133,7 +145,7 @@ impl MediaProvider for NonMediaAnilistService {
             let variables = studio_search_query::Variables {
                 page: page.unwrap_or(1).into(),
                 search: query.to_owned(),
-                per_page: self.base.page_limit.into(),
+                per_page: self.base.page_size.into(),
             };
             let body = StudioSearchQuery::build_query(variables);
             let search = self
@@ -152,7 +164,7 @@ impl MediaProvider for NonMediaAnilistService {
                 .page
                 .unwrap();
             let total = search.page_info.unwrap().total.unwrap().try_into().unwrap();
-            let next_page = if total - (page.unwrap_or(1) * self.base.page_limit) > 0 {
+            let next_page = if total - (page.unwrap_or(1) * self.base.page_size) > 0 {
                 Some(page.unwrap_or(1) + 1)
             } else {
                 None
@@ -176,7 +188,7 @@ impl MediaProvider for NonMediaAnilistService {
             let variables = staff_search_query::Variables {
                 page: page.unwrap_or(1).into(),
                 search: query.to_owned(),
-                per_page: self.base.page_limit.into(),
+                per_page: self.base.page_size.into(),
             };
             let body = StaffSearchQuery::build_query(variables);
             let search = self
@@ -195,7 +207,7 @@ impl MediaProvider for NonMediaAnilistService {
                 .page
                 .unwrap();
             let total = search.page_info.unwrap().total.unwrap().try_into().unwrap();
-            let next_page = if total - (page.unwrap_or(1) * self.base.page_limit) > 0 {
+            let next_page = if total - (page.unwrap_or(1) * self.base.page_size) > 0 {
                 Some(page.unwrap_or(1) + 1)
             } else {
                 None
@@ -346,8 +358,12 @@ impl MediaProvider for NonMediaAnilistService {
                 .map(|r| {
                     let data = r.unwrap().node.unwrap();
                     let title = data.title.unwrap();
-                    let title =
-                        preferred_language(title.native, title.english, self.base.prefer_english);
+                    let title = get_in_preferred_language(
+                        title.native,
+                        title.english,
+                        title.romaji,
+                        &self.base.preferred_language,
+                    );
                     (
                         "Voicing".to_owned(),
                         PartialMetadataWithoutId {
@@ -374,10 +390,11 @@ impl MediaProvider for NonMediaAnilistService {
                     .map(|r| {
                         let data = r.unwrap().node.unwrap();
                         let title = data.title.unwrap();
-                        let title = preferred_language(
+                        let title = get_in_preferred_language(
                             title.native,
                             title.english,
-                            self.base.prefer_english,
+                            title.romaji,
+                            &self.base.preferred_language,
                         );
                         (
                             "Production".to_owned(),
@@ -420,14 +437,9 @@ pub struct AnilistAnimeService {
 }
 
 impl AnilistAnimeService {
-    pub async fn new(config: &config::AnilistConfig, page_limit: i32) -> Self {
-        let client = get_client_config(URL).await;
+    pub async fn new(config: &config::AnilistConfig, page_size: i32) -> Self {
         Self {
-            base: AnilistService {
-                client,
-                prefer_english: config.prefer_english,
-                page_limit,
-            },
+            base: AnilistService::new(page_size, config).await,
         }
     }
 }
@@ -436,7 +448,7 @@ impl AnilistAnimeService {
 impl MediaProvider for AnilistAnimeService {
     async fn metadata_details(&self, identifier: &str) -> Result<MediaDetails> {
         let details =
-            media_details(&self.base.client, identifier, self.base.prefer_english).await?;
+            media_details(&self.base.client, identifier, &self.base.preferred_language).await?;
         Ok(details)
     }
 
@@ -451,9 +463,9 @@ impl MediaProvider for AnilistAnimeService {
             media_search_query::MediaType::ANIME,
             query,
             page,
-            self.base.page_limit,
+            self.base.page_size,
             display_nsfw,
-            self.base.prefer_english,
+            &self.base.preferred_language,
         )
         .await?;
         Ok(SearchResults {
@@ -469,14 +481,9 @@ pub struct AnilistMangaService {
 }
 
 impl AnilistMangaService {
-    pub async fn new(config: &config::AnilistConfig, page_limit: i32) -> Self {
-        let client = get_client_config(URL).await;
+    pub async fn new(config: &config::AnilistConfig, page_size: i32) -> Self {
         Self {
-            base: AnilistService {
-                client,
-                prefer_english: config.prefer_english,
-                page_limit,
-            },
+            base: AnilistService::new(page_size, config).await,
         }
     }
 }
@@ -485,7 +492,7 @@ impl AnilistMangaService {
 impl MediaProvider for AnilistMangaService {
     async fn metadata_details(&self, identifier: &str) -> Result<MediaDetails> {
         let details =
-            media_details(&self.base.client, identifier, self.base.prefer_english).await?;
+            media_details(&self.base.client, identifier, &self.base.preferred_language).await?;
         Ok(details)
     }
 
@@ -500,9 +507,9 @@ impl MediaProvider for AnilistMangaService {
             media_search_query::MediaType::MANGA,
             query,
             page,
-            self.base.page_limit,
+            self.base.page_size,
             display_nsfw,
-            self.base.prefer_english,
+            &self.base.preferred_language,
         )
         .await?;
         Ok(SearchResults {
@@ -516,7 +523,11 @@ async fn get_client_config(url: &str) -> Client {
     get_base_http_client(url, None)
 }
 
-async fn media_details(client: &Client, id: &str, prefer_english: bool) -> Result<MediaDetails> {
+async fn media_details(
+    client: &Client,
+    id: &str,
+    preferred_language: &AnilistPreferredLanguage,
+) -> Result<MediaDetails> {
     let variables = media_details_query::Variables {
         id: id.parse::<i64>().unwrap(),
     };
@@ -540,9 +551,7 @@ async fn media_details(client: &Client, id: &str, prefer_english: bool) -> Resul
     }
     let images = images
         .into_iter()
-        .map(|i| MetadataImageForMediaDetails {
-            image: i,
-        })
+        .map(|i| MetadataImageForMediaDetails { image: i })
         .unique()
         .collect();
     let mut genres = details
@@ -629,7 +638,12 @@ async fn media_details(client: &Client, id: &str, prefer_english: bool) -> Resul
         .flat_map(|r| {
             r.unwrap().media_recommendation.map(|data| {
                 let title = data.title.unwrap();
-                let title = preferred_language(title.native, title.english, prefer_english);
+                let title = get_in_preferred_language(
+                    title.native,
+                    title.english,
+                    title.romaji,
+                    preferred_language,
+                );
                 PartialMetadataWithoutId {
                     title,
                     identifier: data.id.to_string(),
@@ -654,7 +668,12 @@ async fn media_details(client: &Client, id: &str, prefer_english: bool) -> Resul
         },
     }));
     let title = details.title.unwrap();
-    let title = preferred_language(title.native, title.english, prefer_english);
+    let title = get_in_preferred_language(
+        title.native,
+        title.english,
+        title.romaji,
+        preferred_language,
+    );
     Ok(MediaDetails {
         title,
         identifier: details.id.to_string(),
@@ -686,16 +705,16 @@ async fn search(
     media_type: media_search_query::MediaType,
     query: &str,
     page: Option<i32>,
-    page_limit: i32,
+    page_size: i32,
     _is_adult: bool,
-    prefer_english: bool,
+    preferred_language: &AnilistPreferredLanguage,
 ) -> Result<(Vec<MetadataSearchItem>, i32, Option<i32>)> {
     let page = page.unwrap_or(1);
     let variables = media_search_query::Variables {
         page: page.into(),
         search: query.to_owned(),
         type_: media_type,
-        per_page: page_limit.into(),
+        per_page: page_size.into(),
     };
     let body = MediaSearchQuery::build_query(variables);
     let search = client
@@ -712,7 +731,7 @@ async fn search(
         .page
         .unwrap();
     let total = search.page_info.unwrap().total.unwrap().try_into().unwrap();
-    let next_page = if total - (page * page_limit) > 0 {
+    let next_page = if total - (page * page_size) > 0 {
         Some(page + 1)
     } else {
         None
@@ -724,7 +743,12 @@ async fn search(
         .flatten()
         .map(|b| {
             let title = b.title.unwrap();
-            let title = preferred_language(title.native, title.english, prefer_english);
+            let title = get_in_preferred_language(
+                title.native,
+                title.english,
+                title.romaji,
+                preferred_language,
+            );
             MetadataSearchItem {
                 identifier: b.id.to_string(),
                 title,
@@ -738,15 +762,16 @@ async fn search(
     Ok((media, total, next_page))
 }
 
-fn preferred_language(
+fn get_in_preferred_language(
     native: Option<String>,
     english: Option<String>,
-    prefer_english: bool,
+    romaji: Option<String>,
+    preferred_language: &AnilistPreferredLanguage,
 ) -> String {
-    let title = if prefer_english {
-        english.or(native)
-    } else {
-        native
+    let title = match preferred_language {
+        AnilistPreferredLanguage::Native => native.clone(),
+        AnilistPreferredLanguage::English => english.clone(),
+        AnilistPreferredLanguage::Romaji => romaji.clone(),
     };
-    title.unwrap()
+    title.or(native).unwrap()
 }
diff --git a/apps/backend/src/providers/anilist/staff_details.graphql b/apps/backend/src/providers/anilist/staff_details.graphql
index 2ac6c9ad2d..1b23bc1f6e 100644
--- a/apps/backend/src/providers/anilist/staff_details.graphql
+++ b/apps/backend/src/providers/anilist/staff_details.graphql
@@ -28,6 +28,7 @@ query StaffQuery($id: Int!) {
           title {
             native
             english
+            romaji
           }
           coverImage {
             extraLarge
@@ -44,6 +45,7 @@ query StaffQuery($id: Int!) {
           title {
             native
             english
+            romaji
           }
           coverImage {
             extraLarge
diff --git a/apps/backend/src/providers/anilist/studio_details.graphql b/apps/backend/src/providers/anilist/studio_details.graphql
index bb47d54873..7574f820ec 100644
--- a/apps/backend/src/providers/anilist/studio_details.graphql
+++ b/apps/backend/src/providers/anilist/studio_details.graphql
@@ -9,7 +9,9 @@ query StudioQuery($id: Int!) {
           id
           type
           title {
+            english
             native
+            romaji
           }
           coverImage {
             extraLarge
diff --git a/apps/frontend/app/lib/utilities.server.ts b/apps/frontend/app/lib/utilities.server.ts
index 821dfeca9f..5c8180fdee 100644
--- a/apps/frontend/app/lib/utilities.server.ts
+++ b/apps/frontend/app/lib/utilities.server.ts
@@ -80,6 +80,10 @@ class AuthenticatedGraphQLClient extends GraphQLClient {
 							BackendError.MutationNotAllowed,
 							() => "You do not have permission to perform this action",
 						)
+						.with(
+							BackendError.AdminOnlyAction,
+							() => "You must be an admin to perform this action",
+						)
 						.otherwise(() => error);
 					return Response.json({ message });
 				});
diff --git a/apps/frontend/app/routes/_dashboard.collections.list.tsx b/apps/frontend/app/routes/_dashboard.collections.list.tsx
index 6f1e4519bf..600593c55f 100644
--- a/apps/frontend/app/routes/_dashboard.collections.list.tsx
+++ b/apps/frontend/app/routes/_dashboard.collections.list.tsx
@@ -23,7 +23,6 @@ import {
 	Form,
 	Link,
 	type MetaArgs_SingleFetch,
-	useFetcher,
 	useLoaderData,
 	useNavigation,
 	useSearchParams,
@@ -36,7 +35,7 @@ import {
 import { truncate } from "@ryot/ts-utils";
 import { IconEdit, IconPlus, IconTrashFilled } from "@tabler/icons-react";
 import { ClientError } from "graphql-request";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useState } from "react";
 import { Virtuoso } from "react-virtuoso";
 import { namedAction } from "remix-utils/named-action";
 import { withQuery } from "ufo";
@@ -44,6 +43,7 @@ import { z } from "zod";
 import { DebouncedSearchInput, ProRequiredAlert } from "~/components/common";
 import { confirmWrapper } from "~/components/confirmation";
 import {
+	useConfirmSubmit,
 	useFallbackImageUrl,
 	useUserCollections,
 	useUserDetails,
@@ -233,8 +233,7 @@ const DisplayCollection = (props: {
 	openModal: () => void;
 }) => {
 	const userDetails = useUserDetails();
-	const fetcher = useFetcher<typeof action>();
-	const deleteFormRef = useRef<HTMLFormElement>(null);
+	const submit = useConfirmSubmit();
 	const fallbackImageUrl = useFallbackImageUrl(props.collection.name);
 	const additionalDisplay = [];
 
@@ -309,9 +308,8 @@ const DisplayCollection = (props: {
 								</ActionIcon>
 							) : null}
 							{!props.collection.isDefault ? (
-								<fetcher.Form
+								<Form
 									method="POST"
-									ref={deleteFormRef}
 									action={withQuery("", { intent: "delete" })}
 								>
 									<input
@@ -320,19 +318,22 @@ const DisplayCollection = (props: {
 										defaultValue={props.collection.name}
 									/>
 									<ActionIcon
+										type="submit"
 										color="red"
 										variant="outline"
-										onClick={async () => {
+										onClick={async (e) => {
+											const form = e.currentTarget.form;
+											e.preventDefault();
 											const conf = await confirmWrapper({
 												confirmation:
 													"Are you sure you want to delete this collection?",
 											});
-											if (conf) fetcher.submit(deleteFormRef.current);
+											if (conf && form) submit(form);
 										}}
 									>
 										<IconTrashFilled size={18} />
 									</ActionIcon>
-								</fetcher.Form>
+								</Form>
 							) : null}
 						</Group>
 					</Group>
diff --git a/apps/frontend/app/routes/_dashboard.settings.imports-and-exports._index.tsx b/apps/frontend/app/routes/_dashboard.settings.imports-and-exports._index.tsx
index 8adfe4864c..c9ad6d327a 100644
--- a/apps/frontend/app/routes/_dashboard.settings.imports-and-exports._index.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.imports-and-exports._index.tsx
@@ -28,10 +28,8 @@ import {
 	unstable_parseMultipartFormData,
 } from "@remix-run/node";
 import {
-	type FetcherWithComponents,
 	Form,
 	type MetaArgs_SingleFetch,
-	useFetcher,
 	useLoaderData,
 } from "@remix-run/react";
 import {
@@ -44,7 +42,7 @@ import {
 } from "@ryot/generated/graphql/backend/graphql";
 import { changeCase } from "@ryot/ts-utils";
 import { IconDownload } from "@tabler/icons-react";
-import { type ReactNode, type RefObject, useRef, useState } from "react";
+import { type ReactNode, useState } from "react";
 import { namedAction } from "remix-utils/named-action";
 import { match } from "ts-pattern";
 import { withFragment, withQuery } from "ufo";
@@ -53,6 +51,7 @@ import { confirmWrapper } from "~/components/confirmation";
 import { dayjsLib } from "~/lib/generals";
 import {
 	useApplicationEvents,
+	useConfirmSubmit,
 	useCoreDetails,
 	useUserCollections,
 } from "~/lib/hooks";
@@ -208,9 +207,6 @@ export default function Page() {
 	const events = useApplicationEvents();
 	const [deployImportSource, setDeployImportSource] = useState<ImportSource>();
 
-	const fetcher = useFetcher<typeof action>();
-	const formRef = useRef<HTMLFormElement>(null);
-
 	return (
 		<Container size="xs">
 			<Tabs defaultValue="import">
@@ -220,8 +216,7 @@ export default function Page() {
 				</Tabs.List>
 				<Box mt="xl">
 					<Tabs.Panel value="import">
-						<fetcher.Form
-							ref={formRef}
+						<Form
 							method="POST"
 							action={withQuery("", { intent: "deployImport" })}
 							encType="multipart/form-data"
@@ -275,7 +270,7 @@ export default function Page() {
 									}}
 								/>
 								{deployImportSource ? (
-									<ImportSourceElement fetcher={fetcher} formRef={formRef}>
+									<ImportSourceElement>
 										{match(deployImportSource)
 											.with(
 												ImportSource.Audiobookshelf,
@@ -500,7 +495,7 @@ export default function Page() {
 									<Text>You have not performed any imports</Text>
 								)}
 							</Stack>
-						</fetcher.Form>
+						</Form>
 					</Tabs.Panel>
 					<Tabs.Panel value="export">
 						<Stack>
@@ -583,24 +578,27 @@ export default function Page() {
 
 const ImportSourceElement = (props: {
 	children: ReactNode | Array<ReactNode>;
-	fetcher: FetcherWithComponents<unknown>;
-	formRef: RefObject<HTMLFormElement>;
 }) => {
+	const submit = useConfirmSubmit();
+
 	return (
 		<>
 			{props.children}
 			<Button
+				type="submit"
 				variant="light"
 				color="blue"
 				fullWidth
 				mt="md"
 				radius="md"
-				onClick={async () => {
+				onClick={async (e) => {
+					const form = e.currentTarget.form;
+					e.preventDefault();
 					const conf = await confirmWrapper({
 						confirmation:
 							"Are you sure you want to deploy an import job? This action is irreversible.",
 					});
-					if (conf) props.fetcher.submit(props.formRef.current);
+					if (conf && form) submit(form);
 				}}
 			>
 				Import
diff --git a/apps/frontend/app/routes/_dashboard.settings.integrations.tsx b/apps/frontend/app/routes/_dashboard.settings.integrations.tsx
index b47a9dd419..865a393352 100644
--- a/apps/frontend/app/routes/_dashboard.settings.integrations.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.integrations.tsx
@@ -22,12 +22,7 @@ import {
 import { useDisclosure } from "@mantine/hooks";
 import { unstable_defineAction, unstable_defineLoader } from "@remix-run/node";
 import type { MetaArgs_SingleFetch } from "@remix-run/react";
-import {
-	Form,
-	useActionData,
-	useFetcher,
-	useLoaderData,
-} from "@remix-run/react";
+import { Form, useActionData, useLoaderData } from "@remix-run/react";
 import {
 	CreateUserIntegrationDocument,
 	DeleteUserIntegrationDocument,
@@ -46,7 +41,7 @@ import {
 	IconPencil,
 	IconTrash,
 } from "@tabler/icons-react";
-import { useRef, useState } from "react";
+import { useState } from "react";
 import { namedAction } from "remix-utils/named-action";
 import { match } from "ts-pattern";
 import { withQuery } from "ufo";
@@ -54,6 +49,7 @@ import { z } from "zod";
 import { zx } from "zodix";
 import { confirmWrapper } from "~/components/confirmation";
 import { dayjsLib } from "~/lib/generals";
+import { useConfirmSubmit } from "~/lib/hooks";
 import {
 	createToastHeaders,
 	processSubmission,
@@ -278,8 +274,7 @@ const DisplayIntegration = (props: {
 	const [parent] = useAutoAnimate();
 	const [integrationInputOpened, { toggle: integrationInputToggle }] =
 		useDisclosure(false);
-	const fetcher = useFetcher<typeof action>();
-	const deleteFormRef = useRef<HTMLFormElement>(null);
+	const submit = useConfirmSubmit();
 
 	const integrationUrl =
 		typeof window !== "undefined"
@@ -324,31 +319,30 @@ const DisplayIntegration = (props: {
 						>
 							<IconPencil />
 						</ActionIcon>
-						<fetcher.Form
-							method="POST"
-							ref={deleteFormRef}
-							action={withQuery("", { intent: "delete" })}
-						>
+						<Form method="POST" action={withQuery("", { intent: "delete" })}>
 							<input
 								type="hidden"
 								name="integrationId"
 								defaultValue={props.integration.id}
 							/>
 							<ActionIcon
+								type="submit"
 								color="red"
 								variant="subtle"
 								mt={4}
-								onClick={async () => {
+								onClick={async (e) => {
+									const form = e.currentTarget.form;
+									e.preventDefault();
 									const conf = await confirmWrapper({
 										confirmation:
 											"Are you sure you want to delete this integration?",
 									});
-									if (conf) fetcher.submit(deleteFormRef.current);
+									if (conf && form) submit(form);
 								}}
 							>
 								<IconTrash />
 							</ActionIcon>
-						</fetcher.Form>
+						</Form>
 					</Group>
 				</Flex>
 				{integrationInputOpened ? (
diff --git a/apps/frontend/app/routes/_dashboard.settings.notifications.tsx b/apps/frontend/app/routes/_dashboard.settings.notifications.tsx
index c917b8e3c2..39bdfe4891 100644
--- a/apps/frontend/app/routes/_dashboard.settings.notifications.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.notifications.tsx
@@ -21,7 +21,6 @@ import { unstable_defineAction, unstable_defineLoader } from "@remix-run/node";
 import {
 	Form,
 	type MetaArgs_SingleFetch,
-	useFetcher,
 	useLoaderData,
 } from "@remix-run/react";
 import {
@@ -39,7 +38,7 @@ import {
 	IconPlayerPlay,
 	IconTrash,
 } from "@tabler/icons-react";
-import { useRef, useState } from "react";
+import { useState } from "react";
 import { namedAction } from "remix-utils/named-action";
 import { match } from "ts-pattern";
 import { withQuery } from "ufo";
@@ -47,7 +46,7 @@ import { z } from "zod";
 import { zx } from "zodix";
 import { confirmWrapper } from "~/components/confirmation";
 import { dayjsLib } from "~/lib/generals";
-import { useCoreDetails } from "~/lib/hooks";
+import { useConfirmSubmit, useCoreDetails } from "~/lib/hooks";
 import {
 	createToastHeaders,
 	processSubmission,
@@ -352,8 +351,7 @@ export default function Page() {
 const DisplayNotification = (props: {
 	notification: UserNotificationPlatformsQuery["userNotificationPlatforms"][number];
 }) => {
-	const fetcher = useFetcher<typeof action>();
-	const deleteFormRef = useRef<HTMLFormElement>(null);
+	const submit = useConfirmSubmit();
 
 	return (
 		<Paper p="xs" withBorder>
@@ -391,30 +389,29 @@ const DisplayNotification = (props: {
 						</ActionIcon>
 					</Form>
 					<Tooltip label="Delete">
-						<fetcher.Form
-							method="POST"
-							ref={deleteFormRef}
-							action={withQuery("", { intent: "delete" })}
-						>
+						<Form method="POST" action={withQuery("", { intent: "delete" })}>
 							<input
 								hidden
 								name="notificationId"
 								defaultValue={props.notification.id}
 							/>
 							<ActionIcon
+								type="submit"
 								color="red"
 								variant="outline"
-								onClick={async () => {
+								onClick={async (e) => {
+									const form = e.currentTarget.form;
+									e.preventDefault();
 									const conf = await confirmWrapper({
 										confirmation:
 											"Are you sure you want to delete this notification platform?",
 									});
-									if (conf) fetcher.submit(deleteFormRef.current);
+									if (conf && form) submit(form);
 								}}
 							>
 								<IconTrash size={16} />
 							</ActionIcon>
-						</fetcher.Form>
+						</Form>
 					</Tooltip>
 				</Group>
 			</Flex>
diff --git a/apps/frontend/app/routes/_dashboard.settings.profile-and-sharing.tsx b/apps/frontend/app/routes/_dashboard.settings.profile-and-sharing.tsx
index b15392c58e..1e78c4e89d 100644
--- a/apps/frontend/app/routes/_dashboard.settings.profile-and-sharing.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.profile-and-sharing.tsx
@@ -9,16 +9,16 @@ import {
 	Title,
 } from "@mantine/core";
 import { unstable_defineAction } from "@remix-run/node";
-import { type MetaArgs_SingleFetch, useFetcher } from "@remix-run/react";
+import { Form } from "@remix-run/react";
+import type { MetaArgs_SingleFetch } from "@remix-run/react";
 import { UpdateUserDocument } from "@ryot/generated/graphql/backend/graphql";
-import { useRef } from "react";
 import { namedAction } from "remix-utils/named-action";
 import { withQuery } from "ufo";
 import { z } from "zod";
 import { ProRequiredAlert } from "~/components/common";
 import { confirmWrapper } from "~/components/confirmation";
 import { queryClient, queryFactory } from "~/lib/generals";
-import { useUserDetails } from "~/lib/hooks";
+import { useConfirmSubmit, useUserDetails } from "~/lib/hooks";
 import {
 	createToastHeaders,
 	getAuthorizationCookie,
@@ -53,6 +53,7 @@ export const action = unstable_defineAction(async ({ request }) => {
 });
 
 const updateProfileFormSchema = z.object({
+	userId: z.string(),
 	username: z.string().optional(),
 	email: z.string().email().optional(),
 	password: z.string().optional(),
@@ -60,8 +61,7 @@ const updateProfileFormSchema = z.object({
 
 export default function Page() {
 	const userDetails = useUserDetails();
-	const fetcher = useFetcher<typeof action>();
-	const formRef = useRef<HTMLFormElement>(null);
+	const submit = useConfirmSubmit();
 
 	return (
 		<Container size="xs">
@@ -74,11 +74,15 @@ export default function Page() {
 					<Tabs.Panel value="profile">
 						<Stack>
 							<Title>Profile</Title>
-							<fetcher.Form
-								ref={formRef}
+							<Form
 								method="POST"
 								action={withQuery(".", { intent: "updateProfile" })}
 							>
+								<input
+									type="hidden"
+									name="userId"
+									defaultValue={userDetails.id}
+								/>
 								<Stack>
 									<TextInput
 										readOnly
@@ -111,19 +115,22 @@ export default function Page() {
 										}
 									/>
 									<Button
-										onClick={async () => {
+										type="submit"
+										onClick={async (e) => {
+											const form = e.currentTarget.form;
+											e.preventDefault();
 											const conf = await confirmWrapper({
 												confirmation:
 													"Are you sure you want to update your profile?",
 											});
-											if (conf) fetcher.submit(formRef.current);
+											if (conf && form) submit(form);
 										}}
 										fullWidth
 									>
 										Update
 									</Button>
 								</Stack>
-							</fetcher.Form>
+							</Form>
 						</Stack>
 					</Tabs.Panel>
 					<Tabs.Panel value="sharing">
diff --git a/apps/frontend/app/routes/_dashboard.settings.users.tsx b/apps/frontend/app/routes/_dashboard.settings.users.tsx
index d2c4d6555c..b8dd29f829 100644
--- a/apps/frontend/app/routes/_dashboard.settings.users.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.users.tsx
@@ -9,8 +9,10 @@ import {
 	Group,
 	Modal,
 	Paper,
+	PasswordInput,
 	SimpleGrid,
 	Stack,
+	Switch,
 	Text,
 	TextInput,
 	Title,
@@ -22,17 +24,24 @@ import {
 	unstable_defineLoader,
 } from "@remix-run/node";
 import type { MetaArgs_SingleFetch } from "@remix-run/react";
-import { Form, useFetcher, useLoaderData } from "@remix-run/react";
+import { Form, useLoaderData } from "@remix-run/react";
 import {
 	DeleteUserDocument,
 	RegisterErrorVariant,
 	RegisterUserDocument,
+	UpdateUserDocument,
 	UserLot,
 	UsersListDocument,
+	type UsersListQuery,
 } from "@ryot/generated/graphql/backend/graphql";
 import { changeCase, randomString, truncate } from "@ryot/ts-utils";
-import { IconPlus, IconRefresh, IconTrash } from "@tabler/icons-react";
-import { forwardRef, useRef, useState } from "react";
+import {
+	IconPencil,
+	IconPlus,
+	IconRefresh,
+	IconTrash,
+} from "@tabler/icons-react";
+import { forwardRef, useState } from "react";
 import { VirtuosoGrid } from "react-virtuoso";
 import { namedAction } from "remix-utils/named-action";
 import { match } from "ts-pattern";
@@ -41,7 +50,7 @@ import { z } from "zod";
 import { zx } from "zodix";
 import { DebouncedSearchInput } from "~/components/common";
 import { confirmWrapper } from "~/components/confirmation";
-import { useUserDetails } from "~/lib/hooks";
+import { useConfirmSubmit, useCoreDetails } from "~/lib/hooks";
 import {
 	createToastHeaders,
 	getEnhancedCookieName,
@@ -99,7 +108,17 @@ export const action = unstable_defineAction(async ({ request }) => {
 			const { registerUser } = await serverGqlService.authenticatedRequest(
 				request,
 				RegisterUserDocument,
-				{ input: { password: submission } },
+				{
+					input: {
+						adminAccessToken: submission.adminAccessToken,
+						data: {
+							password: {
+								password: submission.password,
+								username: submission.username,
+							},
+						},
+					},
+				},
 			);
 			const success = registerUser.__typename === "StringIdObject";
 			return Response.json({ status: "success", submission } as const, {
@@ -120,20 +139,41 @@ export const action = unstable_defineAction(async ({ request }) => {
 				}),
 			});
 		},
+		update: async () => {
+			const submission = processSubmission(formData, updateUserSchema);
+			submission.isDisabled = submission.isDisabled === true;
+			await serverGqlService.authenticatedRequest(request, UpdateUserDocument, {
+				input: submission,
+			});
+			return Response.json({ status: "success", submission } as const, {
+				headers: await createToastHeaders({
+					type: "success",
+					message: "User updated successfully",
+				}),
+			});
+		},
 	});
 });
 
 const registerFormSchema = z.object({
-	creatorUserId: z.string(),
 	username: z.string(),
 	password: z.string(),
+	adminAccessToken: z.string().optional(),
 });
 
 const deleteSchema = z.object({ toDeleteUserId: z.string() });
 
+const updateUserSchema = z.object({
+	userId: z.string(),
+	adminAccessToken: z.string(),
+	isDisabled: zx.CheckboxAsString.optional(),
+	lot: z.nativeEnum(UserLot).optional(),
+	password: z.string().optional(),
+});
+
 export default function Page() {
 	const loaderData = useLoaderData<typeof loader>();
-	const userDetails = useUserDetails();
+	const coreDetails = useCoreDetails();
 	const [
 		registerUserModalOpened,
 		{ open: openRegisterUserModal, close: closeRegisterUserModal },
@@ -163,7 +203,6 @@ export default function Page() {
 				>
 					<Form replace method="POST" onSubmit={closeRegisterUserModal}>
 						<input hidden name="intent" defaultValue="registerNew" />
-						<input hidden name="creatorUserId" defaultValue={userDetails.id} />
 						<Stack>
 							<Title order={3}>Create User</Title>
 							<TextInput label="Name" required name="username" />
@@ -179,6 +218,14 @@ export default function Page() {
 									</ActionIcon>
 								}
 							/>
+							{!coreDetails.signupAllowed ? (
+								<TextInput
+									required
+									name="adminAccessToken"
+									label="Admin Access Token"
+									description="This is required as registration is disabled"
+								/>
+							) : null}
 							<Button variant="outline" type="submit">
 								Create
 							</Button>
@@ -206,15 +253,22 @@ export default function Page() {
 	);
 }
 
+type User = UsersListQuery["usersList"][number];
+
 const UserDisplay = (props: { index: number }) => {
 	const loaderData = useLoaderData<typeof loader>();
-	const fetcher = useFetcher<typeof action>();
-	const deleteFormRef = useRef<HTMLFormElement>(null);
 	const user = loaderData.usersList[props.index];
+	const submit = useConfirmSubmit();
+	const [updateUserData, setUpdateUserData] = useState<User | null>(null);
+
 	if (!user) return null;
 
 	return (
 		<Paper p="xs" withBorder key={user.id} data-user-id={user.id}>
+			<UpdateUserModal
+				updateUserData={updateUserData}
+				closeIntegrationModal={() => setUpdateUserData(null)}
+			/>
 			<Flex align="center" justify="space-between">
 				<Group wrap="nowrap">
 					<Avatar name={user.name} />
@@ -222,30 +276,84 @@ const UserDisplay = (props: { index: number }) => {
 						<Text lineClamp={1} fw="bold">
 							{truncate(user.name, { length: 20 })}
 						</Text>
-						<Text size="xs">Role: {changeCase(user.lot)}</Text>
+						<Text size="xs">
+							Role: {changeCase(user.lot)}
+							{user.isDisabled ? ", Status: Disabled" : null}
+						</Text>
 					</Box>
 				</Group>
-				<fetcher.Form
-					method="POST"
-					ref={deleteFormRef}
-					action={withQuery("", { intent: "delete" })}
-					style={{ flex: "none" }}
-				>
-					<input hidden name="toDeleteUserId" defaultValue={user.id} />
+				<Group>
 					<ActionIcon
-						color="red"
+						color="indigo"
 						variant="outline"
-						onClick={async () => {
-							const conf = await confirmWrapper({
-								confirmation: "Are you sure you want to delete this user?",
-							});
-							if (conf) fetcher.submit(deleteFormRef.current);
-						}}
+						onClick={() => setUpdateUserData(user)}
 					>
-						<IconTrash size={16} />
+						<IconPencil />
 					</ActionIcon>
-				</fetcher.Form>
+					<Form
+						method="POST"
+						action={withQuery("", { intent: "delete" })}
+						style={{ flex: "none" }}
+					>
+						<input hidden name="toDeleteUserId" defaultValue={user.id} />
+						<ActionIcon
+							color="red"
+							type="submit"
+							variant="outline"
+							onClick={async (e) => {
+								const form = e.currentTarget.form;
+								e.preventDefault();
+								const conf = await confirmWrapper({
+									confirmation: "Are you sure you want to delete this user?",
+								});
+								if (conf && form) submit(form);
+							}}
+						>
+							<IconTrash size={16} />
+						</ActionIcon>
+					</Form>
+				</Group>
 			</Flex>
 		</Paper>
 	);
 };
+
+const UpdateUserModal = (props: {
+	updateUserData: User | null;
+	closeIntegrationModal: () => void;
+}) => {
+	return (
+		<Modal
+			opened={props.updateUserData !== null}
+			onClose={props.closeIntegrationModal}
+			centered
+			withCloseButton={false}
+		>
+			<Form
+				replace
+				method="POST"
+				onSubmit={() => props.closeIntegrationModal()}
+				action={withQuery("", { intent: "update" })}
+			>
+				<input hidden name="userId" defaultValue={props.updateUserData?.id} />
+				<Stack>
+					<Title order={3}>Update {props.updateUserData?.name}</Title>
+					<TextInput
+						required
+						name="adminAccessToken"
+						label="Admin Access Token"
+						description="This is required as registration is disabled"
+					/>
+					<Switch
+						label="Is disabled"
+						name="isDisabled"
+						description="This will disable the user from logging in"
+						defaultChecked={props.updateUserData?.isDisabled || undefined}
+					/>
+					<PasswordInput name="password" label="Password" />
+					<Button type="submit">Submit</Button>
+				</Stack>
+			</Form>
+		</Modal>
+	);
+};
diff --git a/apps/frontend/app/routes/api.auth.tsx b/apps/frontend/app/routes/api.auth.tsx
index df3f613ac7..4dfb641baa 100644
--- a/apps/frontend/app/routes/api.auth.tsx
+++ b/apps/frontend/app/routes/api.auth.tsx
@@ -31,7 +31,7 @@ export const loader = unstable_defineLoader(async ({ request }) => {
 	const [_, { registerUser }] = await Promise.all([
 		getCachedCoreDetails(),
 		serverGqlService.request(RegisterUserDocument, {
-			input: { oidc: oidcInput },
+			input: { data: { oidc: oidcInput } },
 		}),
 	]);
 	if (registerUser.__typename === "RegisterError")
diff --git a/apps/frontend/app/routes/auth.tsx b/apps/frontend/app/routes/auth.tsx
index 2a31d8b8c6..a9ead4430a 100644
--- a/apps/frontend/app/routes/auth.tsx
+++ b/apps/frontend/app/routes/auth.tsx
@@ -79,7 +79,8 @@ export const loader = unstable_defineLoader(async ({ request }) => {
 					{ query: "avengers" },
 				),
 				{
-					message: "Welcome to Ryot! Add any movie you want to your watchlist!",
+					message:
+						"Welcome to Ryot! Get started by adding a movie to your watchlist!",
 					closeAfter: dayjsLib.duration(10, "second").asMilliseconds(),
 				},
 			);
@@ -122,9 +123,11 @@ export const action = unstable_defineAction(async ({ request }) => {
 				RegisterUserDocument,
 				{
 					input: {
-						password: {
-							password: submission.value.password,
-							username: submission.value.username,
+						data: {
+							password: {
+								password: submission.value.password,
+								username: submission.value.username,
+							},
 						},
 					},
 				},
@@ -171,6 +174,10 @@ export const action = unstable_defineAction(async ({ request }) => {
 					LoginErrorVariant.UsernameDoesNotExist,
 					() => "The credentials provided were incorrect",
 				)
+				.with(
+					LoginErrorVariant.AccountDisabled,
+					() => "This account has been disabled. Please contact support.",
+				)
 				.with(
 					LoginErrorVariant.IncorrectProviderChosen,
 					() => "The provider chosen was incorrect",
diff --git a/docs/includes/backend-config-schema.yaml b/docs/includes/backend-config-schema.yaml
index af789a3468..29042fa387 100644
--- a/docs/includes/backend-config-schema.yaml
+++ b/docs/includes/backend-config-schema.yaml
@@ -3,9 +3,14 @@ anime_and_manga:
   # Settings related to Anilist.
   anilist:
     # Whether to prefer the english name for media from this source.
+    # @deprecated
     # @envvar ANIME_AND_MANGA_ANILIST_PREFER_ENGLISH
     prefer_english: false
 
+    # The preferred language for media from this source.
+    # @envvar ANIME_AND_MANGA_ANILIST_PREFERRED_LANGUAGE
+    preferred_language: "native"
+
   # Settings related to MAL.
   mal:
     # The client ID to be used for the MAL API.
@@ -153,6 +158,10 @@ scheduler:
 
 # Settings related to server.
 server:
+  # An access token that can be used for admin operations.
+  # @envvar SERVER_ADMIN_ACCESS_TOKEN
+  admin_access_token: ""
+
   # An array of URLs for CORS.
   # @envvar SERVER_CORS_ORIGINS
   cors_origins: []
diff --git a/libs/config/src/lib.rs b/libs/config/src/lib.rs
index b99cdcddf0..bc4613f239 100644
--- a/libs/config/src/lib.rs
+++ b/libs/config/src/lib.rs
@@ -31,11 +31,25 @@ pub struct MalConfig {
     pub client_id: String,
 }
 
+derive_enum!(
+    #[derive(ConfigEnum, Default)]
+    pub enum AnilistPreferredLanguage {
+        English,
+        #[default]
+        Native,
+        Romaji,
+    }
+);
+
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
 #[config(rename_all = "snake_case", env_prefix = "ANIME_AND_MANGA_ANILIST_")]
 pub struct AnilistConfig {
     /// Whether to prefer the english name for media from this source.
+    // TODO: Remove this in the next major release.
+    #[deprecated]
     pub prefer_english: bool,
+    /// The preferred language for media from this source.
+    pub preferred_language: AnilistPreferredLanguage,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
@@ -92,13 +106,6 @@ derive_enum!(
     }
 );
 
-#[derive(Debug, Serialize, Deserialize, Clone, Config)]
-#[config(rename_all = "snake_case", env_prefix = "BOOKS_GOOGLE_BOOKS_")]
-pub struct GoogleBooksConfig {
-    /// Whether to pass the raw query string to the search API.
-    pub pass_raw_query: bool,
-}
-
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
 #[config(rename_all = "snake_case", env_prefix = "BOOKS_OPENLIBRARY_")]
 pub struct OpenlibraryConfig {
@@ -106,6 +113,13 @@ pub struct OpenlibraryConfig {
     pub cover_image_size: OpenlibraryCoverImageSize,
 }
 
+#[derive(Debug, Serialize, Deserialize, Clone, Config)]
+#[config(rename_all = "snake_case", env_prefix = "BOOKS_GOOGLE_BOOKS_")]
+pub struct GoogleBooksConfig {
+    /// Whether to pass the raw query string to the search API.
+    pub pass_raw_query: bool,
+}
+
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
 #[config(rename_all = "snake_case")]
 pub struct BookConfig {
@@ -370,6 +384,9 @@ pub struct ServerConfig {
     /// Number of seconds to sleep before starting the server.
     #[setting(default = 0)]
     pub sleep_before_startup_seconds: u64,
+    /// An access token that can be used for admin operations.
+    #[setting(default = format!("{}", PROJECT_NAME))]
+    pub admin_access_token: String,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
@@ -466,8 +483,8 @@ impl AppConfig {
         cl.podcasts.listennotes.api_token = gt();
         cl.video_games.twitch.client_id = gt();
         cl.video_games.twitch.client_secret = gt();
-        cl.server.cors_origins = vec![gt()];
         cl.users.jwt_secret = gt();
+        cl.server.cors_origins = vec![gt()];
         cl.server.smtp.server = gt();
         cl.server.smtp.user = gt();
         cl.server.smtp.password = gt();
@@ -475,6 +492,7 @@ impl AppConfig {
         cl.server.oidc.client_id = gt();
         cl.server.oidc.client_secret = gt();
         cl.server.oidc.issuer_url = gt();
+        cl.server.admin_access_token = gt();
         cl
     }
 }
diff --git a/libs/database/src/migrations/m20230417_create_user.rs b/libs/database/src/migrations/m20230417_create_user.rs
index c2fce5911b..d92fd07932 100644
--- a/libs/database/src/migrations/m20230417_create_user.rs
+++ b/libs/database/src/migrations/m20230417_create_user.rs
@@ -19,6 +19,7 @@ pub enum User {
     SinkIntegrations,
     OidcIssuerId,
     ExtraInformation,
+    IsDisabled,
 }
 
 #[async_trait::async_trait]
@@ -44,6 +45,7 @@ impl MigrationTrait for Migration {
                             .default(Expr::current_timestamp()),
                     )
                     .col(ColumnDef::new(User::ExtraInformation).json_binary())
+                    .col(ColumnDef::new(User::IsDisabled).boolean())
                     .to_owned(),
             )
             .await?;
diff --git a/libs/database/src/migrations/m20240717_zz_add_columns_to_user_table.rs b/libs/database/src/migrations/m20240717_zz_add_columns_to_user_table.rs
new file mode 100644
index 0000000000..e650c29afc
--- /dev/null
+++ b/libs/database/src/migrations/m20240717_zz_add_columns_to_user_table.rs
@@ -0,0 +1,23 @@
+use sea_orm_migration::prelude::*;
+
+#[derive(DeriveMigrationName)]
+pub struct Migration;
+
+#[async_trait::async_trait]
+impl MigrationTrait for Migration {
+    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        let db = manager.get_connection();
+        db.execute_unprepared(
+            r#"
+ALTER TABLE "user" ADD COLUMN IF NOT EXISTS "is_disabled" boolean;
+        "#,
+        )
+        .await?;
+
+        Ok(())
+    }
+
+    async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
+        Ok(())
+    }
+}
diff --git a/libs/database/src/migrations/mod.rs b/libs/database/src/migrations/mod.rs
index 0ca91c68ff..75916a2941 100644
--- a/libs/database/src/migrations/mod.rs
+++ b/libs/database/src/migrations/mod.rs
@@ -36,6 +36,7 @@ mod m20240713_create_user_summary;
 mod m20240713_zz_cleanup_v6_6_2_migrations;
 mod m20240716_add_columns_to_user_table;
 mod m20240717_add_columns_to_integration_and_notification_tables;
+mod m20240717_zz_add_columns_to_user_table;
 
 pub use m20230410_create_metadata::Metadata as AliasedMetadata;
 pub use m20230413_create_person::Person as AliasedPerson;
@@ -93,6 +94,7 @@ impl MigratorTrait for Migrator {
             Box::new(m20240713_zz_cleanup_v6_6_2_migrations::Migration),
             Box::new(m20240716_add_columns_to_user_table::Migration),
             Box::new(m20240717_add_columns_to_integration_and_notification_tables::Migration),
+            Box::new(m20240717_zz_add_columns_to_user_table::Migration),
         ]
     }
 }
diff --git a/libs/generated/src/graphql/backend/gql.ts b/libs/generated/src/graphql/backend/gql.ts
index 34beb45837..68bcd34ef3 100644
--- a/libs/generated/src/graphql/backend/gql.ts
+++ b/libs/generated/src/graphql/backend/gql.ts
@@ -13,7 +13,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
  * Therefore it is highly recommended to use the babel or swc plugin for production.
  */
 const documents = {
-    "mutation RegisterUser($input: AuthUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateUserWorkout($input: UserWorkoutInput!) {\n  createUserWorkout(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob($toExport: [ExportItem!]!) {\n  deployExportJob(toExport: $toExport)\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkout($input: UpdateUserWorkoutInput!) {\n  updateUserWorkout(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation PostReview($input: PostReviewInput!) {\n  postReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UpdateUserPreferenceInput!) {\n  updateUserPreference(input: $input)\n}": types.RegisterUserDocument,
+    "mutation RegisterUser($input: RegisterUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateUserWorkout($input: UserWorkoutInput!) {\n  createUserWorkout(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob($toExport: [ExportItem!]!) {\n  deployExportJob(toExport: $toExport)\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkout($input: UpdateUserWorkoutInput!) {\n  updateUserWorkout(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation PostReview($input: PostReviewInput!) {\n  postReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UpdateUserPreferenceInput!) {\n  updateUserPreference(input: $input)\n}": types.RegisterUserDocument,
     "query CollectionContents($input: CollectionContentsInput!) {\n  collectionContents(input: $input) {\n    user {\n      id\n      name\n    }\n    reviews {\n      ...ReviewItemPart\n    }\n    results {\n      details {\n        total\n        nextPage\n      }\n      items {\n        entityId\n        entityLot\n      }\n    }\n    details {\n      name\n      description\n      createdOn\n    }\n  }\n}": types.CollectionContentsDocument,
     "query CoreDetails {\n  coreDetails {\n    isPro\n    version\n    docsLink\n    pageLimit\n    websiteUrl\n    authorName\n    oidcEnabled\n    signupAllowed\n    repositoryLink\n    localAuthDisabled\n    fileStorageEnabled\n    tokenValidForDays\n  }\n}": types.CoreDetailsDocument,
     "query ExerciseDetails($exerciseId: String!) {\n  exerciseDetails(exerciseId: $exerciseId) {\n    id\n    lot\n    source\n    level\n    force\n    mechanic\n    equipment\n    muscles\n    createdByUserId\n    attributes {\n      instructions\n      images\n    }\n  }\n}": types.ExerciseDetailsDocument,
@@ -39,7 +39,7 @@ const documents = {
     "query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableWatchProviders\n      disableYankIntegrations\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\n      measurements {\n        custom {\n          name\n          dataType\n        }\n        inbuilt {\n          weight\n          bodyMassIndex\n          totalBodyWater\n          muscle\n          leanBodyMass\n          bodyFat\n          boneMass\n          visceralFat\n          waistCircumference\n          waistToHeightRatio\n          hipCircumference\n          waistToHipRatio\n          chestCircumference\n          thighCircumference\n          bicepsCircumference\n          neckCircumference\n          bodyFatCaliper\n          chestSkinfold\n          abdominalSkinfold\n          thighSkinfold\n          basalMetabolicRate\n          totalDailyEnergyExpenditure\n          calories\n        }\n      }\n      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}": types.UserPreferencesDocument,
     "query UserWorkoutList($input: SearchInput!) {\n  userWorkoutList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      id\n      name\n      startTime\n      endTime\n      summary {\n        ...WorkoutSummaryPart\n      }\n    }\n  }\n}": types.UserWorkoutListDocument,
     "query WorkoutDetails($workoutId: String!) {\n  workoutDetails(workoutId: $workoutId) {\n    id\n    name\n    comment\n    startTime\n    endTime\n    repeatedFrom\n    summary {\n      ...WorkoutSummaryPart\n    }\n    information {\n      assets {\n        ...EntityAssetsPart\n      }\n      exercises {\n        name\n        lot\n        notes\n        restTime\n        total {\n          ...WorkoutOrExerciseTotalsPart\n        }\n        supersetWith\n        assets {\n          ...EntityAssetsPart\n        }\n        sets {\n          statistic {\n            ...WorkoutSetStatisticPart\n          }\n          note\n          lot\n          personalBests\n          confirmedAt\n        }\n      }\n    }\n  }\n}": types.WorkoutDetailsDocument,
-    "query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    id\n    name\n    count\n    isDefault\n    description\n    creator {\n      id\n      name\n    }\n    collaborators {\n      id\n      name\n    }\n    informationTemplate {\n      lot\n      name\n      required\n      description\n      defaultValue\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    name\n    lot\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}": types.GetOidcRedirectUrlDocument,
+    "query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    id\n    name\n    count\n    isDefault\n    description\n    creator {\n      id\n      name\n    }\n    collaborators {\n      id\n      name\n    }\n    informationTemplate {\n      lot\n      name\n      required\n      description\n      defaultValue\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    lot\n    name\n    isDisabled\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}": types.GetOidcRedirectUrlDocument,
     "fragment SeenPodcastExtraInformationPart on SeenPodcastExtraInformation {\n  episode\n}\n\nfragment SeenShowExtraInformationPart on SeenShowExtraInformation {\n  episode\n  season\n}\n\nfragment SeenAnimeExtraInformationPart on SeenAnimeExtraInformation {\n  episode\n}\n\nfragment SeenMangaExtraInformationPart on SeenMangaExtraInformation {\n  chapter\n  volume\n}\n\nfragment CalendarEventPart on GraphqlCalendarEvent {\n  date\n  metadataId\n  metadataLot\n  episodeName\n  metadataTitle\n  metadataImage\n  calendarEventId\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\n  }\n}\n\nfragment SeenPart on Seen {\n  id\n  progress\n  providerWatchedOn\n  state\n  startedOn\n  finishedOn\n  lastUpdatedOn\n  numTimesUpdated\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\n  }\n  animeExtraInformation {\n    ...SeenAnimeExtraInformationPart\n  }\n  mangaExtraInformation {\n    ...SeenMangaExtraInformationPart\n  }\n}\n\nfragment MetadataSearchItemPart on MetadataSearchItem {\n  identifier\n  title\n  image\n  publishYear\n}\n\nfragment WorkoutOrExerciseTotalsPart on WorkoutOrExerciseTotals {\n  personalBestsAchieved\n  weight\n  reps\n  distance\n  duration\n  restTime\n}\n\nfragment EntityAssetsPart on EntityAssets {\n  images\n  videos\n}\n\nfragment WorkoutSetStatisticPart on WorkoutSetStatistic {\n  duration\n  distance\n  reps\n  weight\n  oneRm\n  pace\n  volume\n}\n\nfragment WorkoutSummaryPart on WorkoutSummary {\n  total {\n    ...WorkoutOrExerciseTotalsPart\n  }\n  exercises {\n    numSets\n    id\n    lot\n    bestSet {\n      statistic {\n        ...WorkoutSetStatisticPart\n      }\n      lot\n      personalBests\n    }\n  }\n}\n\nfragment CollectionPart on Collection {\n  id\n  name\n  userId\n}\n\nfragment ReviewItemPart on ReviewItem {\n  id\n  rating\n  textOriginal\n  textRendered\n  isSpoiler\n  visibility\n  postedOn\n  postedBy {\n    id\n    name\n  }\n  comments {\n    id\n    text\n    createdOn\n    user {\n      id\n      name\n    }\n    likedBy\n  }\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\n  }\n  animeExtraInformation {\n    ...SeenAnimeExtraInformationPart\n  }\n  mangaExtraInformation {\n    ...SeenMangaExtraInformationPart\n  }\n}": types.SeenPodcastExtraInformationPartFragmentDoc,
 };
 
@@ -60,7 +60,7 @@ export function graphql(source: string): unknown;
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
-export function graphql(source: "mutation RegisterUser($input: AuthUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateUserWorkout($input: UserWorkoutInput!) {\n  createUserWorkout(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob($toExport: [ExportItem!]!) {\n  deployExportJob(toExport: $toExport)\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkout($input: UpdateUserWorkoutInput!) {\n  updateUserWorkout(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation PostReview($input: PostReviewInput!) {\n  postReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UpdateUserPreferenceInput!) {\n  updateUserPreference(input: $input)\n}"): (typeof documents)["mutation RegisterUser($input: AuthUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateUserWorkout($input: UserWorkoutInput!) {\n  createUserWorkout(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob($toExport: [ExportItem!]!) {\n  deployExportJob(toExport: $toExport)\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkout($input: UpdateUserWorkoutInput!) {\n  updateUserWorkout(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation PostReview($input: PostReviewInput!) {\n  postReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UpdateUserPreferenceInput!) {\n  updateUserPreference(input: $input)\n}"];
+export function graphql(source: "mutation RegisterUser($input: RegisterUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateUserWorkout($input: UserWorkoutInput!) {\n  createUserWorkout(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob($toExport: [ExportItem!]!) {\n  deployExportJob(toExport: $toExport)\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkout($input: UpdateUserWorkoutInput!) {\n  updateUserWorkout(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation PostReview($input: PostReviewInput!) {\n  postReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UpdateUserPreferenceInput!) {\n  updateUserPreference(input: $input)\n}"): (typeof documents)["mutation RegisterUser($input: RegisterUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateUserWorkout($input: UserWorkoutInput!) {\n  createUserWorkout(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob($toExport: [ExportItem!]!) {\n  deployExportJob(toExport: $toExport)\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkout($input: UpdateUserWorkoutInput!) {\n  updateUserWorkout(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation PostReview($input: PostReviewInput!) {\n  postReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UpdateUserPreferenceInput!) {\n  updateUserPreference(input: $input)\n}"];
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
@@ -164,7 +164,7 @@ export function graphql(source: "query WorkoutDetails($workoutId: String!) {\n
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
-export function graphql(source: "query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    id\n    name\n    count\n    isDefault\n    description\n    creator {\n      id\n      name\n    }\n    collaborators {\n      id\n      name\n    }\n    informationTemplate {\n      lot\n      name\n      required\n      description\n      defaultValue\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    name\n    lot\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"): (typeof documents)["query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    id\n    name\n    count\n    isDefault\n    description\n    creator {\n      id\n      name\n    }\n    collaborators {\n      id\n      name\n    }\n    informationTemplate {\n      lot\n      name\n      required\n      description\n      defaultValue\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    name\n    lot\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"];
+export function graphql(source: "query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    id\n    name\n    count\n    isDefault\n    description\n    creator {\n      id\n      name\n    }\n    collaborators {\n      id\n      name\n    }\n    informationTemplate {\n      lot\n      name\n      required\n      description\n      defaultValue\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    lot\n    name\n    isDisabled\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"): (typeof documents)["query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    id\n    name\n    count\n    isDefault\n    description\n    creator {\n      id\n      name\n    }\n    collaborators {\n      id\n      name\n    }\n    informationTemplate {\n      lot\n      name\n      required\n      description\n      defaultValue\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    lot\n    name\n    isDisabled\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"];
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
diff --git a/libs/generated/src/graphql/backend/graphql.ts b/libs/generated/src/graphql/backend/graphql.ts
index 4cbdeaa3ab..7bc7483dcf 100644
--- a/libs/generated/src/graphql/backend/graphql.ts
+++ b/libs/generated/src/graphql/backend/graphql.ts
@@ -69,6 +69,7 @@ export type AuthUserInput = {
 };
 
 export enum BackendError {
+  AdminOnlyAction = 'ADMIN_ONLY_ACTION',
   MutationNotAllowed = 'MUTATION_NOT_ALLOWED',
   NoAuthToken = 'NO_AUTH_TOKEN',
   NoUserId = 'NO_USER_ID',
@@ -731,6 +732,7 @@ export type LoginError = {
 };
 
 export enum LoginErrorVariant {
+  AccountDisabled = 'ACCOUNT_DISABLED',
   CredentialsMismatch = 'CREDENTIALS_MISMATCH',
   IncorrectProviderChosen = 'INCORRECT_PROVIDER_CHOSEN',
   UsernameDoesNotExist = 'USERNAME_DOES_NOT_EXIST'
@@ -1204,7 +1206,7 @@ export type MutationRootPresignedPutS3UrlArgs = {
 
 
 export type MutationRootRegisterUserArgs = {
-  input: AuthUserInput;
+  input: RegisterUserInput;
 };
 
 
@@ -1278,8 +1280,6 @@ export type OidcUserInput = {
 };
 
 export type PasswordUserInput = {
-  /** If provided, that means an admin tried to create an account. */
-  creatorUserId?: InputMaybe<Scalars['String']['input']>;
   password: Scalars['String']['input'];
   username: Scalars['String']['input'];
 };
@@ -1688,6 +1688,12 @@ export enum RegisterErrorVariant {
 
 export type RegisterResult = RegisterError | StringIdObject;
 
+export type RegisterUserInput = {
+  /** If registration is disabled, this can be used to override it. */
+  adminAccessToken?: InputMaybe<Scalars['String']['input']>;
+  data: AuthUserInput;
+};
+
 export type ReviewItem = {
   animeExtraInformation?: Maybe<SeenAnimeExtraInformation>;
   comments: Array<ImportOrExportItemReviewComment>;
@@ -1869,8 +1875,12 @@ export type UpdateSeenItemInput = {
 };
 
 export type UpdateUserInput = {
+  adminAccessToken?: InputMaybe<Scalars['String']['input']>;
   extraInformation?: InputMaybe<Scalars['JSON']['input']>;
+  isDisabled?: InputMaybe<Scalars['Boolean']['input']>;
+  lot?: InputMaybe<UserLot>;
   password?: InputMaybe<Scalars['String']['input']>;
+  userId: Scalars['String']['input'];
   username?: InputMaybe<Scalars['String']['input']>;
 };
 
@@ -1905,6 +1915,7 @@ export type User = {
   createdOn: Scalars['DateTime']['output'];
   id: Scalars['String']['output'];
   isDemo?: Maybe<Scalars['Boolean']['output']>;
+  isDisabled?: Maybe<Scalars['Boolean']['output']>;
   lot: UserLot;
   name: Scalars['String']['output'];
   oidcIssuerId?: Maybe<Scalars['String']['output']>;
@@ -2437,7 +2448,7 @@ export type WorkoutSummaryExercise = {
 };
 
 export type RegisterUserMutationVariables = Exact<{
-  input: AuthUserInput;
+  input: RegisterUserInput;
 }>;
 
 
@@ -2941,7 +2952,7 @@ export type UsersListQueryVariables = Exact<{
 }>;
 
 
-export type UsersListQuery = { usersList: Array<{ id: string, name: string, lot: UserLot }> };
+export type UsersListQuery = { usersList: Array<{ id: string, lot: UserLot, name: string, isDisabled?: boolean | null }> };
 
 export type UserUpcomingCalendarEventsQueryVariables = Exact<{
   input: UserUpcomingCalendarEventInput;
@@ -3017,7 +3028,7 @@ export const WorkoutSetStatisticPartFragmentDoc = {"kind":"Document","definition
 export const WorkoutSummaryPartFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSummaryPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSummary"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"numSets"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"bestSet"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"statistic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSetStatisticPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"personalBests"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutOrExerciseTotals"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personalBestsAchieved"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"restTime"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSetStatisticPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSetStatistic"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"oneRm"}},{"kind":"Field","name":{"kind":"Name","value":"pace"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}}]} as unknown as DocumentNode<WorkoutSummaryPartFragment, unknown>;
 export const CollectionPartFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}}]} as unknown as DocumentNode<CollectionPartFragment, unknown>;
 export const ReviewItemPartFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ReviewItemPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rating"}},{"kind":"Field","name":{"kind":"Name","value":"textOriginal"}},{"kind":"Field","name":{"kind":"Name","value":"textRendered"}},{"kind":"Field","name":{"kind":"Name","value":"isSpoiler"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"postedOn"}},{"kind":"Field","name":{"kind":"Name","value":"postedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"likedBy"}}]}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenAnimeExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenMangaExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}}]} as unknown as DocumentNode<ReviewItemPartFragment, unknown>;
-export const RegisterUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RegisterUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AuthUserInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StringIdObject"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<RegisterUserMutation, RegisterUserMutationVariables>;
+export const RegisterUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RegisterUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterUserInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StringIdObject"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<RegisterUserMutation, RegisterUserMutationVariables>;
 export const LoginUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"LoginUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AuthUserInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginResponse"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apiKey"}}]}}]}}]}}]} as unknown as DocumentNode<LoginUserMutation, LoginUserMutationVariables>;
 export const AddEntityToCollectionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddEntityToCollection"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ChangeCollectionToEntityInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addEntityToCollection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<AddEntityToCollectionMutation, AddEntityToCollectionMutationVariables>;
 export const CommitMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CommitMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CommitMediaInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"commitMetadata"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<CommitMetadataMutation, CommitMetadataMutationVariables>;
@@ -3092,7 +3103,7 @@ export const UserExportsDocument = {"kind":"Document","definitions":[{"kind":"Op
 export const UserCollectionsListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserCollectionsList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userCollectionsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"creator"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"collaborators"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"informationTemplate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"required"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}}]}}]}}]}}]} as unknown as DocumentNode<UserCollectionsListQuery, UserCollectionsListQueryVariables>;
 export const UserIntegrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserIntegrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userIntegrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"source"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"maximumProgress"}},{"kind":"Field","name":{"kind":"Name","value":"minimumProgress"}},{"kind":"Field","name":{"kind":"Name","value":"lastTriggeredOn"}}]}}]}}]} as unknown as DocumentNode<UserIntegrationsQuery, UserIntegrationsQueryVariables>;
 export const UserNotificationPlatformsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserNotificationPlatforms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userNotificationPlatforms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode<UserNotificationPlatformsQuery, UserNotificationPlatformsQueryVariables>;
-export const UsersListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UsersList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"usersList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}}]}}]}}]} as unknown as DocumentNode<UsersListQuery, UsersListQueryVariables>;
+export const UsersListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UsersList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"usersList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}}]}}]}}]} as unknown as DocumentNode<UsersListQuery, UsersListQueryVariables>;
 export const UserUpcomingCalendarEventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserUpcomingCalendarEvents"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserUpcomingCalendarEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userUpcomingCalendarEvents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CalendarEventPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CalendarEventPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"GraphqlCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"metadataId"}},{"kind":"Field","name":{"kind":"Name","value":"metadataLot"}},{"kind":"Field","name":{"kind":"Name","value":"episodeName"}},{"kind":"Field","name":{"kind":"Name","value":"metadataTitle"}},{"kind":"Field","name":{"kind":"Name","value":"metadataImage"}},{"kind":"Field","name":{"kind":"Name","value":"calendarEventId"}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}}]}}]} as unknown as DocumentNode<UserUpcomingCalendarEventsQuery, UserUpcomingCalendarEventsQueryVariables>;
 export const UserCalendarEventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserCalendarEvents"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserCalendarEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userCalendarEvents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"events"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CalendarEventPart"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CalendarEventPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"GraphqlCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"metadataId"}},{"kind":"Field","name":{"kind":"Name","value":"metadataLot"}},{"kind":"Field","name":{"kind":"Name","value":"episodeName"}},{"kind":"Field","name":{"kind":"Name","value":"metadataTitle"}},{"kind":"Field","name":{"kind":"Name","value":"metadataImage"}},{"kind":"Field","name":{"kind":"Name","value":"calendarEventId"}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}}]}}]} as unknown as DocumentNode<UserCalendarEventsQuery, UserCalendarEventsQueryVariables>;
 export const MetadataPartialDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MetadataPartialDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"metadataId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"metadataPartialDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"metadataId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"metadataId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"image"}},{"kind":"Field","name":{"kind":"Name","value":"publishYear"}}]}}]}}]} as unknown as DocumentNode<MetadataPartialDetailsQuery, MetadataPartialDetailsQueryVariables>;
diff --git a/libs/graphql/src/backend/mutations/combined.gql b/libs/graphql/src/backend/mutations/combined.gql
index 8d171fae22..fe262f2182 100644
--- a/libs/graphql/src/backend/mutations/combined.gql
+++ b/libs/graphql/src/backend/mutations/combined.gql
@@ -1,4 +1,4 @@
-mutation RegisterUser($input: AuthUserInput!) {
+mutation RegisterUser($input: RegisterUserInput!) {
   registerUser(input: $input){
     __typename
     ... on RegisterError {
diff --git a/libs/graphql/src/backend/queries/combined.gql b/libs/graphql/src/backend/queries/combined.gql
index 5df63dc582..e867d6eca3 100644
--- a/libs/graphql/src/backend/queries/combined.gql
+++ b/libs/graphql/src/backend/queries/combined.gql
@@ -81,8 +81,9 @@ query UserNotificationPlatforms {
 query UsersList($query: String) {
   usersList(query: $query) {
     id
-    name
     lot
+    name
+    isDisabled
   }
 }
 


Test patch: