diff options
Diffstat (limited to 'code')
| -rw-r--r-- | code/app/src/lib/api/time-entry.ts | 30 | ||||
| -rw-r--r-- | code/app/src/lib/api/user.ts | 14 | ||||
| -rw-r--r-- | code/app/src/lib/helpers.ts | 24 | ||||
| -rw-r--r-- | code/app/src/lib/logger.ts | 30 | ||||
| -rw-r--r-- | code/app/src/lib/session.ts | 18 | ||||
| -rw-r--r-- | code/app/src/routes/(main)/+layout.server.ts | 10 | ||||
| -rw-r--r-- | code/app/src/routes/(main)/+layout.ts | 4 |
7 files changed, 58 insertions, 72 deletions
diff --git a/code/app/src/lib/api/time-entry.ts b/code/app/src/lib/api/time-entry.ts index a40b0c2..faedb48 100644 --- a/code/app/src/lib/api/time-entry.ts +++ b/code/app/src/lib/api/time-entry.ts @@ -1,16 +1,16 @@ -import {api_base} from "$lib/configuration"; -import {is_guid} from "$lib/helpers"; -import {http_delete, http_get, http_post} from "./internal-fetch"; -import type {TimeCategoryDto} from "$lib/models/TimeCategoryDto"; -import type {TimeLabelDto} from "$lib/models/TimeLabelDto"; -import type {TimeEntryDto} from "$lib/models/TimeEntryDto"; -import type {TimeEntryQuery} from "$lib/models/TimeEntryQuery"; -import type {IInternalFetchResponse} from "$lib/models/IInternalFetchResponse"; +import { api_base } from "$lib/configuration"; +import { is_guid } from "$lib/helpers"; +import { http_delete, http_get, http_post } from "./internal-fetch"; +import type { WorkCategory } from "$lib/models/work/WorkCategory"; +import type { WorkLabel } from "$lib/models/work/WorkLabel"; +import type { WorkEntry } from "$lib/models/work/WorkEntry"; +import type { WorkQuery } from "$lib/models/work/WorkQuery"; +import type { IInternalFetchResponse } from "$lib/models/internal/IInternalFetchResponse"; // ENTRIES -export async function create_time_entry(payload: TimeEntryDto): Promise<IInternalFetchResponse> { +export async function create_time_entry(payload: WorkEntry): Promise<IInternalFetchResponse> { return http_post(api_base("v1/entries/create"), payload); } @@ -21,7 +21,7 @@ export async function get_time_entry(entryId: string): Promise<IInternalFetchRes throw new Error("entryId is not a valid guid."); } -export async function get_time_entries(entryQuery: TimeEntryQuery): Promise<IInternalFetchResponse> { +export async function get_time_entries(entryQuery: WorkQuery): Promise<IInternalFetchResponse> { return http_post(api_base("v1/entries/query"), entryQuery); } @@ -30,7 +30,7 @@ export async function delete_time_entry(id: string): Promise<IInternalFetchRespo return http_delete(api_base("v1/entries/" + id + "/delete")); } -export async function update_time_entry(entryDto: TimeEntryDto): Promise<IInternalFetchResponse> { +export async function update_time_entry(entryDto: WorkEntry): Promise<IInternalFetchResponse> { if (!is_guid(entryDto.id ?? "")) throw new Error("id is not a valid guid"); if (!entryDto.category) throw new Error("category is empty"); if (!entryDto.stop) throw new Error("stop is empty"); @@ -39,7 +39,7 @@ export async function update_time_entry(entryDto: TimeEntryDto): Promise<IIntern } // LABELS -export async function create_time_label(labelDto: TimeLabelDto): Promise<IInternalFetchResponse> { +export async function create_time_label(labelDto: WorkLabel): Promise<IInternalFetchResponse> { return http_post(api_base("v1/labels/create"), labelDto); } @@ -52,7 +52,7 @@ export async function delete_time_label(id: string): Promise<IInternalFetchRespo return http_delete(api_base("v1/labels/" + id + "/delete")); } -export async function update_time_label(labelDto: TimeLabelDto): Promise<IInternalFetchResponse> { +export async function update_time_label(labelDto: WorkLabel): Promise<IInternalFetchResponse> { if (!is_guid(labelDto.id ?? "")) throw new Error("id is not a valid guid"); if (!labelDto.name) throw new Error("name is empty"); if (!labelDto.color) throw new Error("color is empty"); @@ -60,7 +60,7 @@ export async function update_time_label(labelDto: TimeLabelDto): Promise<IIntern } // CATEGORIES -export async function create_time_category(category: TimeCategoryDto): Promise<IInternalFetchResponse> { +export async function create_time_category(category: WorkCategory): Promise<IInternalFetchResponse> { if (!category.name) throw new Error("name is empty"); if (!category.color) throw new Error("color is empty"); return http_post(api_base("v1/categories/create"), category); @@ -75,7 +75,7 @@ export async function delete_time_category(id: string): Promise<IInternalFetchRe return http_delete(api_base("v1/categories/" + id + "/delete")); } -export async function update_time_category(category: TimeCategoryDto): Promise<IInternalFetchResponse> { +export async function update_time_category(category: WorkCategory): Promise<IInternalFetchResponse> { if (!is_guid(category.id ?? "")) throw new Error("id is not a valid guid"); if (!category.name) throw new Error("name is empty"); if (!category.color) throw new Error("color is empty"); diff --git a/code/app/src/lib/api/user.ts b/code/app/src/lib/api/user.ts index f0dc932..f08fb6d 100644 --- a/code/app/src/lib/api/user.ts +++ b/code/app/src/lib/api/user.ts @@ -1,9 +1,9 @@ -import {api_base} from "$lib/configuration"; -import {http_delete, http_get, http_post} from "./internal-fetch"; -import type {LoginPayload} from "$lib/models/LoginPayload"; -import type {UpdateProfilePayload} from "$lib/models/UpdateProfilePayload"; -import type {CreateAccountPayload} from "$lib/models/CreateAccountPayload"; -import type {IInternalFetchResponse} from "$lib/models/IInternalFetchResponse"; +import { api_base } from "$lib/configuration"; +import { http_delete, http_get, http_post } from "./internal-fetch"; +import type { LoginPayload } from "$lib/models/internal/LoginPayload"; +import type { UpdateProfilePayload } from "$lib/models/internal/UpdateProfilePayload"; +import type { CreateAccountPayload } from "$lib/models/internal/CreateAccountPayload"; +import type { IInternalFetchResponse } from "$lib/models/internal/IInternalFetchResponse"; export async function login(payload: LoginPayload): Promise<IInternalFetchResponse> { return http_post(api_base("_/account/login"), payload); @@ -25,7 +25,7 @@ export async function check_forgot_password_request(public_id: string): Promise< export async function fulfill_forgot_password_request(public_id: string, newPassword: string): Promise<IInternalFetchResponse> { if (!public_id) throw new Error("Id is empty"); - return http_post(api_base("_/forgot-password-requests/fulfill"), {id: public_id, newPassword}); + return http_post(api_base("_/forgot-password-requests/fulfill"), { id: public_id, newPassword }); } export async function delete_account(): Promise<IInternalFetchResponse> { diff --git a/code/app/src/lib/helpers.ts b/code/app/src/lib/helpers.ts index 3fa1653..b659506 100644 --- a/code/app/src/lib/helpers.ts +++ b/code/app/src/lib/helpers.ts @@ -1,7 +1,7 @@ import { browser } from "$app/environment"; -import type { TimeEntryDto } from "$lib/models/TimeEntryDto"; -import type { UnwrappedEntryDateTime } from "$lib/models/UnwrappedEntryDateTime"; -import { logInfo } from "$lib/logger"; +import type { WorkEntry } from "$lib/models/work/WorkEntry"; +import type { UnwrappedEntryDateTime } from "$lib/models/internal/UnwrappedEntryDateTime"; +import { log_info } from "$lib/logger"; import { Temporal } from "temporal-polyfill"; export const EMAIL_REGEX = new RegExp(/^([a-z0-9]+(?:([._\-])[a-z0-9]+)*@(?:[a-z0-9]+(?:(-)[a-z0-9]+)?\.)+[a-z0-9](?:[a-z0-9]*[a-z0-9])?)$/i); @@ -9,7 +9,7 @@ export const URL_REGEX = new RegExp(/^(http:\/\/www\.|https:\/\/www\.|http:\/\/| export const GUID_REGEX = new RegExp(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i); export const NORWEGIAN_PHONE_NUMBER_REGEX = new RegExp(/(0047|\+47|47)?\d{8,12}/); -export function get_default_sorted(unsorted: Array<TimeEntryDto>): Array<TimeEntryDto> { +export function get_default_sorted(unsorted: Array<WorkEntry>): Array<WorkEntry> { if (unsorted.length < 1) return unsorted; const byStart = unsorted.sort((a, b) => { return Temporal.Instant.compare(Temporal.Instant.from(b.start), Temporal.Instant.from(a.start)); @@ -43,17 +43,7 @@ export function is_norwegian_phone_number(value: string): boolean { return NORWEGIAN_PHONE_NUMBER_REGEX.test(String(value)); } -export function get_cookie(name: string) { - const value = `; ${document.cookie}`; - const parts = value.split(`; ${name}=`); - if (parts.length === 2) return parts.pop()?.split(";").shift(); -} - -export function set_cookie(name: string, value: string, baseDomain = window.location.hostname) { - document.cookie = name + "=" + encodeURIComponent(value) + (baseDomain ? ";domain=" + baseDomain : ""); -} - -export function unwrap_date_time_from_entry(entry: TimeEntryDto): UnwrappedEntryDateTime { +export function unwrap_date_time_from_entry(entry: WorkEntry): UnwrappedEntryDateTime { if (!entry) throw new Error("entry was undefined"); const currentTimeZone = Temporal.Now.timeZone().id; const startInstant = Temporal.Instant.from(entry.start).toZonedDateTimeISO(currentTimeZone); @@ -425,7 +415,7 @@ export function can_use_dom(): boolean { export function session_storage_remove_regex(regex: RegExp): void { if (!browser) { - logInfo("sessionStorage is not available in non-browser contexts"); + log_info("sessionStorage is not available in non-browser contexts"); return; } let n = sessionStorage.length; @@ -439,7 +429,7 @@ export function session_storage_remove_regex(regex: RegExp): void { export function local_storage_remove_regex(regex: RegExp): void { if (!browser) { - logInfo("sessionStorage is not available in non-browser contexts"); + log_info("sessionStorage is not available in non-browser contexts"); return; } let n = localStorage.length; diff --git a/code/app/src/lib/logger.ts b/code/app/src/lib/logger.ts index df0a821..831694c 100644 --- a/code/app/src/lib/logger.ts +++ b/code/app/src/lib/logger.ts @@ -10,13 +10,13 @@ const pinoConfig = dev ? { const pinoLogger = pino(pinoConfig); -function browserLogLevel(): number { - if (browser) return LogLevel.toNumber(sessionStorage.getItem(StorageKeys.logLevel), LogLevel.INFO); +function browser_log_level(): number { + if (browser) return LogLevel.to_number(sessionStorage.getItem(StorageKeys.logLevel), LogLevel.INFO); throw new Error("Called browser api in server"); } -function serverLogLevel(): number { - if (!browser) return LogLevel.toNumber(import.meta.env.VITE_LOG_LEVEL, LogLevel.ERROR); +function server_log_level(): number { + if (!browser) return LogLevel.to_number(import.meta.env.VITE_LOG_LEVEL, LogLevel.ERROR); throw new Error("Called server api in browser"); } @@ -25,7 +25,7 @@ export const LogLevel = { INFO: 1, ERROR: 2, SILENT: 3, - toString(levelInt: number): string { + to_string(levelInt: number): string { switch (levelInt) { case 0: return "DEBUG"; @@ -39,7 +39,7 @@ export const LogLevel = { throw new Error("Log level int is unknown"); } }, - toNumber(levelString?: string | null, fallback?: number): number { + to_number(levelString?: string | null, fallback?: number): number { if (!levelString && fallback) return fallback; else if (!levelString && !fallback) throw new Error("levelString was empty, and no fallback was specified"); switch (levelString?.toUpperCase()) { @@ -58,29 +58,29 @@ export const LogLevel = { }, }; -export function logDebug(message: string, ...additional: any[]): void { - if (browser && browserLogLevel() <= LogLevel.DEBUG) { +export function log_debug(message: string, ...additional: any[]): void { + if (browser && browser_log_level() <= LogLevel.DEBUG) { pinoLogger.debug(message, additional); } - if (!browser && serverLogLevel() <= LogLevel.DEBUG) { + if (!browser && server_log_level() <= LogLevel.DEBUG) { pinoLogger.debug(message, additional); } } -export function logInfo(message: string, ...additional: any[]): void { - if (browser && browserLogLevel() <= LogLevel.INFO) { +export function log_info(message: string, ...additional: any[]): void { + if (browser && browser_log_level() <= LogLevel.INFO) { pinoLogger.info(message, additional); } - if (!browser && serverLogLevel() <= LogLevel.INFO) { + if (!browser && server_log_level() <= LogLevel.INFO) { pinoLogger.info(message, additional); } } -export function logError(message: any, ...additional: any[]): void { - if (browser && browserLogLevel() <= LogLevel.ERROR) { +export function log_error(message: any, ...additional: any[]): void { + if (browser && browser_log_level() <= LogLevel.ERROR) { pinoLogger.error(message, additional); } - if (!browser && serverLogLevel() <= LogLevel.ERROR) { + if (!browser && server_log_level() <= LogLevel.ERROR) { pinoLogger.error(message, additional); } }
\ No newline at end of file diff --git a/code/app/src/lib/session.ts b/code/app/src/lib/session.ts index ee79933..7cd5fcf 100644 --- a/code/app/src/lib/session.ts +++ b/code/app/src/lib/session.ts @@ -1,9 +1,9 @@ -import {logError, logInfo} from "$lib/logger"; +import { log_error, log_info } from "$lib/logger"; import { Temporal } from "temporal-polyfill"; import { get_profile_for_active_check, logout } from "./api/user"; import { is_guid, session_storage_get_json, session_storage_set_json } from "./helpers"; import { SECONDS_BETWEEN_SESSION_CHECK, StorageKeys } from "./configuration"; -import type { ISession } from "$lib/models/ISession"; +import type { ISession } from "$lib/models/internal/ISession"; export async function is_active(forceRefresh: boolean = false): Promise<boolean> { const nowEpoch = Temporal.Now.instant().epochSeconds; @@ -16,7 +16,7 @@ export async function is_active(forceRefresh: boolean = false): Promise<boolean> const sessionIsValid = data.profile && is_guid(data.profile.id); if (!sessionIsValid) { clear_session_data(); - logInfo("Session data is not valid"); + log_info("Session data is not valid"); } return sessionIsValid; } @@ -29,7 +29,7 @@ export async function end_session(cb: Function): Promise<void> { } async function call_api(): Promise<boolean> { - logInfo("Getting profile data while checking session state"); + log_info("Getting profile data while checking session state"); try { const response = await get_profile_for_active_check(); if (response.ok) { @@ -40,20 +40,20 @@ async function call_api(): Promise<boolean> { lastChecked: Temporal.Now.instant().epochSeconds } as ISession; session_storage_set_json(StorageKeys.session, session); - logInfo("Successfully got profile data while checking session state"); + log_info("Successfully got profile data while checking session state"); return true; } else { - logError("Api returned invalid data while getting profile data"); + log_error("Api returned invalid data while getting profile data"); clear_session_data(); return false; } } else { - logError("Api returned unsuccessfully while getting profile data"); + log_error("Api returned unsuccessfully while getting profile data"); clear_session_data(); return false; } } catch (e) { - logError(e); + log_error(e); clear_session_data(); return false; } @@ -61,7 +61,7 @@ async function call_api(): Promise<boolean> { export function clear_session_data() { session_storage_set_json(StorageKeys.session, {}); - logInfo("Cleared session data."); + log_info("Cleared session data."); } export function get_session_data(): ISession { diff --git a/code/app/src/routes/(main)/+layout.server.ts b/code/app/src/routes/(main)/+layout.server.ts index d2eb2eb..0277a2c 100644 --- a/code/app/src/routes/(main)/+layout.server.ts +++ b/code/app/src/routes/(main)/+layout.server.ts @@ -1,17 +1,16 @@ import { api_base, CookieNames } from "$lib/configuration"; -import { logError } from "$lib/logger"; +import { log_error } from "$lib/logger"; import { error, redirect } from "@sveltejs/kit"; import type { LayoutServerLoad } from "./$types"; export const load: LayoutServerLoad = async ({ routeId, cookies, locals }) => { const isPublicRoute = (routeId?.startsWith("(main)/(public)") || routeId === "(main)") ?? true; - - let sessionIsValid = (await fetch(api_base("_/valid-session"), { + const sessionIsValid = (await fetch(api_base("_/valid-session"), { headers: { Cookie: CookieNames.session + "=" + cookies.get(CookieNames.session) } }).catch((e) => { - logError(e); + log_error(e); throw error(503, { message: "We are experiencing a service distruption! Have patience while we resolve the issue." }) @@ -25,9 +24,10 @@ export const load: LayoutServerLoad = async ({ routeId, cookies, locals }) => { if (sessionIsValid && isPublicRoute) { throw redirect(302, "/home"); - } else if (!sessionIsValid && !isPublicRoute) { + } else if (routeId === "(main)" || !sessionIsValid && !isPublicRoute) { throw redirect(302, "/sign-in"); } + return { locale: locals.locale } diff --git a/code/app/src/routes/(main)/+layout.ts b/code/app/src/routes/(main)/+layout.ts index 5d0e005..491ea1f 100644 --- a/code/app/src/routes/(main)/+layout.ts +++ b/code/app/src/routes/(main)/+layout.ts @@ -6,10 +6,6 @@ import { setLocale } from '$lib/i18n/i18n-svelte' export const load: LayoutLoad<{ locale: Locales }> = async ({ data: { locale } }) => { // load dictionary into memory await loadLocaleAsync(locale) - - // if you need to output a localized string in a `load` function, - // you always need to call `setLocale` right before you access the `LL` store setLocale(locale) - // pass locale to the "rendering context" return { locale } }
\ No newline at end of file |
