Refactor web to use OpenAPI SDK (#326)

* Refactor main index page

* Refactor admin page

* Refactor Auth endpoint

* Refactor directory to prep for monorepo

* Fixed refactoring path

* Resolved file path in vite

* Refactor photo index page

* Refactor thumbnail

* Fixed test

* Refactor Video Viewer component

* Refactor download file

* Refactor navigation bar

* Refactor upload file check

* Simplify Upload Asset signature

* PR feedback
This commit is contained in:
Alex
2022-07-10 21:41:45 -05:00
committed by GitHub
parent 7f236c5b18
commit 9a6dfacf9b
55 changed files with 516 additions and 691 deletions

View File

@@ -1,18 +1,15 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
import { checkAppVersion } from '$lib/utils/check-app-version';
import { browser } from '$app/env';
export const load: Load = async ({ url }) => {
if (browser) {
const { shouldShowAnnouncement, localVersion, remoteVersion } = await checkAppVersion();
return { props: { url, shouldShowAnnouncement, localVersion, remoteVersion } };
} else {
return {
props: { url },
};
export const load: Load = async ({ url, session }) => {
if (session.user) {
api.setAccessToken(session.user.accessToken);
}
return {
props: { url },
};
};
</script>
@@ -24,11 +21,21 @@
import DownloadPanel from '$lib/components/asset-viewer/download-panel.svelte';
import AnnouncementBox from '$lib/components/shared/announcement-box.svelte';
import UploadPanel from '$lib/components/shared/upload-panel.svelte';
import { onMount } from 'svelte';
import { api } from '@api';
export let url: string;
export let shouldShowAnnouncement: boolean;
export let localVersion: string;
export let remoteVersion: string;
let shouldShowAnnouncement: boolean;
let localVersion: string;
let remoteVersion: string;
onMount(async () => {
const res = await checkAppVersion();
shouldShowAnnouncement = res.shouldShowAnnouncement;
localVersion = res.localVersion ?? 'unknown';
remoteVersion = res.remoteVersion ?? 'unknown';
});
</script>
<main>

View File

@@ -1,44 +1,34 @@
import type { RequestHandler } from '@sveltejs/kit';
import { serverEndpoint } from '$lib/constants';
import { api } from '@api';
export const post: RequestHandler = async ({ request, locals }) => {
const form = await request.formData();
export const post: RequestHandler = async ({ request }) => {
const form = await request.formData();
const email = form.get('email')
const password = form.get('password')
const firstName = form.get('firstName')
const lastName = form.get('lastName')
const email = form.get('email');
const password = form.get('password');
const firstName = form.get('firstName');
const lastName = form.get('lastName');
const payload = {
email,
password,
firstName,
lastName,
}
const { status } = await api.userApi.createUser({
email: String(email),
password: String(password),
firstName: String(firstName),
lastName: String(lastName),
});
const res = await fetch(`${serverEndpoint}/user`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${locals.user?.accessToken}`
},
body: JSON.stringify(payload),
})
if (res.status === 201) {
return {
status: 201,
body: {
success: 'Succesfully create user account'
}
}
} else {
return {
status: 400,
body: {
error: await res.json()
}
}
}
}
if (status === 201) {
return {
status: 201,
body: {
success: 'Succesfully create user account',
},
};
} else {
return {
status: 400,
body: {
error: 'Error create user account',
},
};
}
};

View File

@@ -1,8 +1,8 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
import { getRequest } from '$lib/api';
import { api, UserResponseDto } from '@api';
export const load: Load = async ({ session, fetch }) => {
export const load: Load = async ({ session }) => {
if (!session.user) {
return {
status: 302,
@@ -10,13 +10,13 @@
};
}
const usersOnServer = await getRequest('user', session.user.accessToken);
const { data } = await api.userApi.getAllUsers(false);
return {
status: 200,
props: {
user: session.user,
usersOnServer,
allUsers: data,
},
};
};
@@ -24,7 +24,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { session } from '$app/stores';
import type { ImmichUser } from '$lib/models/immich-user';
import { AdminSideBarSelection } from '$lib/models/admin-sidebar-selection';
@@ -34,12 +33,12 @@
import UserManagement from '$lib/components/admin/user-management.svelte';
import FullScreenModal from '$lib/components/shared/full-screen-modal.svelte';
import CreateUserForm from '$lib/components/forms/create-user-form.svelte';
import StatusBox from '../../lib/components/shared/status-box.svelte';
import StatusBox from '$lib/components/shared/status-box.svelte';
let selectedAction: AdminSideBarSelection;
export let user: ImmichUser;
export let usersOnServer: Array<ImmichUser>;
export let allUsers: UserResponseDto[];
let shouldShowCreateUserForm: boolean;
@@ -52,9 +51,8 @@
});
const onUserCreated = async () => {
if ($session.user) {
usersOnServer = await getRequest('user', $session.user.accessToken);
}
const { data } = await api.userApi.getAllUsers(false);
allUsers = data;
shouldShowCreateUserForm = false;
};
@@ -97,7 +95,7 @@
<section id="setting-content" class="relative pt-[85px] flex place-content-center">
<section class="w-[800px] pt-4">
{#if selectedAction === AdminSideBarSelection.USER_MANAGEMENT}
<UserManagement {usersOnServer} on:createUser={() => (shouldShowCreateUserForm = true)} />
<UserManagement {allUsers} on:createUser={() => (shouldShowCreateUserForm = true)} />
{/if}
</section>
</section>

View File

@@ -2,7 +2,6 @@
export const prerender = false;
import type { Load } from '@sveltejs/kit';
import type { ImmichUser } from '$lib/models/immich-user';
export const load: Load = async ({ session }) => {
if (!session.user) {
@@ -13,14 +12,7 @@
}
try {
const res = await fetch(serverEndpoint + '/user/me', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + session.user.accessToken,
},
});
const userInfo: ImmichUser = await res.json();
const { data: userInfo } = await api.userApi.getMyUserInfo();
if (userInfo.shouldChangePassword) {
return {
@@ -47,15 +39,15 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { session } from '$app/stores';
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
import ChangePasswordForm from '../../../lib/components/forms/change-password-form.svelte';
import { serverEndpoint } from '../../../lib/constants';
export let user: ImmichUser;
import ChangePasswordForm from '$lib/components/forms/change-password-form.svelte';
import { api, UserResponseDto } from '@api';
export let user: UserResponseDto;
const onSuccessHandler = async () => {
/** Svelte route fetch */
const res = await fetch('/auth/logout', { method: 'POST' });
if (res.status == 200 && res.statusText == 'OK') {

View File

@@ -1,27 +1,26 @@
import type { RequestHandler } from '@sveltejs/kit';
import { serverEndpoint } from '$lib/constants';
import { api } from '@api';
export const post: RequestHandler = async ({ request, locals }) => {
const form = await request.formData();
if (!locals.user) {
return {
status: 401,
body: {
error: 'Unauthorized',
},
};
}
const form = await request.formData();
const password = form.get('password');
const payload = {
id: locals.user?.id,
password,
const { status } = await api.userApi.updateUser({
id: locals.user.id,
password: String(password),
shouldChangePassword: false,
};
const res = await fetch(`${serverEndpoint}/user`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${locals.user?.accessToken}`,
},
body: JSON.stringify(payload),
});
if (res.status === 200) {
if (status === 200) {
return {
status: 200,
body: {
@@ -32,7 +31,7 @@ export const post: RequestHandler = async ({ request, locals }) => {
return {
status: 400,
body: {
error: await res.json(),
error: 'Error change password',
},
};
}

View File

@@ -1,11 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit';
import { getRequest } from '../../../../lib/api';
export const get: RequestHandler = async ({ request, locals }) => {
const allUsers = await getRequest('user?isAll=true', locals.user!.accessToken);
return {
status: 200,
body: { allUsers },
};
};

View File

@@ -1,52 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit';
import { putRequest } from '$lib/api';
import * as cookie from 'cookie';
export const post: RequestHandler = async ({ request, locals }) => {
const { id, isAdmin } = await request.json()
const res = await putRequest('user', {
id,
isAdmin,
}, locals.user!.accessToken);
if (res.statusCode) {
return {
status: res.statusCode,
body: JSON.stringify(res)
}
}
if (res.id == locals.user!.id) {
return {
status: 200,
body: { userInfo: res },
headers: {
'Set-Cookie': cookie.serialize('session', JSON.stringify(
{
id: res.id,
accessToken: locals.user!.accessToken,
firstName: res.firstName,
lastName: res.lastName,
isAdmin: res.isAdmin,
email: res.email,
}), {
path: '/',
httpOnly: true,
sameSite: 'strict',
maxAge: 60 * 60 * 24 * 30,
})
}
}
} else {
return {
status: 200,
body: { userInfo: { ...locals.user! } },
}
}
}

View File

@@ -1,17 +1,6 @@
import type { RequestHandler } from '@sveltejs/kit';
import { serverEndpoint } from '$lib/constants';
import * as cookie from 'cookie';
import { getRequest, putRequest } from '$lib/api';
type AuthUser = {
accessToken: string;
userId: string;
userEmail: string;
firstName: string;
lastName: string;
isAdmin: boolean;
shouldChangePassword: boolean;
};
import { api } from '@api';
export const post: RequestHandler = async ({ request }) => {
const form = await request.formData();
@@ -19,22 +8,11 @@ export const post: RequestHandler = async ({ request }) => {
const email = form.get('email');
const password = form.get('password');
const payload = {
email,
password,
};
const res = await fetch(`${serverEndpoint}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (res.status === 201) {
// Login success
const authUser = (await res.json()) as AuthUser;
try {
const { data: authUser } = await api.authenticationApi.login({
email: String(email),
password: String(password),
});
return {
status: 200,
@@ -70,7 +48,7 @@ export const post: RequestHandler = async ({ request }) => {
),
},
};
} else {
} catch (error) {
return {
status: 400,
body: {

View File

@@ -1,63 +0,0 @@
import type { RequestHandler } from '@sveltejs/kit';
import { putRequest } from '../../../lib/api';
import * as cookie from 'cookie';
export const post: RequestHandler = async ({ request, locals }) => {
const form = await request.formData();
const firstName = form.get('firstName');
const lastName = form.get('lastName');
if (locals.user) {
const updatedUser = await putRequest(
'user',
{
id: locals.user.id,
firstName,
lastName,
},
locals.user.accessToken,
);
return {
status: 200,
body: {
user: {
id: updatedUser.id,
accessToken: locals.user.accessToken,
firstName: updatedUser.firstName,
lastName: updatedUser.lastName,
isAdmin: updatedUser.isAdmin,
email: updatedUser.email,
},
success: 'Update user success',
},
headers: {
'Set-Cookie': cookie.serialize(
'session',
JSON.stringify({
id: updatedUser.id,
accessToken: locals.user.accessToken,
firstName: updatedUser.firstName,
lastName: updatedUser.lastName,
isAdmin: updatedUser.isAdmin,
email: updatedUser.email,
}),
{
path: '/',
httpOnly: true,
sameSite: 'strict',
maxAge: 60 * 60 * 24 * 30,
},
),
},
};
}
return {
status: 400,
body: {
error: 'Cannot get access token from cookies',
},
};
};

View File

@@ -1,6 +1,6 @@
import type { RequestHandler } from '@sveltejs/kit';
export const post: RequestHandler = async ({ request }) => {
export const post: RequestHandler = async () => {
return {
headers: {
'Set-Cookie': 'session=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT',

View File

@@ -1,14 +1,11 @@
<script context="module" lang="ts">
import type { Load } from '@sveltejs/kit';
import { serverEndpoint } from '$lib/constants';
export const load: Load = async ({ session, fetch }) => {
const res = await fetch(`${serverEndpoint}/user/count`);
const { userCount } = await res.json();
export const load: Load = async ({ session }) => {
const { data } = await api.userApi.getUserCount();
if (userCount != 0) {
if (data.userCount != 0) {
// Admin has been registered, redirect to login
if (!session.user) {
return {
status: 302,
@@ -17,7 +14,7 @@
} else {
return {
status: 302,
redirect: '/dashboard',
redirect: '/photos',
};
}
}
@@ -28,6 +25,7 @@
<script lang="ts">
import AdminRegistrationForm from '$lib/components/forms/admin-registration-form.svelte';
import { api } from '@api';
</script>
<svelte:head>

View File

@@ -1,43 +1,34 @@
import type { RequestHandler } from '@sveltejs/kit';
import { serverEndpoint } from '$lib/constants';
import { api } from '@api';
export const post: RequestHandler = async ({ request }) => {
const form = await request.formData();
const form = await request.formData();
const email = form.get('email')
const password = form.get('password')
const firstName = form.get('firstName')
const lastName = form.get('lastName')
const email = form.get('email');
const password = form.get('password');
const firstName = form.get('firstName');
const lastName = form.get('lastName');
const payload = {
email,
password,
firstName,
lastName,
}
const { status } = await api.authenticationApi.adminSignUp({
email: String(email),
password: String(password),
firstName: String(firstName),
lastName: String(lastName),
});
const res = await fetch(`${serverEndpoint}/auth/admin-sign-up`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload),
})
if (res.status === 201) {
return {
status: 201,
body: {
success: 'Succesfully create admin account'
}
}
} else {
return {
status: 400,
body: {
error: await res.json()
}
}
}
}
if (status === 201) {
return {
status: 201,
body: {
success: 'Succesfully create admin account',
},
};
} else {
return {
status: 400,
body: {
error: 'Error create admin account',
},
};
}
};

View File

@@ -1,39 +1,28 @@
<script context="module" lang="ts">
export const prerender = false;
import type { Load } from '@sveltejs/kit';
import { api } from '@api';
export const load: Load = async ({ session, fetch }) => {
const res = await fetch(`${serverEndpoint}/user/count`);
const { userCount } = await res.json();
export const load: Load = async ({ session }) => {
const { data } = await api.userApi.getUserCount();
if (!session.user) {
// Check if admin exist to wherether navigating to login or registration
if (userCount != 0) {
return {
status: 200,
props: {
isAdminUserExist: true,
},
};
} else {
return {
status: 200,
props: {
isAdminUserExist: false,
},
};
}
} else {
if (session.user) {
return {
status: 302,
redirect: '/photos',
};
}
return {
status: 200,
props: {
isAdminUserExist: data.userCount == 0 ? false : true,
},
};
};
</script>
<script lang="ts">
import { serverEndpoint } from '$lib/constants';
import { goto } from '$app/navigation';
export let isAdminUserExist: boolean;

View File

@@ -12,6 +12,8 @@
};
}
await getAssetsInfo(session.user.accessToken);
return {
status: 200,
props: {
@@ -30,17 +32,16 @@
import ImageOutline from 'svelte-material-icons/ImageOutline.svelte';
import { AppSideBarSelection } from '$lib/models/admin-sidebar-selection';
import { onDestroy, onMount } from 'svelte';
import { onMount } from 'svelte';
import { fly } from 'svelte/transition';
import { session } from '$app/stores';
import { assetsGroupByDate, flattenAssetGroupByDate } from '$lib/stores/assets';
import ImmichThumbnail from '$lib/components/asset-viewer/immich-thumbnail.svelte';
import moment from 'moment';
import type { ImmichAsset } from '$lib/models/immich-asset';
import AssetViewer from '$lib/components/asset-viewer/asset-viewer.svelte';
import StatusBox from '$lib/components/shared/status-box.svelte';
import { fileUploader } from '$lib/utils/file-uploader';
import { openWebsocketConnection, closeWebsocketConnection } from '$lib/stores/websocket';
import { AssetResponseDto } from '@api';
export let user: ImmichUser;
@@ -54,7 +55,7 @@
let isShowAsset = false;
let currentViewAssetIndex = 0;
let currentSelectedAsset: ImmichAsset;
let currentSelectedAsset: AssetResponseDto;
const onButtonClicked = (buttonType: CustomEvent) => {
selectedAction = buttonType.detail['actionType'] as AppSideBarSelection;
@@ -62,16 +63,6 @@
onMount(async () => {
selectedAction = AppSideBarSelection.PHOTOS;
if ($session.user) {
await getAssetsInfo($session.user.accessToken);
openWebsocketConnection($session.user.accessToken);
}
});
onDestroy(() => {
closeWebsocketConnection();
});
const thumbnailMouseEventHandler = (event: CustomEvent) => {