diff --git a/src/components/shared/ProfileInfo.tsx b/src/components/shared/ProfileInfo.tsx index c6c8617..0e84a25 100644 --- a/src/components/shared/ProfileInfo.tsx +++ b/src/components/shared/ProfileInfo.tsx @@ -44,7 +44,7 @@ export default function ProfileInfo() { )} -
+

Made with ♥ by{" "} ) => { try { - await db.execute(sql`SELECT 1`); // Execute a simple query + const missingKeys = findMissingKeys(ENV, ['DB_USERNAME', 'DB_PASSWORD', 'DB_HOST', 'DB_PORT', 'DB_DATABASE_NAME']); + if (!ENV.DATABASE_URL && missingKeys.length > 0) { + throw new APIError({ + message: `Some database credentials are missing: ${missingKeys.join(', ')}. Please add them to the .env file`, + status: 500, + }); + } else { + return await db.execute(sql`SELECT 1`); // Execute a simple query + } } catch (error: any) { throw new DatabaseConnectionError(error.message, "Database connection failed"); } diff --git a/src/handlers/serverUtils/user.utils.ts b/src/handlers/serverUtils/user.utils.ts index faf90db..6756e1a 100644 --- a/src/handlers/serverUtils/user.utils.ts +++ b/src/handlers/serverUtils/user.utils.ts @@ -1,6 +1,7 @@ import { appConfig } from "@/config/app.config" import { connectDB, db } from "@/config/db" import { ENV } from "@/config/environment" +import { APIError } from "@/lib/api" import { getCookie } from "@/lib/cookie" import { NextApiRequest } from "next" @@ -22,7 +23,19 @@ export const getCurrentUserFromAPIKey = () => { } }) } - return null + throw new APIError({ + message: "Invalid API key. Please check your API key variable `IMMICH_API_KEY` in the .env file", + status: 403, + }); + }) + .catch((error) => { + if (error instanceof APIError) { + throw error; + } + throw new APIError({ + message: "Failed to connect to Immich API: " + ENV.IMMICH_URL, + status: 500, + }); }) } @@ -37,6 +50,11 @@ export const getCurrentUserFromAccessToken = (token: string) => { return res.json() } return null + }).catch((error) => { + throw new APIError({ + message: "Failed to connect to Immich API: " + ENV.IMMICH_URL, + status: 500, + }); }) } diff --git a/src/helpers/data.helper.ts b/src/helpers/data.helper.ts index 939493a..b68bf17 100644 --- a/src/helpers/data.helper.ts +++ b/src/helpers/data.helper.ts @@ -17,4 +17,9 @@ export const removeNullOrUndefinedProperties = (obj: any) => { return v !== null && v !== undefined && v !== '' && v !== 'null' && v !== 'undefined' && v !== 'null' && v !== 'undefined' })); +} + +export const findMissingKeys = (obj: any, keys: string[]) => { + + return keys.filter((key) => !(key in obj) || obj[key] === '' || obj[key] === null || obj[key] === undefined); } \ No newline at end of file diff --git a/src/lib/api.ts b/src/lib/api.ts index abc56cd..eee6dd2 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -2,6 +2,21 @@ import type { AxiosError, AxiosRequestConfig, Method } from 'axios' import axios from 'axios' import qs from 'qs' +export class APIError extends Error { + status: number; + constructor({ + message, + status, + }: { + message: string; + status: number; + }) { + super(message); + this.name = 'APIError'; + this.message = message; + this.status = status; + } +} const handleErrors = (error: AxiosError | any) => { @@ -26,8 +41,6 @@ const handleErrors = (error: AxiosError | any) => { } export default class API { - - static setBaseURL(url: string) { if (url) { axios.defaults.baseURL = url diff --git a/src/pages/analytics/exif.tsx b/src/pages/analytics/exif.tsx index 59244ef..23da1c4 100644 --- a/src/pages/analytics/exif.tsx +++ b/src/pages/analytics/exif.tsx @@ -106,40 +106,42 @@ export default function ExifDataAnalytics() { }, []); return ( - +

-
- {["Total", "Images", "Videos"].map((type, i) => ( - +
+
+ {["Total", "Images", "Videos"].map((type, i) => ( + + + {type} + + + {loading ? "Loading..." : statistics[type.toLowerCase() as keyof typeof statistics].toLocaleString()} + + + ))} + - {type} + Live Photos - {loading ? "Loading..." : statistics[type.toLowerCase() as keyof typeof statistics].toLocaleString()} + {loading ? "Loading..." : livePhotoStatistics.total.toLocaleString()} - ))} - - - Live Photos - - - {loading ? "Loading..." : livePhotoStatistics.total.toLocaleString()} - - -
- -
- {exifCharts.map((chart) => ( - - ))} +
+ +
+ {exifCharts.map((chart) => ( + + ))} +
); diff --git a/src/pages/api/share-link/[token]/index.ts b/src/pages/api/share-link/[token]/index.ts index fca170d..d2a1d11 100644 --- a/src/pages/api/share-link/[token]/index.ts +++ b/src/pages/api/share-link/[token]/index.ts @@ -13,11 +13,15 @@ export default async function GET(req: NextApiRequest, res: NextApiResponse) { return res.status(404).json({ message: "Token not found" }); } + if (!ENV.IMMICH_SHARE_LINK_KEY) { + return res.status(401).json({ message: "Please check your link and try again. If you're the admin, check if you've enabled all the configurations in the Immich Power Tools in your environment variables" }); + } + const decoded = verify(token as string, ENV.JWT_SECRET); - console.log(decoded); + if (!decoded) { - return res.status(401).json({ message: "Unauthorized" }); + return res.status(401).json({ message: "Link is invalid. Please check your link and try again" }); } diff --git a/src/pages/api/share-link/generate.ts b/src/pages/api/share-link/generate.ts index b76b93c..139f7e9 100644 --- a/src/pages/api/share-link/generate.ts +++ b/src/pages/api/share-link/generate.ts @@ -15,11 +15,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Unauthorized" }); } - if (!ENV.IMMICH_SHARE_LINK_KEY) { - return res.status(401).json({ message: "Unauthorized" }); + if (!ENV.JWT_SECRET) { + return res.status(401).json({ message: "The JWT_SECRET is missing in the .env file. Please add it to the .env file for generating share links" }); } - console.log(expiresIn); + if (!ENV.IMMICH_SHARE_LINK_KEY) { + return res.status(401).json({ message: "The IMMICH_SHARE_LINK_KEY is missing in the .env file. Please add it to the .env file for generating share links" }); + } + + if (!ENV.POWER_TOOLS_ENDPOINT_URL) { + return res.status(401).json({ message: "The POWER_TOOLS_ENDPOINT_URL is missing in the .env file. Please add it to the .env file for generating share links" }); + } const token = sign(filters, ENV.JWT_SECRET, expiresIn !== "never" ? { expiresIn: expiresIn