mirror of
https://github.com/unraid/api.git
synced 2026-01-08 01:29:49 -06:00
refactor(web): sign in / out graph mutations
This commit is contained in:
@@ -3,16 +3,18 @@ import { TransitionRoot } from '@headlessui/vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import { useDropdownStore } from '~/store/dropdown';
|
||||
import { useErrorsStore } from '~/store/errors';
|
||||
import { useServerStore } from '~/store/server';
|
||||
|
||||
defineProps<{ t: any; }>();
|
||||
|
||||
const dropdownStore = useDropdownStore();
|
||||
const { dropdownVisible } = storeToRefs(dropdownStore);
|
||||
const { errors } = storeToRefs(useErrorsStore());
|
||||
const { connectPluginInstalled, registered, state, stateDataError } = storeToRefs(useServerStore());
|
||||
|
||||
const showDefaultContent = computed(() => !showLaunchpad.value);
|
||||
const showLaunchpad = computed(() => state.value === 'ENOKEYFILE' || ((connectPluginInstalled.value && !registered.value) && !stateDataError.value));
|
||||
const showLaunchpad = computed(() => state.value === 'ENOKEYFILE' || ((connectPluginInstalled.value && !registered.value) && !errors.value.length && !stateDataError.value));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -13,6 +13,8 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
|
||||
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
||||
*/
|
||||
const documents = {
|
||||
"\n mutation ConnectSignIn($input: ConnectSignInInput!) {\n connectSignIn(input: $input)\n }\n": types.ConnectSignInDocument,
|
||||
"\n mutation SignOut {\n connectSignOut\n }\n": types.SignOutDocument,
|
||||
"\n query serverState {\n cloud {\n error\n apiKey {\n valid\n error\n }\n cloud {\n status\n error\n }\n minigraphql {\n status\n error\n }\n relay {\n status\n error\n }\n }\n config {\n error\n valid\n }\n info {\n os {\n hostname\n }\n }\n owner {\n avatar\n username\n }\n registration {\n state\n expiration\n keyFile {\n contents\n }\n }\n vars {\n regGen\n regState\n configError\n configValid\n }\n }\n": types.serverStateDocument,
|
||||
};
|
||||
|
||||
@@ -30,6 +32,14 @@ const documents = {
|
||||
*/
|
||||
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: "\n mutation ConnectSignIn($input: ConnectSignInInput!) {\n connectSignIn(input: $input)\n }\n"): (typeof documents)["\n mutation ConnectSignIn($input: ConnectSignInInput!) {\n connectSignIn(input: $input)\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation SignOut {\n connectSignOut\n }\n"): (typeof documents)["\n mutation SignOut {\n connectSignOut\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
@@ -20,10 +20,16 @@ export type Scalars = {
|
||||
JSON: { input: string; output: string; }
|
||||
/** The `Long` scalar type represents 52-bit integers */
|
||||
Long: { input: number; output: number; }
|
||||
/** A field whose value is a valid TCP port within the range of 0 to 65535: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_ports */
|
||||
Port: { input: number; output: number; }
|
||||
/** A field whose value is a generic Universally Unique Identifier: https://en.wikipedia.org/wiki/Universally_unique_identifier. */
|
||||
UUID: { input: string; output: string; }
|
||||
};
|
||||
|
||||
export type AllowedOriginInput = {
|
||||
origins: Array<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type ApiKey = {
|
||||
__typename?: 'ApiKey';
|
||||
description?: Maybe<Scalars['String']['output']>;
|
||||
@@ -242,6 +248,20 @@ export enum ConfigErrorState {
|
||||
Withdrawn = 'WITHDRAWN'
|
||||
}
|
||||
|
||||
export type ConnectSignInInput = {
|
||||
accessToken?: InputMaybe<Scalars['String']['input']>;
|
||||
apiKey: Scalars['String']['input'];
|
||||
idToken?: InputMaybe<Scalars['String']['input']>;
|
||||
refreshToken?: InputMaybe<Scalars['String']['input']>;
|
||||
userInfo?: InputMaybe<ConnectUserInfoInput>;
|
||||
};
|
||||
|
||||
export type ConnectUserInfoInput = {
|
||||
avatar?: InputMaybe<Scalars['String']['input']>;
|
||||
email: Scalars['String']['input'];
|
||||
preferred_username: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type ContainerHostConfig = {
|
||||
__typename?: 'ContainerHostConfig';
|
||||
networkMode: Scalars['String']['output'];
|
||||
@@ -568,6 +588,8 @@ export type Mutation = {
|
||||
/** Cancel parity check */
|
||||
cancelParityCheck?: Maybe<Scalars['JSON']['output']>;
|
||||
clearArrayDiskStatistics?: Maybe<Scalars['JSON']['output']>;
|
||||
connectSignIn: Scalars['Boolean']['output'];
|
||||
connectSignOut: Scalars['Boolean']['output'];
|
||||
/** Delete a user */
|
||||
deleteUser?: Maybe<User>;
|
||||
/** Get an existing API key */
|
||||
@@ -582,6 +604,8 @@ export type Mutation = {
|
||||
/** Resume parity check */
|
||||
resumeParityCheck?: Maybe<Scalars['JSON']['output']>;
|
||||
sendNotification?: Maybe<Notification>;
|
||||
setAdditionalAllowedOrigins: Array<Scalars['String']['output']>;
|
||||
setupRemoteAccess: Scalars['Boolean']['output'];
|
||||
shutdown?: Maybe<Scalars['String']['output']>;
|
||||
/** Start array */
|
||||
startArray?: Maybe<ArrayType>;
|
||||
@@ -589,7 +613,6 @@ export type Mutation = {
|
||||
startParityCheck?: Maybe<Scalars['JSON']['output']>;
|
||||
/** Stop array */
|
||||
stopArray?: Maybe<ArrayType>;
|
||||
testMutation?: Maybe<Scalars['JSON']['output']>;
|
||||
unmountArrayDisk?: Maybe<Disk>;
|
||||
/** Update an existing API key */
|
||||
updateApikey?: Maybe<ApiKey>;
|
||||
@@ -627,6 +650,11 @@ export type MutationclearArrayDiskStatisticsArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationconnectSignInArgs = {
|
||||
input: ConnectSignInInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationdeleteUserArgs = {
|
||||
input: deleteUserInput;
|
||||
};
|
||||
@@ -659,14 +687,18 @@ export type MutationsendNotificationArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationstartParityCheckArgs = {
|
||||
correct?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
export type MutationsetAdditionalAllowedOriginsArgs = {
|
||||
input: AllowedOriginInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationtestMutationArgs = {
|
||||
id: Scalars['String']['input'];
|
||||
input?: InputMaybe<testMutationInput>;
|
||||
export type MutationsetupRemoteAccessArgs = {
|
||||
input: SetupRemoteAccessInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationstartParityCheckArgs = {
|
||||
correct?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
};
|
||||
|
||||
|
||||
@@ -711,6 +743,8 @@ export type Notification = {
|
||||
|
||||
export type NotificationFilter = {
|
||||
importance?: InputMaybe<Importance>;
|
||||
limit: Scalars['Int']['input'];
|
||||
offset: Scalars['Int']['input'];
|
||||
type?: InputMaybe<NotificationType>;
|
||||
};
|
||||
|
||||
@@ -888,7 +922,6 @@ export type Query = {
|
||||
servers: Array<Server>;
|
||||
/** Network Shares */
|
||||
shares?: Maybe<Array<Maybe<Share>>>;
|
||||
testQuery?: Maybe<Scalars['JSON']['output']>;
|
||||
twoFactor?: Maybe<TwoFactorWithToken>;
|
||||
unassignedDevices?: Maybe<Array<Maybe<UnassignedDevice>>>;
|
||||
/** User account */
|
||||
@@ -930,7 +963,7 @@ export type QuerydockerNetworksArgs = {
|
||||
|
||||
|
||||
export type QuerynotificationsArgs = {
|
||||
filter?: InputMaybe<NotificationFilter>;
|
||||
filter: NotificationFilter;
|
||||
};
|
||||
|
||||
|
||||
@@ -939,12 +972,6 @@ export type QueryserverArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QuerytestQueryArgs = {
|
||||
id: Scalars['String']['input'];
|
||||
input?: InputMaybe<testQueryInput>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryuserArgs = {
|
||||
id: Scalars['ID']['input'];
|
||||
};
|
||||
@@ -1053,6 +1080,12 @@ export type Service = {
|
||||
version?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type SetupRemoteAccessInput = {
|
||||
accessType: WAN_ACCESS_TYPE;
|
||||
forwardType?: InputMaybe<WAN_FORWARD_TYPE>;
|
||||
port?: InputMaybe<Scalars['Port']['input']>;
|
||||
};
|
||||
|
||||
/** Network Share */
|
||||
export type Share = {
|
||||
__typename?: 'Share';
|
||||
@@ -1107,7 +1140,6 @@ export type Subscription = {
|
||||
service?: Maybe<Array<Service>>;
|
||||
share: Share;
|
||||
shares?: Maybe<Array<Share>>;
|
||||
testSubscription: Scalars['String']['output'];
|
||||
twoFactor?: Maybe<TwoFactorWithoutToken>;
|
||||
unassignedDevices?: Maybe<Array<UnassignedDevice>>;
|
||||
user: User;
|
||||
@@ -1505,6 +1537,17 @@ export type Vms = {
|
||||
domain?: Maybe<Array<VmDomain>>;
|
||||
};
|
||||
|
||||
export enum WAN_ACCESS_TYPE {
|
||||
Always = 'ALWAYS',
|
||||
Disabled = 'DISABLED',
|
||||
Dynamic = 'DYNAMIC'
|
||||
}
|
||||
|
||||
export enum WAN_FORWARD_TYPE {
|
||||
Static = 'STATIC',
|
||||
Upnp = 'UPNP'
|
||||
}
|
||||
|
||||
export type Welcome = {
|
||||
__typename?: 'Welcome';
|
||||
message: Scalars['String']['output'];
|
||||
@@ -1568,15 +1611,6 @@ export enum registrationType {
|
||||
Trial = 'TRIAL'
|
||||
}
|
||||
|
||||
export type testMutationInput = {
|
||||
state: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type testQueryInput = {
|
||||
optional?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
state: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type updateApikeyInput = {
|
||||
description?: InputMaybe<Scalars['String']['input']>;
|
||||
expiresAt: Scalars['Long']['input'];
|
||||
@@ -1586,10 +1620,24 @@ export type usersInput = {
|
||||
slim?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
};
|
||||
|
||||
export type ConnectSignInMutationVariables = Exact<{
|
||||
input: ConnectSignInInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type ConnectSignInMutation = { __typename?: 'Mutation', connectSignIn: boolean };
|
||||
|
||||
export type SignOutMutationVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type SignOutMutation = { __typename?: 'Mutation', connectSignOut: boolean };
|
||||
|
||||
export type serverStateQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type serverStateQuery = { __typename?: 'Query', cloud?: { __typename?: 'Cloud', error?: string | null, apiKey: { __typename?: 'ApiKeyResponse', valid: boolean, error?: string | null }, cloud: { __typename?: 'CloudResponse', status: string, error?: string | null }, minigraphql: { __typename?: 'MinigraphqlResponse', status: MinigraphStatus, error?: string | null }, relay?: { __typename?: 'RelayResponse', status: string, error?: string | null } | null } | null, config: { __typename?: 'Config', error?: ConfigErrorState | null, valid?: boolean | null }, info?: { __typename?: 'Info', os?: { __typename?: 'Os', hostname?: string | null } | null } | null, owner?: { __typename?: 'Owner', avatar?: string | null, username?: string | null } | null, registration?: { __typename?: 'Registration', state?: RegistrationState | null, expiration?: string | null, keyFile?: { __typename?: 'KeyFile', contents?: string | null } | null } | null, vars?: { __typename?: 'Vars', regGen?: string | null, regState?: RegistrationState | null, configError?: ConfigErrorState | null, configValid?: boolean | null } | null };
|
||||
|
||||
|
||||
export const ConnectSignInDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ConnectSignIn"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConnectSignInInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"connectSignIn"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<ConnectSignInMutation, ConnectSignInMutationVariables>;
|
||||
export const SignOutDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SignOut"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"connectSignOut"}}]}}]} as unknown as DocumentNode<SignOutMutation, SignOutMutationVariables>;
|
||||
export const serverStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"serverState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"valid"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"minigraphql"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"relay"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"valid"}}]}},{"kind":"Field","name":{"kind":"Name","value":"info"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"os"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hostname"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"owner"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"registration"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"expiration"}},{"kind":"Field","name":{"kind":"Name","value":"keyFile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"contents"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"vars"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"regGen"}},{"kind":"Field","name":{"kind":"Name","value":"regState"}},{"kind":"Field","name":{"kind":"Name","value":"configError"}},{"kind":"Field","name":{"kind":"Name","value":"configValid"}}]}}]}}]} as unknown as DocumentNode<serverStateQuery, serverStateQueryVariables>;
|
||||
13
web/store/account.fragment.ts
Normal file
13
web/store/account.fragment.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { graphql } from '~/composables/gql/gql';
|
||||
|
||||
export const CONNECT_SIGN_IN = graphql(/* GraphQL */`
|
||||
mutation ConnectSignIn($input: ConnectSignInInput!) {
|
||||
connectSignIn(input: $input)
|
||||
}
|
||||
`);
|
||||
|
||||
export const CONNECT_SIGN_OUT = graphql(/* GraphQL */`
|
||||
mutation SignOut {
|
||||
connectSignOut
|
||||
}
|
||||
`);
|
||||
@@ -1,8 +1,12 @@
|
||||
import { useMutation } from '@vue/apollo-composable';
|
||||
import { logErrorMessages } from '@vue/apollo-util';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
import { CONNECT_SIGN_IN, CONNECT_SIGN_OUT } from './account.fragment';
|
||||
import { useCallbackStore } from '~/store/callbackActions';
|
||||
import { useErrorsStore } from '~/store/errors';
|
||||
import { useServerStore } from '~/store/server';
|
||||
import { useUnraidApiStore } from '~/store/unraidApi';
|
||||
import { WebguiUpdate } from '~/composables/services/webgui';
|
||||
import { ACCOUNT_CALLBACK } from '~/helpers/urls';
|
||||
import type { ExternalSignIn, ExternalSignOut } from '~/store/callback';
|
||||
@@ -12,16 +16,50 @@ import type { ExternalSignIn, ExternalSignOut } from '~/store/callback';
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
|
||||
export interface ConnectSignInMutationPayload {
|
||||
apiKey: string;
|
||||
email: string;
|
||||
preferred_username: string;
|
||||
}
|
||||
|
||||
export const useAccountStore = defineStore('account', () => {
|
||||
const callbackStore = useCallbackStore();
|
||||
const errorsStore = useErrorsStore();
|
||||
const serverStore = useServerStore();
|
||||
const unraidApiStore = useUnraidApiStore();
|
||||
|
||||
// State
|
||||
const accountAction = ref<ExternalSignIn|ExternalSignOut>();
|
||||
const accountAction = ref<ExternalSignIn | ExternalSignOut>();
|
||||
const accountActionHide = ref<boolean>(false);
|
||||
const accountActionStatus = ref<'failed' | 'ready' | 'success' | 'updating'>('ready');
|
||||
|
||||
/**
|
||||
* Handling sign in / out via graph api
|
||||
*/
|
||||
const unraidApiClient = computed(() => unraidApiStore.unraidApiClient);
|
||||
const connectSignInPayload = ref<ConnectSignInMutationPayload | undefined>();
|
||||
const setConnectSignInPayload = (payload: ConnectSignInMutationPayload | undefined) => {
|
||||
connectSignInPayload.value = payload;
|
||||
};
|
||||
const queueConnectSignOut = ref<boolean>(false);
|
||||
const setQueueConnectSignOut = (data: boolean) => {
|
||||
queueConnectSignOut.value = data;
|
||||
};
|
||||
watchEffect(() => {
|
||||
if (unraidApiClient.value && connectSignInPayload.value) {
|
||||
// connectSignInMutation();
|
||||
setTimeout(() => {
|
||||
connectSignInMutation();
|
||||
}, 250);
|
||||
}
|
||||
if (unraidApiClient.value && queueConnectSignOut.value) {
|
||||
// connectSignOutMutation();
|
||||
setTimeout(() => {
|
||||
connectSignOutMutation();
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
|
||||
const username = ref<string>('');
|
||||
|
||||
// Getters
|
||||
@@ -100,75 +138,94 @@ export const useAccountStore = defineStore('account', () => {
|
||||
serverStore.inIframe,
|
||||
);
|
||||
};
|
||||
/**
|
||||
* @description Update myservers.cfg for both Sign In & Sign Out
|
||||
* @note unraid-api requires apikey & token realted keys to be lowercase
|
||||
*/
|
||||
const updatePluginConfig = async (action: ExternalSignIn | ExternalSignOut) => {
|
||||
// save any existing username before updating
|
||||
if (serverStore.username) { username.value = serverStore.username; }
|
||||
|
||||
accountAction.value = action;
|
||||
const connectSignInMutation = async () => {
|
||||
if (!connectSignInPayload.value
|
||||
|| (connectSignInPayload.value && (!connectSignInPayload.value.apiKey || !connectSignInPayload.value.email || !connectSignInPayload.value.preferred_username))
|
||||
) {
|
||||
accountActionStatus.value = 'failed';
|
||||
return;
|
||||
}
|
||||
|
||||
accountActionStatus.value = 'updating';
|
||||
const { mutate: signInMutation, onDone, onError } = useMutation(CONNECT_SIGN_IN, {
|
||||
variables: {
|
||||
input: {
|
||||
apiKey: connectSignInPayload.value.apiKey,
|
||||
userInfo: {
|
||||
email: connectSignInPayload.value.email,
|
||||
preferred_username: connectSignInPayload.value.preferred_username,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!serverStore.registered && !accountAction.value.user) {
|
||||
signInMutation();
|
||||
|
||||
onDone((res) => {
|
||||
if (res.data?.connectSignIn) {
|
||||
accountActionStatus.value = 'success';
|
||||
setConnectSignInPayload(undefined); // reset
|
||||
return;
|
||||
}
|
||||
accountActionStatus.value = 'failed';
|
||||
errorsStore.setError({
|
||||
heading: 'unraid-api failed to update Connect account configuration',
|
||||
message: 'Sign In mutation unsuccessful',
|
||||
level: 'error',
|
||||
ref: 'connectSignInMutation',
|
||||
type: 'account',
|
||||
});
|
||||
});
|
||||
|
||||
onError(error => {
|
||||
logErrorMessages(error);
|
||||
accountActionStatus.value = 'failed';
|
||||
errorsStore.setError({
|
||||
heading: 'unraid-api failed to update Connect account configuration',
|
||||
message: error.message,
|
||||
level: 'error',
|
||||
ref: 'connectSignInMutation',
|
||||
type: 'account',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const connectSignOutMutation = async () => {
|
||||
accountActionStatus.value = 'updating';
|
||||
// @todo is this still needed here with the change to a mutation?
|
||||
if (!serverStore.registered && accountAction.value && !accountAction.value.user) {
|
||||
accountActionHide.value = true;
|
||||
accountActionStatus.value = 'success';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userPayload = {
|
||||
...(accountAction.value.user
|
||||
? {
|
||||
apikey: accountAction.value.apiKey,
|
||||
// avatar: '',
|
||||
email: accountAction.value.user?.email,
|
||||
regWizTime: `${Date.now()}_${serverStore.guid}`, // set when signing in the first time and never unset for the sake of displaying Sign In/Up in the UPC without needing to validate guid every time
|
||||
username: accountAction.value.user?.preferred_username,
|
||||
}
|
||||
: {
|
||||
accesstoken: '',
|
||||
apikey: '',
|
||||
avatar: '',
|
||||
email: '',
|
||||
idtoken: '',
|
||||
refreshtoken: '',
|
||||
username: '',
|
||||
}),
|
||||
};
|
||||
const response = await WebguiUpdate
|
||||
.formUrl({
|
||||
csrf_token: serverStore.csrf,
|
||||
'#file': 'dynamix.my.servers/myservers.cfg',
|
||||
'#section': 'remote',
|
||||
...userPayload,
|
||||
})
|
||||
.post()
|
||||
.res((res) => {
|
||||
accountActionStatus.value = 'success';
|
||||
})
|
||||
.catch((err) => {
|
||||
accountActionStatus.value = 'failed';
|
||||
errorsStore.setError({
|
||||
heading: 'Failed to update Connect account configuration',
|
||||
message: err.message,
|
||||
level: 'error',
|
||||
ref: 'updatePluginConfig',
|
||||
type: 'account',
|
||||
});
|
||||
});
|
||||
return response;
|
||||
} catch (err) {
|
||||
const { mutate: signOutMutation, onDone, onError } = useMutation(CONNECT_SIGN_OUT);
|
||||
|
||||
signOutMutation();
|
||||
|
||||
onDone((res) => {
|
||||
console.debug('[connectSignOutMutation]', res);
|
||||
accountActionStatus.value = 'success';
|
||||
setQueueConnectSignOut(false); // reset
|
||||
});
|
||||
|
||||
onError(error => {
|
||||
logErrorMessages(error);
|
||||
accountActionStatus.value = 'failed';
|
||||
errorsStore.setError({
|
||||
heading: 'Failed to update Connect account configuration',
|
||||
message: err.message,
|
||||
message: error.message,
|
||||
level: 'error',
|
||||
ref: 'updatePluginConfig',
|
||||
ref: 'connectSignOutMutation',
|
||||
type: 'account',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const setAccountAction = (action: ExternalSignIn|ExternalSignOut) => {
|
||||
console.debug('[setAccountAction]', { action });
|
||||
accountAction.value = action;
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -185,6 +242,8 @@ export const useAccountStore = defineStore('account', () => {
|
||||
signOut,
|
||||
trialExtend,
|
||||
trialStart,
|
||||
updatePluginConfig,
|
||||
setAccountAction,
|
||||
setConnectSignInPayload,
|
||||
setQueueConnectSignOut,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -45,28 +45,46 @@ export const useCallbackActionsStore = defineStore('callbackActions', () => {
|
||||
if (action?.keyUrl) {
|
||||
await installKeyStore.install(action as ExternalKeyActions);
|
||||
}
|
||||
if (action?.user || action.type === 'signOut' || action.type === 'oemSignOut') {
|
||||
await accountStore.updatePluginConfig(action);
|
||||
if (action?.user || action.type === 'signIn') {
|
||||
accountStore.setAccountAction(action);
|
||||
accountStore.setConnectSignInPayload({
|
||||
apiKey: action.apiKey,
|
||||
email: action.user.email,
|
||||
preferred_username: action.user.preferred_username,
|
||||
});
|
||||
}
|
||||
if (action.type === 'signOut' || action.type === 'oemSignOut') {
|
||||
accountStore.setAccountAction(action);
|
||||
accountStore.setQueueConnectSignOut(true);
|
||||
}
|
||||
// all actions have run
|
||||
if (array.length === (index + 1)) {
|
||||
await serverStore.refreshServerState();
|
||||
// callbackStatus.value = 'done';
|
||||
if (array.length > 1) {
|
||||
// if we have more than 1 action it means there was a key install and an account action so both need to be successful
|
||||
const allSuccess = accountStore.accountActionStatus === 'success' && installKeyStore.keyInstallStatus === 'success';
|
||||
callbackStatus.value = allSuccess ? 'success' : 'error';
|
||||
} else {
|
||||
// only 1 action needs to be successful
|
||||
const oneSuccess = accountStore.accountActionStatus === 'success' || installKeyStore.keyInstallStatus === 'success';
|
||||
callbackStatus.value = oneSuccess ? 'success' : 'error';
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// Wait until we have a refreshServerStateStatus value to determine callbackStatus
|
||||
const refreshServerStateStatus = computed(() => serverStore.refreshServerStateStatus);
|
||||
watchEffect(() => {
|
||||
if (callbackData.value?.actions && refreshServerStateStatus.value === 'done') {
|
||||
if (callbackData.value.actions.length > 1) {
|
||||
// if we have more than 1 action it means there was a key install and an account action so both need to be successful
|
||||
const allSuccess = accountStore.accountActionStatus === 'success' && installKeyStore.keyInstallStatus === 'success';
|
||||
callbackStatus.value = allSuccess ? 'success' : 'error';
|
||||
} else {
|
||||
// only 1 action needs to be successful
|
||||
const oneSuccess = accountStore.accountActionStatus === 'success' || installKeyStore.keyInstallStatus === 'success';
|
||||
callbackStatus.value = oneSuccess ? 'success' : 'error';
|
||||
}
|
||||
}
|
||||
/** @todo ensure timeout messaging is correct */
|
||||
if (callbackData.value?.actions && refreshServerStateStatus.value === 'timeout') {
|
||||
callbackStatus.value = 'error';
|
||||
}
|
||||
});
|
||||
|
||||
const setCallbackStatus = (status: CallbackStatus) => { callbackStatus.value = status; };
|
||||
|
||||
watch(callbackStatus, (newVal, oldVal) => {
|
||||
if (newVal === 'loading') {
|
||||
addPreventClose();
|
||||
|
||||
@@ -50,7 +50,15 @@ export const useServerStore = defineStore('server', () => {
|
||||
/**
|
||||
* State
|
||||
*/
|
||||
const apiKey = ref<string>(''); // @todo potentially move to a user store
|
||||
const apiKey = ref<string>('');
|
||||
watch(apiKey, (newVal, oldVal) => {
|
||||
if (newVal) {
|
||||
return unraidApiStore.createApolloClient();
|
||||
}
|
||||
if (oldVal) {
|
||||
return unraidApiStore.closeUnraidApiClient();
|
||||
}
|
||||
});
|
||||
const apiVersion = ref<string>('');
|
||||
const avatar = ref<string>(''); // @todo potentially move to a user store
|
||||
const cloud = ref<ServerStateCloudStatus>();
|
||||
@@ -536,38 +544,6 @@ export const useServerStore = defineStore('server', () => {
|
||||
});
|
||||
const trialExtensionEligible = computed(() => !regGen.value || regGen.value < 2);
|
||||
|
||||
const invalidApiKey = computed((): Error | undefined => {
|
||||
// must be registered with plugin installed
|
||||
if (!connectPluginInstalled.value || !registered.value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Keeping separate from validApiKeyLength because we may want to add more checks. Cloud also help with debugging user error submissions.
|
||||
if (apiKey.value.length !== 64) {
|
||||
return {
|
||||
heading: 'Invalid API Key',
|
||||
level: 'error',
|
||||
message: 'Please sign out then sign back in to refresh your API key.',
|
||||
ref: 'invalidApiKeyLength',
|
||||
type: 'server',
|
||||
};
|
||||
}
|
||||
if (!apiKey.value.startsWith('unupc_')) {
|
||||
return {
|
||||
heading: 'Invalid API Key Format',
|
||||
level: 'error',
|
||||
message: 'Please sign out then sign back in to refresh your API key.',
|
||||
ref: 'invalidApiKeyFormat',
|
||||
type: 'server',
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
watch(invalidApiKey, (newVal, oldVal) => {
|
||||
if (oldVal && oldVal.ref) { errorsStore.removeErrorByRef(oldVal.ref); }
|
||||
if (newVal) { errorsStore.setError(newVal); }
|
||||
});
|
||||
|
||||
const tooManyDevices = computed((): Error | undefined => {
|
||||
if (!config.value?.valid && config.value?.error === 'INVALID') {
|
||||
return {
|
||||
@@ -643,7 +619,8 @@ export const useServerStore = defineStore('server', () => {
|
||||
});
|
||||
|
||||
const cloudError = computed((): Error | undefined => {
|
||||
if (!cloud.value?.error) { return undefined; }
|
||||
// if we're not registered then the cloud error should be ignored
|
||||
if (!registered.value || !cloud.value?.error) { return; }
|
||||
return {
|
||||
actions: [
|
||||
{
|
||||
@@ -660,7 +637,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
debugServer: serverDebugPayload.value,
|
||||
heading: 'Unraid Connect Error',
|
||||
level: 'error',
|
||||
message: cloud.value.error,
|
||||
message: cloud.value?.error ?? '',
|
||||
ref: 'cloudError',
|
||||
type: 'unraidApiState',
|
||||
};
|
||||
@@ -676,29 +653,9 @@ export const useServerStore = defineStore('server', () => {
|
||||
tooManyDevices.value,
|
||||
pluginInstallFailed.value,
|
||||
deprecatedUnraidSSL.value,
|
||||
invalidApiKey.value,
|
||||
cloudError.value,
|
||||
].filter(Boolean);
|
||||
});
|
||||
/**
|
||||
* Determines whether or not we start or stop the apollo client for unraid-api
|
||||
*/
|
||||
const registeredWithValidApiKey = computed(() => registered.value && !invalidApiKey.value);
|
||||
watch(registeredWithValidApiKey, (newVal, oldVal) => {
|
||||
if (oldVal) {
|
||||
return unraidApiStore.closeUnraidApiClient();
|
||||
}
|
||||
if (newVal) {
|
||||
// if this is just after sign in, let's delay the start by a few seconds to give unraid-api time to update
|
||||
if (accountStore.accountActionType === 'signIn') {
|
||||
return setTimeout(() => {
|
||||
unraidApiStore.createApolloClient();
|
||||
}, 2000);
|
||||
} else {
|
||||
return unraidApiStore.createApolloClient();
|
||||
}
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
@@ -814,7 +771,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
}, refreshTimeout);
|
||||
}
|
||||
// Extract the new values from the response
|
||||
const newRegistered = fromApi && response?.data ? !!response.data.owner.username : response.registered;
|
||||
const newRegistered = fromApi && response?.data ? response.data.owner.username !== 'root' : response.registered;
|
||||
const newState = fromApi && response?.data ? response.data.vars.regState : response.state;
|
||||
// Compare the new values to the old values
|
||||
const registrationStatusChanged = oldRegistered !== newRegistered;
|
||||
@@ -858,12 +815,10 @@ export const useServerStore = defineStore('server', () => {
|
||||
// getters
|
||||
authAction,
|
||||
deprecatedUnraidSSL,
|
||||
invalidApiKey,
|
||||
isRemoteAccess,
|
||||
keyActions,
|
||||
pluginInstallFailed,
|
||||
pluginOutdated,
|
||||
registeredWithValidApiKey,
|
||||
server,
|
||||
serverAccountPayload,
|
||||
serverPurchasePayload,
|
||||
|
||||
@@ -64,11 +64,6 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
* Automatically called when an apiKey is set in the serverStore
|
||||
*/
|
||||
const createApolloClient = () => {
|
||||
// sign out imminent, skipping createApolloClient
|
||||
if (accountStore.accountActionType === 'signOut') {
|
||||
return;
|
||||
}
|
||||
|
||||
unraidApiStatus.value = 'connecting';
|
||||
|
||||
const headers = { 'x-api-key': serverStore.apiKey };
|
||||
|
||||
Reference in New Issue
Block a user