diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts
index 8ab5411..a49e884 100644
--- a/backend/src/auth/auth.controller.ts
+++ b/backend/src/auth/auth.controller.ts
@@ -7,13 +7,15 @@ import {
UnauthorizedException,
} from '@nestjs/common';
import { AuthService } from './auth.service';
-import { SignInDto } from '../user/user.dto';
+import { SignInDto, UserDto } from '../user/user.dto';
import { ApiOkResponse, ApiProperty } from '@nestjs/swagger';
import { ApiException } from '@nanogiants/nestjs-swagger-api-exception-decorator';
export class SignInResponse {
@ApiProperty()
accessToken: string;
+ @ApiProperty()
+ user: UserDto;
}
@Controller('auth')
@@ -24,12 +26,14 @@ export class AuthController {
@ApiOkResponse({ description: 'User found', type: SignInResponse })
@ApiException(() => UnauthorizedException)
async signIn(@Body() signInDto: SignInDto) {
- const { token } = await this.authService.signIn(
+ const { token, user } = await this.authService.signIn(
signInDto.name,
signInDto.password,
);
+
return {
accessToken: token,
+ user: UserDto.fromEntity(user),
};
}
}
diff --git a/backend/src/auth/auth.service.ts b/backend/src/auth/auth.service.ts
index 54a7b75..3e480b4 100644
--- a/backend/src/auth/auth.service.ts
+++ b/backend/src/auth/auth.service.ts
@@ -19,6 +19,7 @@ export class AuthService {
password: string,
): Promise<{
token: string;
+ user: User;
}> {
let user = await this.userService.findOneByName(name);
if (!user && (await this.userService.noPreviousAdmins()))
@@ -34,6 +35,7 @@ export class AuthService {
return {
token: await this.jwtService.signAsync(payload),
+ user,
};
}
}
diff --git a/src/App.svelte b/src/App.svelte
index 239f5ae..8ec786e 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -1,22 +1,23 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/lib/pages/LoginPage.svelte b/src/lib/pages/LoginPage.svelte
index a2782ce..75214c5 100644
--- a/src/lib/pages/LoginPage.svelte
+++ b/src/lib/pages/LoginPage.svelte
@@ -1,11 +1,13 @@
+
+Users Page
diff --git a/src/lib/stores/app-state.store.ts b/src/lib/stores/app-state.store.ts
deleted file mode 100644
index 0a4b09d..0000000
--- a/src/lib/stores/app-state.store.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { derived, get, writable } from 'svelte/store';
-import { createLocalStorageStore } from './localstorage.store';
-import {
- getReiverrApiClient,
- reiverrApi,
- type ReiverrSettings,
- type ReiverrUser
-} from '../apis/reiverr/reiverr-api';
-
-interface AuthenticationStoreData {
- token?: string;
- serverBaseUrl?: string;
-}
-
-interface UserStoreData {
- user: ReiverrUser | null;
-}
-
-export interface AppStateData extends AuthenticationStoreData {
- user: ReiverrUser | null;
-}
-
-const authenticationStore = createLocalStorageStore(
- 'authentication-token',
- {
- token: undefined,
- serverBaseUrl: window?.location?.origin
- }
-);
-
-function createAppState() {
- const userStore = writable(undefined);
-
- const combinedStore = derived<[typeof userStore, typeof authenticationStore], AppStateData>(
- [userStore, authenticationStore],
- ([user, auth]) => {
- return {
- ...user,
- ...auth
- };
- }
- );
-
- function setBaseUrl(serverBaseUrl: string | undefined = undefined) {
- authenticationStore.update((p) => ({ ...p, serverBaseUrl }));
- }
-
- function setToken(token: string | undefined = undefined) {
- authenticationStore.update((p) => ({ ...p, token }));
- }
-
- function setUser(user: ReiverrUser | null) {
- userStore.set({ user });
- }
-
- function logOut() {
- setUser(null);
- setToken(undefined);
- }
-
- const ready = new Promise((resolve) => {
- combinedStore.subscribe((state) => {
- if (state.token && state.serverBaseUrl && state.user !== undefined) {
- resolve(state);
- }
- });
- });
-
- async function updateUser(updateFn: (user: ReiverrUser) => ReiverrUser) {
- const user = get(userStore).user;
-
- if (!user) return;
-
- const updated = updateFn(user);
- const update = await reiverrApi.updateUser(updated);
-
- if (update) {
- setUser(update);
- }
- }
-
- return {
- subscribe: combinedStore.subscribe,
- setBaseUrl,
- setToken,
- setUser,
- updateUser,
- logOut,
- ready
- };
-}
-
-export const appState = createAppState();
-export const appStateUser = derived(appState, ($state) => $state.user);
-
-authenticationStore.subscribe((auth) => {
- if (auth.token) {
- reiverrApi
- .getClient(auth.serverBaseUrl, auth.token)
- ?.GET('/user', {})
- .then((res) => res.data)
- .then((user) => appState.setUser(user || null))
- .catch((err) => appState.setUser(null));
- } else {
- appState.setUser(null);
- }
-});
diff --git a/src/lib/stores/session.store.ts b/src/lib/stores/session.store.ts
new file mode 100644
index 0000000..0671e66
--- /dev/null
+++ b/src/lib/stores/session.store.ts
@@ -0,0 +1,70 @@
+import { createLocalStorageStore } from './localstorage.store';
+import type { operations } from '../apis/reiverr/reiverr.generated';
+import axios from 'axios';
+
+export interface Session {
+ baseUrl: string;
+ token: string;
+}
+
+function useSessions() {
+ const sessions = createLocalStorageStore<{ sessions: Session[]; activeSession?: Session }>(
+ 'sessions',
+ {
+ sessions: []
+ }
+ );
+
+ function setActiveSession(session: Session) {
+ sessions.update((s) => ({ ...s, activeSession: session }));
+ }
+
+ async function addSession(baseUrl: string, name: string, password: string, activate = true) {
+ const res = await axios
+ .post(
+ baseUrl + '/api/auth',
+ {
+ name,
+ password
+ }
+ )
+ .catch((e) => e.response);
+
+ if (res.status !== 200) return res;
+
+ const session = {
+ baseUrl,
+ token: res.data.accessToken
+ };
+
+ sessions.update((s) => {
+ const sessions = s.sessions.concat(session);
+ return {
+ sessions,
+ activeSession: activate ? session : s.activeSession
+ };
+ });
+
+ return res;
+ }
+
+ function removeSession(_session?: Session) {
+ sessions.update((s) => {
+ const session = _session || s.activeSession;
+ const sessions = s.sessions.filter((s) => s !== session);
+ return {
+ sessions,
+ activeSession: s.activeSession === session ? undefined : s.activeSession
+ };
+ });
+ }
+
+ return {
+ subscribe: sessions.subscribe,
+ setActiveSession,
+ addSession,
+ removeSession
+ };
+}
+
+export const sessions = useSessions();
diff --git a/src/lib/stores/user.store.ts b/src/lib/stores/user.store.ts
new file mode 100644
index 0000000..a7cffc3
--- /dev/null
+++ b/src/lib/stores/user.store.ts
@@ -0,0 +1,53 @@
+import { derived, get, writable } from 'svelte/store';
+import { reiverrApi, type ReiverrUser } from '../apis/reiverr/reiverr-api';
+import axios from 'axios';
+import type { operations } from '../apis/reiverr/reiverr.generated';
+import { type Session, sessions } from './session.store';
+
+function useUser() {
+ const activeSession = derived(sessions, (sessions) => sessions.activeSession);
+
+ const userStore = writable(undefined);
+
+ let lastActiveSession: Session | undefined;
+ activeSession.subscribe(async (activeSession) => {
+ if (!activeSession) {
+ userStore.set(null);
+ return;
+ }
+
+ userStore.set(undefined);
+ lastActiveSession = activeSession;
+ const user = await axios
+ .get<
+ operations['UserController_getProfile']['responses']['200']['content']['application/json']
+ >(activeSession.baseUrl + '/api/user', {
+ headers: {
+ Authorization: 'Bearer ' + activeSession.token
+ }
+ })
+ .then((r) => r.data);
+
+ if (lastActiveSession === activeSession) userStore.set(user);
+ });
+
+ async function updateUser(updateFn: (user: ReiverrUser) => ReiverrUser) {
+ const user = get(userStore);
+
+ if (!user) return;
+
+ const updated = updateFn(user);
+ const update = await reiverrApi.updateUser(updated);
+
+ if (update) {
+ userStore.set(update);
+ }
+ }
+
+ return {
+ subscribe: userStore.subscribe,
+ updateUser
+ };
+}
+
+export const user = useUser();