adds zod API validation
This commit is contained in:
23
web/src/lib/models/api/base_schema.ts
Normal file
23
web/src/lib/models/api/base_schema.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { z } from "zod";
|
||||
|
||||
|
||||
const RecordOptionsSchema = z.object({
|
||||
expand: z.string().optional(),
|
||||
requestKey: z.string().optional()
|
||||
})
|
||||
|
||||
const RecordListOptionsSchema = RecordOptionsSchema.extend({
|
||||
page: z.number({ coerce: true }).int().positive().optional(),
|
||||
perPage: z.number({ coerce: true }).int().optional(),
|
||||
sort: z.string().optional(),
|
||||
filter: z.string().optional(),
|
||||
expand: z.string().optional(),
|
||||
requestKey: z.string().optional()
|
||||
})
|
||||
|
||||
const RecordIdSchema = z.object({
|
||||
id: z.string().length(15)
|
||||
})
|
||||
|
||||
|
||||
export { RecordOptionsSchema, RecordListOptionsSchema, RecordIdSchema }
|
||||
17
web/src/lib/models/api/comment_schema.ts
Normal file
17
web/src/lib/models/api/comment_schema.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { Comment } from "../comment";
|
||||
|
||||
const CommentCreateSchema = z.object({
|
||||
text: z.string(),
|
||||
rating: z.number(),
|
||||
author: z.string().length(15),
|
||||
trail: z.string().length(15),
|
||||
|
||||
}) satisfies ZodType<Comment>
|
||||
|
||||
const CommentUpdateSchema = z.object({
|
||||
text: z.string().optional(),
|
||||
rating: z.number().optional(),
|
||||
}) satisfies ZodType<Partial<Comment>>
|
||||
|
||||
export { CommentCreateSchema, CommentUpdateSchema }
|
||||
11
web/src/lib/models/api/follow_schema.ts
Normal file
11
web/src/lib/models/api/follow_schema.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { Follow } from "../follow";
|
||||
|
||||
const FollowCreateSchema = z.object({
|
||||
follower: z.string().length(15),
|
||||
followee: z.string().length(15),
|
||||
|
||||
}) satisfies ZodType<Follow>
|
||||
|
||||
|
||||
export { FollowCreateSchema };
|
||||
23
web/src/lib/models/api/list_schema.ts
Normal file
23
web/src/lib/models/api/list_schema.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { List } from "../list";
|
||||
|
||||
const ListCreateSchema = z.object({
|
||||
name: z.string(),
|
||||
public: z.boolean(),
|
||||
description: z.string().optional(),
|
||||
trails: z.array(z.string().length(15)),
|
||||
avatar: z.string().optional(),
|
||||
author: z.string()
|
||||
}) satisfies ZodType<List>
|
||||
|
||||
const ListUpdateSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
public: z.boolean().optional(),
|
||||
description: z.string().optional(),
|
||||
trails: z.array(z.string().length(15)).optional(),
|
||||
"trails-": z.string().optional(),
|
||||
"trails+": z.string().optional(),
|
||||
avatar: z.string().optional(),
|
||||
}) satisfies ZodType<Partial<List>>
|
||||
|
||||
export { ListCreateSchema, ListUpdateSchema };
|
||||
16
web/src/lib/models/api/list_share_schema.ts
Normal file
16
web/src/lib/models/api/list_share_schema.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { ListShare } from "../list_share";
|
||||
|
||||
const ListShareCreateSchema = z.object({
|
||||
user: z.string().length(15),
|
||||
list: z.string().length(15),
|
||||
permission: z.enum(["view", "edit"])
|
||||
|
||||
}) satisfies ZodType<ListShare>
|
||||
|
||||
const ListShareUpdateSchema = z.object({
|
||||
permission: z.enum(["view", "edit"])
|
||||
}) satisfies ZodType<Partial<ListShare>>
|
||||
|
||||
|
||||
export { ListShareCreateSchema, ListShareUpdateSchema };
|
||||
8
web/src/lib/models/api/notification_schema.ts
Normal file
8
web/src/lib/models/api/notification_schema.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { z, type ZodType } from "zod"
|
||||
import { type Notification } from "../notification";
|
||||
|
||||
const NotificationUpdateSchema = z.object({
|
||||
seen: z.literal(true)
|
||||
}) satisfies ZodType<Partial<Notification>>
|
||||
|
||||
export { NotificationUpdateSchema }
|
||||
28
web/src/lib/models/api/settings_schema.ts
Normal file
28
web/src/lib/models/api/settings_schema.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import { NotificationType } from "../notification";
|
||||
import type { Settings } from "../settings";
|
||||
|
||||
const SettingsCreateSchema = z.object({
|
||||
unit: z.enum(["metric", "imperial"]).optional(),
|
||||
language: z.enum(["en", "de", "fr", "hu", "it", "nl", "pl", "pt", "zh"]).optional(),
|
||||
mapFocus: z.enum(["trails", "location"]).optional(),
|
||||
location: z.object({
|
||||
name: z.string(),
|
||||
lat: z.number(),
|
||||
lon: z.number()
|
||||
}).optional(),
|
||||
category: z.string().optional(),
|
||||
tilesets: z.array(z.object({ name: z.string(), url: z.string().url() })).optional(),
|
||||
terrain: z.object({ terrain: z.string().url(), hillshading: z.string().url() }).optional(),
|
||||
user: z.string().optional(),
|
||||
privacy: z.object({
|
||||
account: z.enum(["public", "private"]),
|
||||
trails: z.enum(["public", "private"]),
|
||||
lists: z.enum(["public", "private"])
|
||||
}).optional(),
|
||||
notifications: z.record(z.enum(Object.values(NotificationType) as [string, ...string[]]), z.object({ web: z.boolean(), email: z.boolean() })).optional()
|
||||
|
||||
}) satisfies ZodType<Settings>
|
||||
ZodType<Partial<Comment>>
|
||||
|
||||
export { SettingsCreateSchema };
|
||||
31
web/src/lib/models/api/summit_log_schema.ts
Normal file
31
web/src/lib/models/api/summit_log_schema.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { SummitLog } from "../summit_log";
|
||||
|
||||
|
||||
const SummitLogCreateSchema = z.object({
|
||||
id: z.string().length(15).optional(),
|
||||
date: z.string().date(),
|
||||
text: z.string().optional(),
|
||||
gpx: z.string().optional(),
|
||||
distance: z.number().nonnegative().optional(),
|
||||
elevation_gain: z.number().nonnegative().optional(),
|
||||
elevation_loss: z.number().nonnegative().optional(),
|
||||
duration: z.number().nonnegative().optional(),
|
||||
author: z.string().length(15),
|
||||
photos: z.array(z.string())
|
||||
}) satisfies ZodType<SummitLog>
|
||||
|
||||
const SummitLogUpdateSchema = z.object({
|
||||
date: z.string().date().optional(),
|
||||
text: z.string().optional(),
|
||||
gpx: z.string().optional(),
|
||||
distance: z.number().nonnegative().optional(),
|
||||
elevation_gain: z.number().nonnegative().optional(),
|
||||
elevation_loss: z.number().nonnegative().optional(),
|
||||
duration: z.number().nonnegative().optional(),
|
||||
photos: z.array(z.string()).optional(),
|
||||
"photos-": z.string().optional(),
|
||||
"photos+": z.string().optional(),
|
||||
}) satisfies ZodType<Partial<SummitLog>>
|
||||
|
||||
export { SummitLogCreateSchema, SummitLogUpdateSchema };
|
||||
49
web/src/lib/models/api/trail_schema.ts
Normal file
49
web/src/lib/models/api/trail_schema.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { Trail } from "../trail";
|
||||
|
||||
|
||||
const TrailCreateSchema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string().optional(),
|
||||
location: z.string().optional(),
|
||||
date: z.string().date(),
|
||||
public: z.boolean(),
|
||||
difficulty: z.enum(["easy", "moderate", "difficult"]).optional(),
|
||||
lat: z.number().optional(),
|
||||
lon: z.number().optional(),
|
||||
distance: z.number({coerce: true}).nonnegative().optional(),
|
||||
elevation_gain: z.number({coerce: true}).nonnegative().optional(),
|
||||
elevation_loss: z.number({coerce: true}).nonnegative().optional(),
|
||||
duration: z.number({coerce: true}).nonnegative().optional(),
|
||||
photos: z.array(z.string()),
|
||||
thumbnail: z.number().int().nonnegative().optional(),
|
||||
waypoints: z.array(z.string()),
|
||||
summit_logs: z.array(z.string()),
|
||||
category: z.string().optional(),
|
||||
gpx: z.string().optional(),
|
||||
author: z.string().length(15),
|
||||
|
||||
}) satisfies ZodType<Trail>
|
||||
|
||||
const TrailUpdateSchema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string().optional(),
|
||||
location: z.string().optional(),
|
||||
date: z.string().date(),
|
||||
public: z.boolean().optional(),
|
||||
difficulty: z.enum(["easy", "moderate", "difficult"]).optional(),
|
||||
lat: z.number().optional(),
|
||||
lon: z.number().optional(),
|
||||
distance: z.number({coerce: true}).nonnegative().optional(),
|
||||
elevation_gain: z.number({coerce: true}).nonnegative().optional(),
|
||||
elevation_loss: z.number({coerce: true}).nonnegative().optional(),
|
||||
duration: z.number({coerce: true}).nonnegative().optional(),
|
||||
photos: z.array(z.string()).optional(),
|
||||
thumbnail: z.number().int().nonnegative().optional(),
|
||||
waypoints: z.array(z.string()).optional(),
|
||||
summit_logs: z.array(z.string()).optional(),
|
||||
category: z.string().optional(),
|
||||
gpx: z.string().optional(),
|
||||
}) satisfies ZodType<Partial<Trail>>
|
||||
|
||||
export { TrailCreateSchema, TrailUpdateSchema };
|
||||
16
web/src/lib/models/api/trail_share_schema.ts
Normal file
16
web/src/lib/models/api/trail_share_schema.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { TrailShare } from "../trail_share";
|
||||
|
||||
const TrailShareCreateSchema = z.object({
|
||||
user: z.string().length(15),
|
||||
trail: z.string().length(15),
|
||||
permission: z.enum(["view", "edit"])
|
||||
|
||||
}) satisfies ZodType<TrailShare>
|
||||
|
||||
const TrailShareUpdateSchema = z.object({
|
||||
permission: z.enum(["view", "edit"])
|
||||
}) satisfies ZodType<Partial<TrailShare>>
|
||||
|
||||
|
||||
export { TrailShareCreateSchema, TrailShareUpdateSchema };
|
||||
29
web/src/lib/models/api/user_schema.ts
Normal file
29
web/src/lib/models/api/user_schema.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { User } from "../user";
|
||||
|
||||
const UserCreateSchema = (z.object({
|
||||
username: z.string({ message: "required" }).min(3, "must-be-at-least-n-characters-long").regex(/^[\w][\w\.]*$/, "invalid-username"),
|
||||
email: z.string({ message: "required" }).email("not-a-valid-email-address"),
|
||||
password: z.string().min(8, "must-be-at-least-n-characters-long"),
|
||||
passwordConfirm: z.string().optional()
|
||||
|
||||
}) satisfies ZodType<User>).refine((data) => data.password === data.passwordConfirm, {
|
||||
message: "passwords-must-match",
|
||||
path: ["passwordConfirm"],
|
||||
})
|
||||
|
||||
const UserUpdateSchema = (z.object({
|
||||
username: z.string({ message: "required" }).min(3, "must-be-at-least-n-characters-long").regex(/^[\w][\w\.]*$/, "invalid-username").optional(),
|
||||
email: z.string({ message: "required" }).email("not-a-valid-email-address").optional(),
|
||||
password: z.string().min(8, "must-be-at-least-n-characters-long").optional(),
|
||||
oldPassword: z.string().min(8, "must-be-at-least-n-characters-long").optional(),
|
||||
passwordConfirm: z.string().min(8, "must-be-at-least-n-characters-long").optional(),
|
||||
bio: z.string().optional()
|
||||
}) satisfies ZodType<Partial<User>>).refine((data) => data.password === data.passwordConfirm, {
|
||||
message: "passwords-must-match",
|
||||
path: ["passwordConfirm"],
|
||||
});
|
||||
|
||||
|
||||
|
||||
export { UserCreateSchema, UserUpdateSchema };
|
||||
28
web/src/lib/models/api/waypoint_schema.ts
Normal file
28
web/src/lib/models/api/waypoint_schema.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { z, ZodType } from "zod";
|
||||
import type { Waypoint } from "../waypoint";
|
||||
|
||||
const WaypointCreateSchema = z.object({
|
||||
id: z.string().length(15).optional(),
|
||||
name: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
text: z.string().optional(),
|
||||
lat: z.number(),
|
||||
lon: z.number(),
|
||||
icon: z.string().optional(),
|
||||
author: z.string().length(15),
|
||||
photos: z.array(z.string()),
|
||||
}) satisfies ZodType<Waypoint>
|
||||
|
||||
const WaypointUpdateSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
text: z.string().optional(),
|
||||
lat: z.number().optional(),
|
||||
lon: z.number().optional(),
|
||||
icon: z.string().optional(),
|
||||
photos: z.array(z.string()),
|
||||
"photos-": z.string().optional(),
|
||||
"photos+": z.string().optional(),
|
||||
}) satisfies ZodType<Partial<Waypoint>>
|
||||
|
||||
export { WaypointCreateSchema, WaypointUpdateSchema };
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { User } from "$lib/stores/user_store";
|
||||
import type { UserAnonymous } from "./user";
|
||||
|
||||
export class Comment {
|
||||
id?: string;
|
||||
@@ -8,7 +8,7 @@ export class Comment {
|
||||
trail: string;
|
||||
created?: string;
|
||||
expand?: {
|
||||
author: User
|
||||
author: UserAnonymous
|
||||
}
|
||||
|
||||
constructor(text: string, rating: number, author: string, trail: string) {
|
||||
|
||||
@@ -6,16 +6,16 @@ class SummitLog {
|
||||
date: string;
|
||||
text?: string;
|
||||
gpx?: string;
|
||||
_gpx: File | null;
|
||||
_gpx?: File | null;
|
||||
photos: string[];
|
||||
_photos: File[];
|
||||
_photos?: File[];
|
||||
distance?: number
|
||||
elevation_gain?: number
|
||||
elevation_loss?: number
|
||||
duration?: number
|
||||
author?: string;
|
||||
|
||||
expand: {
|
||||
expand?: {
|
||||
gpx_data?: string;
|
||||
trails_via_summit_logs?: Trail[];
|
||||
author?: UserAnonymous
|
||||
|
||||
@@ -18,14 +18,14 @@ class Trail {
|
||||
difficulty?: "easy" | "moderate" | "difficult"
|
||||
lat?: number;
|
||||
lon?: number;
|
||||
thumbnail: number;
|
||||
thumbnail?: number;
|
||||
photos: string[];
|
||||
gpx?: string;
|
||||
created?: string;
|
||||
category?: string;
|
||||
waypoints: string[];
|
||||
summit_logs: string[];
|
||||
expand: {
|
||||
expand?: {
|
||||
category?: Category;
|
||||
waypoints: Waypoint[]
|
||||
summit_logs: SummitLog[]
|
||||
|
||||
@@ -7,7 +7,6 @@ export type User = {
|
||||
password: string,
|
||||
avatar?: string;
|
||||
bio?: string;
|
||||
language?: string;
|
||||
created?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class Waypoint {
|
||||
icon?: string;
|
||||
marker?: M.Marker;
|
||||
photos: string[];
|
||||
_photos: File[];
|
||||
_photos?: File[];
|
||||
author?: string;
|
||||
|
||||
constructor(lat: number, lon: number, params?: {
|
||||
|
||||
Reference in New Issue
Block a user