feat: secure KYC storage, Google OAuth, terms gating

This commit is contained in:
arifal
2026-04-28 23:10:21 +07:00
parent 58da4608ac
commit 05d0929f7a
41 changed files with 3087 additions and 262 deletions
+3
View File
@@ -33,6 +33,9 @@ yarn-error.log*
# env files (can opt-in for committing if needed) # env files (can opt-in for committing if needed)
.env* .env*
# private uploads (KYC: KTP / selfie). Never serve directly.
/uploads/
# vercel # vercel
.vercel .vercel
+89
View File
@@ -0,0 +1,89 @@
"use client";
import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { signOut, useSession } from "next-auth/react";
import { acceptTermsAction } from "@/features/auth/actions";
export function AcceptTermsForm() {
const router = useRouter();
const { update } = useSession();
const [checked, setChecked] = useState(false);
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
async function handleAccept() {
setError("");
setLoading(true);
const result = await acceptTermsAction();
if (result.error) {
setError(result.error);
setLoading(false);
return;
}
// Refresh JWT supaya middleware lihat acceptedTermsAndPrivacy=true
await update();
router.replace("/");
router.refresh();
}
return (
<div className="mt-6 rounded-2xl border border-neutral-200 bg-white p-6 shadow-sm">
{error && (
<div className="mb-4 rounded-xl bg-red-50 px-4 py-3 text-sm font-medium text-red-600">
{error}
</div>
)}
<label className="flex items-start gap-2.5 text-sm text-neutral-700">
<input
type="checkbox"
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
className="mt-0.5 h-4 w-4 shrink-0 rounded border-neutral-300 text-primary-600 focus:ring-primary-500"
/>
<span>
Saya telah membaca dan menyetujui{" "}
<Link
href="/terms"
target="_blank"
rel="noopener noreferrer"
className="font-semibold text-primary-600 hover:text-primary-700"
>
Syarat &amp; Ketentuan
</Link>{" "}
dan{" "}
<Link
href="/privacy"
target="_blank"
rel="noopener noreferrer"
className="font-semibold text-primary-600 hover:text-primary-700"
>
Kebijakan Privasi
</Link>{" "}
SeTrip.
</span>
</label>
<div className="mt-5 flex flex-col gap-2 sm:flex-row">
<button
type="button"
onClick={handleAccept}
disabled={!checked || loading}
className="flex-1 rounded-xl bg-primary-600 py-2.5 text-sm font-bold text-white shadow-lg shadow-primary-600/20 transition-colors hover:bg-primary-700 disabled:opacity-50"
>
{loading ? "Memproses..." : "Setuju & Lanjutkan"}
</button>
<button
type="button"
onClick={() => signOut({ callbackUrl: "/login" })}
disabled={loading}
className="rounded-xl border border-neutral-200 bg-white px-4 py-2.5 text-sm font-medium text-neutral-600 hover:bg-neutral-50 disabled:opacity-50"
>
Keluar
</button>
</div>
</div>
);
}
+27
View File
@@ -0,0 +1,27 @@
import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { userRepo } from "@/server/repositories/user.repo";
import { AcceptTermsForm } from "./form";
export default async function AcceptTermsPage() {
const session = await getServerSession(authOptions);
if (!session?.user) redirect("/login?callbackUrl=/accept-terms");
// Source of truth = DB (token bisa stale).
const user = await userRepo.findById(session.user.id);
if (user?.acceptedTermsAndPrivacy) redirect("/");
return (
<div className="mx-auto max-w-xl px-4 py-10 sm:py-16">
<h1 className="text-2xl font-bold text-neutral-900 sm:text-3xl">
Satu langkah lagi
</h1>
<p className="mt-2 text-sm text-neutral-600">
Sebelum melanjutkan, mohon baca dan setujui Syarat &amp; Ketentuan dan
Kebijakan Privasi SeTrip.
</p>
<AcceptTermsForm />
</div>
);
}
+18 -1
View File
@@ -3,6 +3,7 @@ import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth"; import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin"; import { isAdminEmail } from "@/lib/admin";
import { organizerRepo } from "@/server/repositories/organizer.repo"; import { organizerRepo } from "@/server/repositories/organizer.repo";
import { organizerService } from "@/server/services/organizer.service";
import { ReviewCard } from "@/features/organizer/components/review-card"; import { ReviewCard } from "@/features/organizer/components/review-card";
type Tab = "PENDING" | "APPROVED" | "REJECTED"; type Tab = "PENDING" | "APPROVED" | "REJECTED";
@@ -28,7 +29,23 @@ export default async function AdminVerificationsPage({ searchParams }: PageProps
const tab: Tab = const tab: Tab =
params.tab === "APPROVED" || params.tab === "REJECTED" ? params.tab : "PENDING"; params.tab === "APPROVED" || params.tab === "REJECTED" ? params.tab : "PENDING";
const items = await organizerRepo.listByStatus(tab); const rows = await organizerRepo.listByStatus(tab);
const items = rows.map((v) => ({
id: v.id,
fullName: v.fullName,
nik: organizerService.decryptNik(v.nikEncrypted),
birthDate: v.birthDate,
address: v.address,
bankName: v.bankName,
bankAccountNumber: v.bankAccountNumber,
bankAccountName: v.bankAccountName,
status: v.status,
rejectionReason: v.rejectionReason,
reviewedAt: v.reviewedAt,
createdAt: v.createdAt,
user: v.user,
reviewedBy: v.reviewedBy,
}));
const tabs: { key: Tab; label: string }[] = [ const tabs: { key: Tab; label: string }[] = [
{ key: "PENDING", label: "Pending" }, { key: "PENDING", label: "Pending" },
+63
View File
@@ -0,0 +1,63 @@
import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { organizerRepo } from "@/server/repositories/organizer.repo";
import {
isKycKind,
mimeFromKey,
readDecrypted,
} from "@/lib/secure-storage";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
interface RouteCtx {
params: Promise<{ id: string; kind: string }>;
}
export async function GET(_req: NextRequest, ctx: RouteCtx) {
const session = await getServerSession(authOptions);
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const { id, kind } = await ctx.params;
if (!isKycKind(kind)) {
return NextResponse.json({ error: "Kind tidak valid" }, { status: 400 });
}
const verification = await organizerRepo.findById(id);
if (!verification) {
return NextResponse.json({ error: "Tidak ditemukan" }, { status: 404 });
}
const isOwner = verification.userId === session.user.id;
const isAdmin = isAdminEmail(session.user.email);
if (!isOwner && !isAdmin) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const key = kind === "ktp" ? verification.ktpImageKey : verification.selfieKey;
if (!key) {
return NextResponse.json({ error: "File belum diunggah" }, { status: 404 });
}
let plain: Buffer;
try {
plain = await readDecrypted(kind, key);
} catch {
return NextResponse.json({ error: "File tidak dapat dibuka" }, { status: 500 });
}
return new NextResponse(new Uint8Array(plain), {
status: 200,
headers: {
"Content-Type": mimeFromKey(key),
"Content-Length": String(plain.length),
"Cache-Control": "private, no-store",
"X-Content-Type-Options": "nosniff",
"Content-Disposition": `inline; filename="${kind}-${id}"`,
},
});
}
+54
View File
@@ -0,0 +1,54 @@
import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import {
ALLOWED_KYC_MIME,
MAX_KYC_FILE_BYTES,
isKycKind,
saveEncrypted,
} from "@/lib/secure-storage";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export async function POST(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
let form: FormData;
try {
form = await req.formData();
} catch {
return NextResponse.json({ error: "Body bukan multipart/form-data" }, { status: 400 });
}
const kind = String(form.get("kind") ?? "");
const file = form.get("file");
if (!isKycKind(kind)) {
return NextResponse.json({ error: "kind harus 'ktp' atau 'selfie'" }, { status: 400 });
}
if (!(file instanceof File)) {
return NextResponse.json({ error: "File wajib diisi" }, { status: 400 });
}
if (!ALLOWED_KYC_MIME.has(file.type)) {
return NextResponse.json(
{ error: "Hanya menerima JPG, PNG, atau WebP" },
{ status: 415 },
);
}
if (file.size > MAX_KYC_FILE_BYTES) {
return NextResponse.json({ error: "File maksimal 5MB" }, { status: 413 });
}
const buf = Buffer.from(await file.arrayBuffer());
const meta = await saveEncrypted(kind, buf, file.type);
return NextResponse.json({
key: meta.key,
mime: meta.mime,
size: meta.size,
});
}
+6
View File
@@ -22,6 +22,12 @@ export * from './enums';
* *
*/ */
export type User = Prisma.UserModel export type User = Prisma.UserModel
/**
* Model Account
* Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
* Session tidak pakai DB — kita pakai JWT, jadi Session/VerificationToken tidak perlu.
*/
export type Account = Prisma.AccountModel
/** /**
* Model OrganizerVerification * Model OrganizerVerification
* *
+6
View File
@@ -46,6 +46,12 @@ export { Prisma }
* *
*/ */
export type User = Prisma.UserModel export type User = Prisma.UserModel
/**
* Model Account
* Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
* Session tidak pakai DB — kita pakai JWT, jadi Session/VerificationToken tidak perlu.
*/
export type Account = Prisma.AccountModel
/** /**
* Model OrganizerVerification * Model OrganizerVerification
* *
+54
View File
@@ -148,6 +148,33 @@ export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedDateTimeFilter<$PrismaModel> _max?: Prisma.NestedDateTimeFilter<$PrismaModel>
} }
export type IntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type IntNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedFloatNullableFilter<$PrismaModel>
_sum?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedIntNullableFilter<$PrismaModel>
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
}
export type EnumVerificationStatusFilter<$PrismaModel = never> = { export type EnumVerificationStatusFilter<$PrismaModel = never> = {
equals?: $Enums.VerificationStatus | Prisma.EnumVerificationStatusFieldRefInput<$PrismaModel> equals?: $Enums.VerificationStatus | Prisma.EnumVerificationStatusFieldRefInput<$PrismaModel>
in?: $Enums.VerificationStatus[] | Prisma.ListEnumVerificationStatusFieldRefInput<$PrismaModel> in?: $Enums.VerificationStatus[] | Prisma.ListEnumVerificationStatusFieldRefInput<$PrismaModel>
@@ -373,6 +400,33 @@ export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedDateTimeFilter<$PrismaModel> _max?: Prisma.NestedDateTimeFilter<$PrismaModel>
} }
export type NestedIntNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedFloatNullableFilter<$PrismaModel>
_sum?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedIntNullableFilter<$PrismaModel>
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
}
export type NestedFloatNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
not?: Prisma.NestedFloatNullableFilter<$PrismaModel> | number | null
}
export type NestedEnumVerificationStatusFilter<$PrismaModel = never> = { export type NestedEnumVerificationStatusFilter<$PrismaModel = never> = {
equals?: $Enums.VerificationStatus | Prisma.EnumVerificationStatusFieldRefInput<$PrismaModel> equals?: $Enums.VerificationStatus | Prisma.EnumVerificationStatusFieldRefInput<$PrismaModel>
in?: $Enums.VerificationStatus[] | Prisma.ListEnumVerificationStatusFieldRefInput<$PrismaModel> in?: $Enums.VerificationStatus[] | Prisma.ListEnumVerificationStatusFieldRefInput<$PrismaModel>
File diff suppressed because one or more lines are too long
+113 -18
View File
@@ -385,6 +385,7 @@ type FieldRefInputType<Model, FieldType> = Model extends never ? never : FieldRe
export const ModelName = { export const ModelName = {
User: 'User', User: 'User',
Account: 'Account',
OrganizerVerification: 'OrganizerVerification', OrganizerVerification: 'OrganizerVerification',
Trip: 'Trip', Trip: 'Trip',
TripReview: 'TripReview', TripReview: 'TripReview',
@@ -405,7 +406,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions omit: GlobalOmitOptions
} }
meta: { meta: {
modelProps: "user" | "organizerVerification" | "trip" | "tripReview" | "tripImage" | "tripParticipant" modelProps: "user" | "account" | "organizerVerification" | "trip" | "tripReview" | "tripImage" | "tripParticipant"
txIsolationLevel: TransactionIsolationLevel txIsolationLevel: TransactionIsolationLevel
} }
model: { model: {
@@ -483,6 +484,80 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
} }
} }
} }
Account: {
payload: Prisma.$AccountPayload<ExtArgs>
fields: Prisma.AccountFieldRefs
operations: {
findUnique: {
args: Prisma.AccountFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload> | null
}
findUniqueOrThrow: {
args: Prisma.AccountFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>
}
findFirst: {
args: Prisma.AccountFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload> | null
}
findFirstOrThrow: {
args: Prisma.AccountFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>
}
findMany: {
args: Prisma.AccountFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>[]
}
create: {
args: Prisma.AccountCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>
}
createMany: {
args: Prisma.AccountCreateManyArgs<ExtArgs>
result: BatchPayload
}
createManyAndReturn: {
args: Prisma.AccountCreateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>[]
}
delete: {
args: Prisma.AccountDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>
}
update: {
args: Prisma.AccountUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>
}
deleteMany: {
args: Prisma.AccountDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.AccountUpdateManyArgs<ExtArgs>
result: BatchPayload
}
updateManyAndReturn: {
args: Prisma.AccountUpdateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>[]
}
upsert: {
args: Prisma.AccountUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$AccountPayload>
}
aggregate: {
args: Prisma.AccountAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateAccount>
}
groupBy: {
args: Prisma.AccountGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AccountGroupByOutputType>[]
}
count: {
args: Prisma.AccountCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AccountCountAggregateOutputType> | number
}
}
}
OrganizerVerification: { OrganizerVerification: {
payload: Prisma.$OrganizerVerificationPayload<ExtArgs> payload: Prisma.$OrganizerVerificationPayload<ExtArgs>
fields: Prisma.OrganizerVerificationFieldRefs fields: Prisma.OrganizerVerificationFieldRefs
@@ -907,15 +982,34 @@ export const UserScalarFieldEnum = {
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
export const AccountScalarFieldEnum = {
id: 'id',
userId: 'userId',
type: 'type',
provider: 'provider',
providerAccountId: 'providerAccountId',
refresh_token: 'refresh_token',
access_token: 'access_token',
expires_at: 'expires_at',
token_type: 'token_type',
scope: 'scope',
id_token: 'id_token',
session_state: 'session_state'
} as const
export type AccountScalarFieldEnum = (typeof AccountScalarFieldEnum)[keyof typeof AccountScalarFieldEnum]
export const OrganizerVerificationScalarFieldEnum = { export const OrganizerVerificationScalarFieldEnum = {
id: 'id', id: 'id',
userId: 'userId', userId: 'userId',
fullName: 'fullName', fullName: 'fullName',
nik: 'nik', nikEncrypted: 'nikEncrypted',
nikHash: 'nikHash',
birthDate: 'birthDate', birthDate: 'birthDate',
address: 'address', address: 'address',
ktpImageUrl: 'ktpImageUrl', ktpImageKey: 'ktpImageKey',
selfieUrl: 'selfieUrl', selfieKey: 'selfieKey',
bankName: 'bankName', bankName: 'bankName',
bankAccountNumber: 'bankAccountNumber', bankAccountNumber: 'bankAccountNumber',
bankAccountName: 'bankAccountName', bankAccountName: 'bankAccountName',
@@ -1056,20 +1150,6 @@ export type ListDateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaM
/**
* Reference to a field of type 'VerificationStatus'
*/
export type EnumVerificationStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'VerificationStatus'>
/**
* Reference to a field of type 'VerificationStatus[]'
*/
export type ListEnumVerificationStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'VerificationStatus[]'>
/** /**
* Reference to a field of type 'Int' * Reference to a field of type 'Int'
*/ */
@@ -1084,6 +1164,20 @@ export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel,
/**
* Reference to a field of type 'VerificationStatus'
*/
export type EnumVerificationStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'VerificationStatus'>
/**
* Reference to a field of type 'VerificationStatus[]'
*/
export type ListEnumVerificationStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'VerificationStatus[]'>
/** /**
* Reference to a field of type 'TripStatus' * Reference to a field of type 'TripStatus'
*/ */
@@ -1221,6 +1315,7 @@ export type PrismaClientOptions = ({
} }
export type GlobalOmitConfig = { export type GlobalOmitConfig = {
user?: Prisma.UserOmit user?: Prisma.UserOmit
account?: Prisma.AccountOmit
organizerVerification?: Prisma.OrganizerVerificationOmit organizerVerification?: Prisma.OrganizerVerificationOmit
trip?: Prisma.TripOmit trip?: Prisma.TripOmit
tripReview?: Prisma.TripReviewOmit tripReview?: Prisma.TripReviewOmit
@@ -52,6 +52,7 @@ export const AnyNull = runtime.AnyNull
export const ModelName = { export const ModelName = {
User: 'User', User: 'User',
Account: 'Account',
OrganizerVerification: 'OrganizerVerification', OrganizerVerification: 'OrganizerVerification',
Trip: 'Trip', Trip: 'Trip',
TripReview: 'TripReview', TripReview: 'TripReview',
@@ -90,15 +91,34 @@ export const UserScalarFieldEnum = {
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
export const AccountScalarFieldEnum = {
id: 'id',
userId: 'userId',
type: 'type',
provider: 'provider',
providerAccountId: 'providerAccountId',
refresh_token: 'refresh_token',
access_token: 'access_token',
expires_at: 'expires_at',
token_type: 'token_type',
scope: 'scope',
id_token: 'id_token',
session_state: 'session_state'
} as const
export type AccountScalarFieldEnum = (typeof AccountScalarFieldEnum)[keyof typeof AccountScalarFieldEnum]
export const OrganizerVerificationScalarFieldEnum = { export const OrganizerVerificationScalarFieldEnum = {
id: 'id', id: 'id',
userId: 'userId', userId: 'userId',
fullName: 'fullName', fullName: 'fullName',
nik: 'nik', nikEncrypted: 'nikEncrypted',
nikHash: 'nikHash',
birthDate: 'birthDate', birthDate: 'birthDate',
address: 'address', address: 'address',
ktpImageUrl: 'ktpImageUrl', ktpImageKey: 'ktpImageKey',
selfieUrl: 'selfieUrl', selfieKey: 'selfieKey',
bankName: 'bankName', bankName: 'bankName',
bankAccountNumber: 'bankAccountNumber', bankAccountNumber: 'bankAccountNumber',
bankAccountName: 'bankAccountName', bankAccountName: 'bankAccountName',
+1
View File
@@ -9,6 +9,7 @@
* 🟢 You can import this file directly. * 🟢 You can import this file directly.
*/ */
export type * from './models/User' export type * from './models/User'
export type * from './models/Account'
export type * from './models/OrganizerVerification' export type * from './models/OrganizerVerification'
export type * from './models/Trip' export type * from './models/Trip'
export type * from './models/TripReview' export type * from './models/TripReview'
File diff suppressed because it is too large Load Diff
@@ -28,11 +28,12 @@ export type OrganizerVerificationMinAggregateOutputType = {
id: string | null id: string | null
userId: string | null userId: string | null
fullName: string | null fullName: string | null
nik: string | null nikEncrypted: string | null
nikHash: string | null
birthDate: Date | null birthDate: Date | null
address: string | null address: string | null
ktpImageUrl: string | null ktpImageKey: string | null
selfieUrl: string | null selfieKey: string | null
bankName: string | null bankName: string | null
bankAccountNumber: string | null bankAccountNumber: string | null
bankAccountName: string | null bankAccountName: string | null
@@ -49,11 +50,12 @@ export type OrganizerVerificationMaxAggregateOutputType = {
id: string | null id: string | null
userId: string | null userId: string | null
fullName: string | null fullName: string | null
nik: string | null nikEncrypted: string | null
nikHash: string | null
birthDate: Date | null birthDate: Date | null
address: string | null address: string | null
ktpImageUrl: string | null ktpImageKey: string | null
selfieUrl: string | null selfieKey: string | null
bankName: string | null bankName: string | null
bankAccountNumber: string | null bankAccountNumber: string | null
bankAccountName: string | null bankAccountName: string | null
@@ -70,11 +72,12 @@ export type OrganizerVerificationCountAggregateOutputType = {
id: number id: number
userId: number userId: number
fullName: number fullName: number
nik: number nikEncrypted: number
nikHash: number
birthDate: number birthDate: number
address: number address: number
ktpImageUrl: number ktpImageKey: number
selfieUrl: number selfieKey: number
bankName: number bankName: number
bankAccountNumber: number bankAccountNumber: number
bankAccountName: number bankAccountName: number
@@ -93,11 +96,12 @@ export type OrganizerVerificationMinAggregateInputType = {
id?: true id?: true
userId?: true userId?: true
fullName?: true fullName?: true
nik?: true nikEncrypted?: true
nikHash?: true
birthDate?: true birthDate?: true
address?: true address?: true
ktpImageUrl?: true ktpImageKey?: true
selfieUrl?: true selfieKey?: true
bankName?: true bankName?: true
bankAccountNumber?: true bankAccountNumber?: true
bankAccountName?: true bankAccountName?: true
@@ -114,11 +118,12 @@ export type OrganizerVerificationMaxAggregateInputType = {
id?: true id?: true
userId?: true userId?: true
fullName?: true fullName?: true
nik?: true nikEncrypted?: true
nikHash?: true
birthDate?: true birthDate?: true
address?: true address?: true
ktpImageUrl?: true ktpImageKey?: true
selfieUrl?: true selfieKey?: true
bankName?: true bankName?: true
bankAccountNumber?: true bankAccountNumber?: true
bankAccountName?: true bankAccountName?: true
@@ -135,11 +140,12 @@ export type OrganizerVerificationCountAggregateInputType = {
id?: true id?: true
userId?: true userId?: true
fullName?: true fullName?: true
nik?: true nikEncrypted?: true
nikHash?: true
birthDate?: true birthDate?: true
address?: true address?: true
ktpImageUrl?: true ktpImageKey?: true
selfieUrl?: true selfieKey?: true
bankName?: true bankName?: true
bankAccountNumber?: true bankAccountNumber?: true
bankAccountName?: true bankAccountName?: true
@@ -229,11 +235,12 @@ export type OrganizerVerificationGroupByOutputType = {
id: string id: string
userId: string userId: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date birthDate: Date
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -271,11 +278,12 @@ export type OrganizerVerificationWhereInput = {
id?: Prisma.StringFilter<"OrganizerVerification"> | string id?: Prisma.StringFilter<"OrganizerVerification"> | string
userId?: Prisma.StringFilter<"OrganizerVerification"> | string userId?: Prisma.StringFilter<"OrganizerVerification"> | string
fullName?: Prisma.StringFilter<"OrganizerVerification"> | string fullName?: Prisma.StringFilter<"OrganizerVerification"> | string
nik?: Prisma.StringFilter<"OrganizerVerification"> | string nikEncrypted?: Prisma.StringFilter<"OrganizerVerification"> | string
nikHash?: Prisma.StringFilter<"OrganizerVerification"> | string
birthDate?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string birthDate?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string
address?: Prisma.StringFilter<"OrganizerVerification"> | string address?: Prisma.StringFilter<"OrganizerVerification"> | string
ktpImageUrl?: Prisma.StringFilter<"OrganizerVerification"> | string ktpImageKey?: Prisma.StringFilter<"OrganizerVerification"> | string
selfieUrl?: Prisma.StringFilter<"OrganizerVerification"> | string selfieKey?: Prisma.StringFilter<"OrganizerVerification"> | string
bankName?: Prisma.StringFilter<"OrganizerVerification"> | string bankName?: Prisma.StringFilter<"OrganizerVerification"> | string
bankAccountNumber?: Prisma.StringFilter<"OrganizerVerification"> | string bankAccountNumber?: Prisma.StringFilter<"OrganizerVerification"> | string
bankAccountName?: Prisma.StringFilter<"OrganizerVerification"> | string bankAccountName?: Prisma.StringFilter<"OrganizerVerification"> | string
@@ -294,11 +302,12 @@ export type OrganizerVerificationOrderByWithRelationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
userId?: Prisma.SortOrder userId?: Prisma.SortOrder
fullName?: Prisma.SortOrder fullName?: Prisma.SortOrder
nik?: Prisma.SortOrder nikEncrypted?: Prisma.SortOrder
nikHash?: Prisma.SortOrder
birthDate?: Prisma.SortOrder birthDate?: Prisma.SortOrder
address?: Prisma.SortOrder address?: Prisma.SortOrder
ktpImageUrl?: Prisma.SortOrder ktpImageKey?: Prisma.SortOrder
selfieUrl?: Prisma.SortOrder selfieKey?: Prisma.SortOrder
bankName?: Prisma.SortOrder bankName?: Prisma.SortOrder
bankAccountNumber?: Prisma.SortOrder bankAccountNumber?: Prisma.SortOrder
bankAccountName?: Prisma.SortOrder bankAccountName?: Prisma.SortOrder
@@ -316,15 +325,16 @@ export type OrganizerVerificationOrderByWithRelationInput = {
export type OrganizerVerificationWhereUniqueInput = Prisma.AtLeast<{ export type OrganizerVerificationWhereUniqueInput = Prisma.AtLeast<{
id?: string id?: string
userId?: string userId?: string
nik?: string nikHash?: string
AND?: Prisma.OrganizerVerificationWhereInput | Prisma.OrganizerVerificationWhereInput[] AND?: Prisma.OrganizerVerificationWhereInput | Prisma.OrganizerVerificationWhereInput[]
OR?: Prisma.OrganizerVerificationWhereInput[] OR?: Prisma.OrganizerVerificationWhereInput[]
NOT?: Prisma.OrganizerVerificationWhereInput | Prisma.OrganizerVerificationWhereInput[] NOT?: Prisma.OrganizerVerificationWhereInput | Prisma.OrganizerVerificationWhereInput[]
fullName?: Prisma.StringFilter<"OrganizerVerification"> | string fullName?: Prisma.StringFilter<"OrganizerVerification"> | string
nikEncrypted?: Prisma.StringFilter<"OrganizerVerification"> | string
birthDate?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string birthDate?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string
address?: Prisma.StringFilter<"OrganizerVerification"> | string address?: Prisma.StringFilter<"OrganizerVerification"> | string
ktpImageUrl?: Prisma.StringFilter<"OrganizerVerification"> | string ktpImageKey?: Prisma.StringFilter<"OrganizerVerification"> | string
selfieUrl?: Prisma.StringFilter<"OrganizerVerification"> | string selfieKey?: Prisma.StringFilter<"OrganizerVerification"> | string
bankName?: Prisma.StringFilter<"OrganizerVerification"> | string bankName?: Prisma.StringFilter<"OrganizerVerification"> | string
bankAccountNumber?: Prisma.StringFilter<"OrganizerVerification"> | string bankAccountNumber?: Prisma.StringFilter<"OrganizerVerification"> | string
bankAccountName?: Prisma.StringFilter<"OrganizerVerification"> | string bankAccountName?: Prisma.StringFilter<"OrganizerVerification"> | string
@@ -337,17 +347,18 @@ export type OrganizerVerificationWhereUniqueInput = Prisma.AtLeast<{
updatedAt?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string updatedAt?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string
user?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput> user?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
reviewedBy?: Prisma.XOR<Prisma.UserNullableScalarRelationFilter, Prisma.UserWhereInput> | null reviewedBy?: Prisma.XOR<Prisma.UserNullableScalarRelationFilter, Prisma.UserWhereInput> | null
}, "id" | "userId" | "nik"> }, "id" | "userId" | "nikHash">
export type OrganizerVerificationOrderByWithAggregationInput = { export type OrganizerVerificationOrderByWithAggregationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
userId?: Prisma.SortOrder userId?: Prisma.SortOrder
fullName?: Prisma.SortOrder fullName?: Prisma.SortOrder
nik?: Prisma.SortOrder nikEncrypted?: Prisma.SortOrder
nikHash?: Prisma.SortOrder
birthDate?: Prisma.SortOrder birthDate?: Prisma.SortOrder
address?: Prisma.SortOrder address?: Prisma.SortOrder
ktpImageUrl?: Prisma.SortOrder ktpImageKey?: Prisma.SortOrder
selfieUrl?: Prisma.SortOrder selfieKey?: Prisma.SortOrder
bankName?: Prisma.SortOrder bankName?: Prisma.SortOrder
bankAccountNumber?: Prisma.SortOrder bankAccountNumber?: Prisma.SortOrder
bankAccountName?: Prisma.SortOrder bankAccountName?: Prisma.SortOrder
@@ -370,11 +381,12 @@ export type OrganizerVerificationScalarWhereWithAggregatesInput = {
id?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string id?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
userId?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string userId?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
fullName?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string fullName?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
nik?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string nikEncrypted?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
nikHash?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
birthDate?: Prisma.DateTimeWithAggregatesFilter<"OrganizerVerification"> | Date | string birthDate?: Prisma.DateTimeWithAggregatesFilter<"OrganizerVerification"> | Date | string
address?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string address?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
ktpImageUrl?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string ktpImageKey?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
selfieUrl?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string selfieKey?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
bankName?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string bankName?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
bankAccountNumber?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string bankAccountNumber?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
bankAccountName?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string bankAccountName?: Prisma.StringWithAggregatesFilter<"OrganizerVerification"> | string
@@ -390,11 +402,12 @@ export type OrganizerVerificationScalarWhereWithAggregatesInput = {
export type OrganizerVerificationCreateInput = { export type OrganizerVerificationCreateInput = {
id?: string id?: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -412,11 +425,12 @@ export type OrganizerVerificationUncheckedCreateInput = {
id?: string id?: string
userId: string userId: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -432,11 +446,12 @@ export type OrganizerVerificationUncheckedCreateInput = {
export type OrganizerVerificationUpdateInput = { export type OrganizerVerificationUpdateInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -454,11 +469,12 @@ export type OrganizerVerificationUncheckedUpdateInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
userId?: Prisma.StringFieldUpdateOperationsInput | string userId?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -475,11 +491,12 @@ export type OrganizerVerificationCreateManyInput = {
id?: string id?: string
userId: string userId: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -495,11 +512,12 @@ export type OrganizerVerificationCreateManyInput = {
export type OrganizerVerificationUpdateManyMutationInput = { export type OrganizerVerificationUpdateManyMutationInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -515,11 +533,12 @@ export type OrganizerVerificationUncheckedUpdateManyInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
userId?: Prisma.StringFieldUpdateOperationsInput | string userId?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -551,11 +570,12 @@ export type OrganizerVerificationCountOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
userId?: Prisma.SortOrder userId?: Prisma.SortOrder
fullName?: Prisma.SortOrder fullName?: Prisma.SortOrder
nik?: Prisma.SortOrder nikEncrypted?: Prisma.SortOrder
nikHash?: Prisma.SortOrder
birthDate?: Prisma.SortOrder birthDate?: Prisma.SortOrder
address?: Prisma.SortOrder address?: Prisma.SortOrder
ktpImageUrl?: Prisma.SortOrder ktpImageKey?: Prisma.SortOrder
selfieUrl?: Prisma.SortOrder selfieKey?: Prisma.SortOrder
bankName?: Prisma.SortOrder bankName?: Prisma.SortOrder
bankAccountNumber?: Prisma.SortOrder bankAccountNumber?: Prisma.SortOrder
bankAccountName?: Prisma.SortOrder bankAccountName?: Prisma.SortOrder
@@ -572,11 +592,12 @@ export type OrganizerVerificationMaxOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
userId?: Prisma.SortOrder userId?: Prisma.SortOrder
fullName?: Prisma.SortOrder fullName?: Prisma.SortOrder
nik?: Prisma.SortOrder nikEncrypted?: Prisma.SortOrder
nikHash?: Prisma.SortOrder
birthDate?: Prisma.SortOrder birthDate?: Prisma.SortOrder
address?: Prisma.SortOrder address?: Prisma.SortOrder
ktpImageUrl?: Prisma.SortOrder ktpImageKey?: Prisma.SortOrder
selfieUrl?: Prisma.SortOrder selfieKey?: Prisma.SortOrder
bankName?: Prisma.SortOrder bankName?: Prisma.SortOrder
bankAccountNumber?: Prisma.SortOrder bankAccountNumber?: Prisma.SortOrder
bankAccountName?: Prisma.SortOrder bankAccountName?: Prisma.SortOrder
@@ -593,11 +614,12 @@ export type OrganizerVerificationMinOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
userId?: Prisma.SortOrder userId?: Prisma.SortOrder
fullName?: Prisma.SortOrder fullName?: Prisma.SortOrder
nik?: Prisma.SortOrder nikEncrypted?: Prisma.SortOrder
nikHash?: Prisma.SortOrder
birthDate?: Prisma.SortOrder birthDate?: Prisma.SortOrder
address?: Prisma.SortOrder address?: Prisma.SortOrder
ktpImageUrl?: Prisma.SortOrder ktpImageKey?: Prisma.SortOrder
selfieUrl?: Prisma.SortOrder selfieKey?: Prisma.SortOrder
bankName?: Prisma.SortOrder bankName?: Prisma.SortOrder
bankAccountNumber?: Prisma.SortOrder bankAccountNumber?: Prisma.SortOrder
bankAccountName?: Prisma.SortOrder bankAccountName?: Prisma.SortOrder
@@ -691,11 +713,12 @@ export type EnumVerificationStatusFieldUpdateOperationsInput = {
export type OrganizerVerificationCreateWithoutUserInput = { export type OrganizerVerificationCreateWithoutUserInput = {
id?: string id?: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -711,11 +734,12 @@ export type OrganizerVerificationCreateWithoutUserInput = {
export type OrganizerVerificationUncheckedCreateWithoutUserInput = { export type OrganizerVerificationUncheckedCreateWithoutUserInput = {
id?: string id?: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -736,11 +760,12 @@ export type OrganizerVerificationCreateOrConnectWithoutUserInput = {
export type OrganizerVerificationCreateWithoutReviewedByInput = { export type OrganizerVerificationCreateWithoutReviewedByInput = {
id?: string id?: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -757,11 +782,12 @@ export type OrganizerVerificationUncheckedCreateWithoutReviewedByInput = {
id?: string id?: string
userId: string userId: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -797,11 +823,12 @@ export type OrganizerVerificationUpdateToOneWithWhereWithoutUserInput = {
export type OrganizerVerificationUpdateWithoutUserInput = { export type OrganizerVerificationUpdateWithoutUserInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -817,11 +844,12 @@ export type OrganizerVerificationUpdateWithoutUserInput = {
export type OrganizerVerificationUncheckedUpdateWithoutUserInput = { export type OrganizerVerificationUncheckedUpdateWithoutUserInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -857,11 +885,12 @@ export type OrganizerVerificationScalarWhereInput = {
id?: Prisma.StringFilter<"OrganizerVerification"> | string id?: Prisma.StringFilter<"OrganizerVerification"> | string
userId?: Prisma.StringFilter<"OrganizerVerification"> | string userId?: Prisma.StringFilter<"OrganizerVerification"> | string
fullName?: Prisma.StringFilter<"OrganizerVerification"> | string fullName?: Prisma.StringFilter<"OrganizerVerification"> | string
nik?: Prisma.StringFilter<"OrganizerVerification"> | string nikEncrypted?: Prisma.StringFilter<"OrganizerVerification"> | string
nikHash?: Prisma.StringFilter<"OrganizerVerification"> | string
birthDate?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string birthDate?: Prisma.DateTimeFilter<"OrganizerVerification"> | Date | string
address?: Prisma.StringFilter<"OrganizerVerification"> | string address?: Prisma.StringFilter<"OrganizerVerification"> | string
ktpImageUrl?: Prisma.StringFilter<"OrganizerVerification"> | string ktpImageKey?: Prisma.StringFilter<"OrganizerVerification"> | string
selfieUrl?: Prisma.StringFilter<"OrganizerVerification"> | string selfieKey?: Prisma.StringFilter<"OrganizerVerification"> | string
bankName?: Prisma.StringFilter<"OrganizerVerification"> | string bankName?: Prisma.StringFilter<"OrganizerVerification"> | string
bankAccountNumber?: Prisma.StringFilter<"OrganizerVerification"> | string bankAccountNumber?: Prisma.StringFilter<"OrganizerVerification"> | string
bankAccountName?: Prisma.StringFilter<"OrganizerVerification"> | string bankAccountName?: Prisma.StringFilter<"OrganizerVerification"> | string
@@ -878,11 +907,12 @@ export type OrganizerVerificationCreateManyReviewedByInput = {
id?: string id?: string
userId: string userId: string
fullName: string fullName: string
nik: string nikEncrypted: string
nikHash: string
birthDate: Date | string birthDate: Date | string
address: string address: string
ktpImageUrl: string ktpImageKey: string
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -897,11 +927,12 @@ export type OrganizerVerificationCreateManyReviewedByInput = {
export type OrganizerVerificationUpdateWithoutReviewedByInput = { export type OrganizerVerificationUpdateWithoutReviewedByInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -918,11 +949,12 @@ export type OrganizerVerificationUncheckedUpdateWithoutReviewedByInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
userId?: Prisma.StringFieldUpdateOperationsInput | string userId?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -938,11 +970,12 @@ export type OrganizerVerificationUncheckedUpdateManyWithoutReviewedByInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
userId?: Prisma.StringFieldUpdateOperationsInput | string userId?: Prisma.StringFieldUpdateOperationsInput | string
fullName?: Prisma.StringFieldUpdateOperationsInput | string fullName?: Prisma.StringFieldUpdateOperationsInput | string
nik?: Prisma.StringFieldUpdateOperationsInput | string nikEncrypted?: Prisma.StringFieldUpdateOperationsInput | string
nikHash?: Prisma.StringFieldUpdateOperationsInput | string
birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string birthDate?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
address?: Prisma.StringFieldUpdateOperationsInput | string address?: Prisma.StringFieldUpdateOperationsInput | string
ktpImageUrl?: Prisma.StringFieldUpdateOperationsInput | string ktpImageKey?: Prisma.StringFieldUpdateOperationsInput | string
selfieUrl?: Prisma.StringFieldUpdateOperationsInput | string selfieKey?: Prisma.StringFieldUpdateOperationsInput | string
bankName?: Prisma.StringFieldUpdateOperationsInput | string bankName?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string bankAccountNumber?: Prisma.StringFieldUpdateOperationsInput | string
bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string bankAccountName?: Prisma.StringFieldUpdateOperationsInput | string
@@ -960,11 +993,12 @@ export type OrganizerVerificationSelect<ExtArgs extends runtime.Types.Extensions
id?: boolean id?: boolean
userId?: boolean userId?: boolean
fullName?: boolean fullName?: boolean
nik?: boolean nikEncrypted?: boolean
nikHash?: boolean
birthDate?: boolean birthDate?: boolean
address?: boolean address?: boolean
ktpImageUrl?: boolean ktpImageKey?: boolean
selfieUrl?: boolean selfieKey?: boolean
bankName?: boolean bankName?: boolean
bankAccountNumber?: boolean bankAccountNumber?: boolean
bankAccountName?: boolean bankAccountName?: boolean
@@ -983,11 +1017,12 @@ export type OrganizerVerificationSelectCreateManyAndReturn<ExtArgs extends runti
id?: boolean id?: boolean
userId?: boolean userId?: boolean
fullName?: boolean fullName?: boolean
nik?: boolean nikEncrypted?: boolean
nikHash?: boolean
birthDate?: boolean birthDate?: boolean
address?: boolean address?: boolean
ktpImageUrl?: boolean ktpImageKey?: boolean
selfieUrl?: boolean selfieKey?: boolean
bankName?: boolean bankName?: boolean
bankAccountNumber?: boolean bankAccountNumber?: boolean
bankAccountName?: boolean bankAccountName?: boolean
@@ -1006,11 +1041,12 @@ export type OrganizerVerificationSelectUpdateManyAndReturn<ExtArgs extends runti
id?: boolean id?: boolean
userId?: boolean userId?: boolean
fullName?: boolean fullName?: boolean
nik?: boolean nikEncrypted?: boolean
nikHash?: boolean
birthDate?: boolean birthDate?: boolean
address?: boolean address?: boolean
ktpImageUrl?: boolean ktpImageKey?: boolean
selfieUrl?: boolean selfieKey?: boolean
bankName?: boolean bankName?: boolean
bankAccountNumber?: boolean bankAccountNumber?: boolean
bankAccountName?: boolean bankAccountName?: boolean
@@ -1029,11 +1065,12 @@ export type OrganizerVerificationSelectScalar = {
id?: boolean id?: boolean
userId?: boolean userId?: boolean
fullName?: boolean fullName?: boolean
nik?: boolean nikEncrypted?: boolean
nikHash?: boolean
birthDate?: boolean birthDate?: boolean
address?: boolean address?: boolean
ktpImageUrl?: boolean ktpImageKey?: boolean
selfieUrl?: boolean selfieKey?: boolean
bankName?: boolean bankName?: boolean
bankAccountNumber?: boolean bankAccountNumber?: boolean
bankAccountName?: boolean bankAccountName?: boolean
@@ -1046,7 +1083,7 @@ export type OrganizerVerificationSelectScalar = {
updatedAt?: boolean updatedAt?: boolean
} }
export type OrganizerVerificationOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "fullName" | "nik" | "birthDate" | "address" | "ktpImageUrl" | "selfieUrl" | "bankName" | "bankAccountNumber" | "bankAccountName" | "status" | "rejectionReason" | "reviewedAt" | "reviewedById" | "verifiedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["organizerVerification"]> export type OrganizerVerificationOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "fullName" | "nikEncrypted" | "nikHash" | "birthDate" | "address" | "ktpImageKey" | "selfieKey" | "bankName" | "bankAccountNumber" | "bankAccountName" | "status" | "rejectionReason" | "reviewedAt" | "reviewedById" | "verifiedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["organizerVerification"]>
export type OrganizerVerificationInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type OrganizerVerificationInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
user?: boolean | Prisma.UserDefaultArgs<ExtArgs> user?: boolean | Prisma.UserDefaultArgs<ExtArgs>
reviewedBy?: boolean | Prisma.OrganizerVerification$reviewedByArgs<ExtArgs> reviewedBy?: boolean | Prisma.OrganizerVerification$reviewedByArgs<ExtArgs>
@@ -1074,19 +1111,23 @@ export type $OrganizerVerificationPayload<ExtArgs extends runtime.Types.Extensio
*/ */
fullName: string fullName: string
/** /**
* Nomor Induk Kependudukan (PII — perlakukan sensitif) * NIK terenkripsi (AES-256-GCM, base64). Plaintext tidak disimpan.
*/ */
nik: string nikEncrypted: string
/**
* HMAC-SHA256(NIK + pepper) untuk uniqueness lookup tanpa membuka plaintext.
*/
nikHash: string
birthDate: Date birthDate: Date
address: string address: string
/** /**
* URL foto KTP (untuk MVP pakai hosting; pindah ke storage privat untuk produksi) * Storage key foto KTP (mis. `ktp/<id>.jpg`). File disimpan terenkripsi di luar /public.
*/ */
ktpImageUrl: string ktpImageKey: string
/** /**
* URL selfie memegang KTP * Storage key selfie memegang KTP.
*/ */
selfieUrl: string selfieKey: string
bankName: string bankName: string
bankAccountNumber: string bankAccountNumber: string
bankAccountName: string bankAccountName: string
@@ -1525,11 +1566,12 @@ export interface OrganizerVerificationFieldRefs {
readonly id: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly id: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly userId: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly userId: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly fullName: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly fullName: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly nik: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly nikEncrypted: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly nikHash: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly birthDate: Prisma.FieldRef<"OrganizerVerification", 'DateTime'> readonly birthDate: Prisma.FieldRef<"OrganizerVerification", 'DateTime'>
readonly address: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly address: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly ktpImageUrl: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly ktpImageKey: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly selfieUrl: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly selfieKey: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly bankName: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly bankName: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly bankAccountNumber: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly bankAccountNumber: Prisma.FieldRef<"OrganizerVerification", 'String'>
readonly bankAccountName: Prisma.FieldRef<"OrganizerVerification", 'String'> readonly bankAccountName: Prisma.FieldRef<"OrganizerVerification", 'String'>
+200 -35
View File
@@ -175,7 +175,7 @@ export type UserGroupByOutputType = {
id: string id: string
name: string name: string
email: string email: string
password: string password: string | null
image: string | null image: string | null
acceptedTermsAndPrivacy: boolean acceptedTermsAndPrivacy: boolean
acceptedAt: Date | null acceptedAt: Date | null
@@ -208,12 +208,13 @@ export type UserWhereInput = {
id?: Prisma.StringFilter<"User"> | string id?: Prisma.StringFilter<"User"> | string
name?: Prisma.StringFilter<"User"> | string name?: Prisma.StringFilter<"User"> | string
email?: Prisma.StringFilter<"User"> | string email?: Prisma.StringFilter<"User"> | string
password?: Prisma.StringFilter<"User"> | string password?: Prisma.StringNullableFilter<"User"> | string | null
image?: Prisma.StringNullableFilter<"User"> | string | null image?: Prisma.StringNullableFilter<"User"> | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFilter<"User"> | boolean acceptedTermsAndPrivacy?: Prisma.BoolFilter<"User"> | boolean
acceptedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null acceptedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
accounts?: Prisma.AccountListRelationFilter
trips?: Prisma.TripListRelationFilter trips?: Prisma.TripListRelationFilter
participations?: Prisma.TripParticipantListRelationFilter participations?: Prisma.TripParticipantListRelationFilter
tripReviews?: Prisma.TripReviewListRelationFilter tripReviews?: Prisma.TripReviewListRelationFilter
@@ -225,12 +226,13 @@ export type UserOrderByWithRelationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
email?: Prisma.SortOrder email?: Prisma.SortOrder
password?: Prisma.SortOrder password?: Prisma.SortOrderInput | Prisma.SortOrder
image?: Prisma.SortOrderInput | Prisma.SortOrder image?: Prisma.SortOrderInput | Prisma.SortOrder
acceptedTermsAndPrivacy?: Prisma.SortOrder acceptedTermsAndPrivacy?: Prisma.SortOrder
acceptedAt?: Prisma.SortOrderInput | Prisma.SortOrder acceptedAt?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
accounts?: Prisma.AccountOrderByRelationAggregateInput
trips?: Prisma.TripOrderByRelationAggregateInput trips?: Prisma.TripOrderByRelationAggregateInput
participations?: Prisma.TripParticipantOrderByRelationAggregateInput participations?: Prisma.TripParticipantOrderByRelationAggregateInput
tripReviews?: Prisma.TripReviewOrderByRelationAggregateInput tripReviews?: Prisma.TripReviewOrderByRelationAggregateInput
@@ -245,12 +247,13 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
OR?: Prisma.UserWhereInput[] OR?: Prisma.UserWhereInput[]
NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[]
name?: Prisma.StringFilter<"User"> | string name?: Prisma.StringFilter<"User"> | string
password?: Prisma.StringFilter<"User"> | string password?: Prisma.StringNullableFilter<"User"> | string | null
image?: Prisma.StringNullableFilter<"User"> | string | null image?: Prisma.StringNullableFilter<"User"> | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFilter<"User"> | boolean acceptedTermsAndPrivacy?: Prisma.BoolFilter<"User"> | boolean
acceptedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null acceptedAt?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string
accounts?: Prisma.AccountListRelationFilter
trips?: Prisma.TripListRelationFilter trips?: Prisma.TripListRelationFilter
participations?: Prisma.TripParticipantListRelationFilter participations?: Prisma.TripParticipantListRelationFilter
tripReviews?: Prisma.TripReviewListRelationFilter tripReviews?: Prisma.TripReviewListRelationFilter
@@ -262,7 +265,7 @@ export type UserOrderByWithAggregationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
email?: Prisma.SortOrder email?: Prisma.SortOrder
password?: Prisma.SortOrder password?: Prisma.SortOrderInput | Prisma.SortOrder
image?: Prisma.SortOrderInput | Prisma.SortOrder image?: Prisma.SortOrderInput | Prisma.SortOrder
acceptedTermsAndPrivacy?: Prisma.SortOrder acceptedTermsAndPrivacy?: Prisma.SortOrder
acceptedAt?: Prisma.SortOrderInput | Prisma.SortOrder acceptedAt?: Prisma.SortOrderInput | Prisma.SortOrder
@@ -280,7 +283,7 @@ export type UserScalarWhereWithAggregatesInput = {
id?: Prisma.StringWithAggregatesFilter<"User"> | string id?: Prisma.StringWithAggregatesFilter<"User"> | string
name?: Prisma.StringWithAggregatesFilter<"User"> | string name?: Prisma.StringWithAggregatesFilter<"User"> | string
email?: Prisma.StringWithAggregatesFilter<"User"> | string email?: Prisma.StringWithAggregatesFilter<"User"> | string
password?: Prisma.StringWithAggregatesFilter<"User"> | string password?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null
acceptedTermsAndPrivacy?: Prisma.BoolWithAggregatesFilter<"User"> | boolean acceptedTermsAndPrivacy?: Prisma.BoolWithAggregatesFilter<"User"> | boolean
acceptedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null acceptedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null
@@ -292,12 +295,13 @@ export type UserCreateInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
@@ -309,12 +313,13 @@ export type UserUncheckedCreateInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
@@ -326,12 +331,13 @@ export type UserUpdateInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
@@ -343,12 +349,13 @@ export type UserUncheckedUpdateInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
@@ -360,7 +367,7 @@ export type UserCreateManyInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
@@ -372,7 +379,7 @@ export type UserUpdateManyMutationInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@@ -384,7 +391,7 @@ export type UserUncheckedUpdateManyInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@@ -458,6 +465,20 @@ export type DateTimeFieldUpdateOperationsInput = {
set?: Date | string set?: Date | string
} }
export type UserCreateNestedOneWithoutAccountsInput = {
create?: Prisma.XOR<Prisma.UserCreateWithoutAccountsInput, Prisma.UserUncheckedCreateWithoutAccountsInput>
connectOrCreate?: Prisma.UserCreateOrConnectWithoutAccountsInput
connect?: Prisma.UserWhereUniqueInput
}
export type UserUpdateOneRequiredWithoutAccountsNestedInput = {
create?: Prisma.XOR<Prisma.UserCreateWithoutAccountsInput, Prisma.UserUncheckedCreateWithoutAccountsInput>
connectOrCreate?: Prisma.UserCreateOrConnectWithoutAccountsInput
upsert?: Prisma.UserUpsertWithoutAccountsInput
connect?: Prisma.UserWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutAccountsInput, Prisma.UserUpdateWithoutAccountsInput>, Prisma.UserUncheckedUpdateWithoutAccountsInput>
}
export type UserCreateNestedOneWithoutOrganizerVerificationInput = { export type UserCreateNestedOneWithoutOrganizerVerificationInput = {
create?: Prisma.XOR<Prisma.UserCreateWithoutOrganizerVerificationInput, Prisma.UserUncheckedCreateWithoutOrganizerVerificationInput> create?: Prisma.XOR<Prisma.UserCreateWithoutOrganizerVerificationInput, Prisma.UserUncheckedCreateWithoutOrganizerVerificationInput>
connectOrCreate?: Prisma.UserCreateOrConnectWithoutOrganizerVerificationInput connectOrCreate?: Prisma.UserCreateOrConnectWithoutOrganizerVerificationInput
@@ -530,11 +551,11 @@ export type UserUpdateOneRequiredWithoutParticipationsNestedInput = {
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutParticipationsInput, Prisma.UserUpdateWithoutParticipationsInput>, Prisma.UserUncheckedUpdateWithoutParticipationsInput> update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutParticipationsInput, Prisma.UserUpdateWithoutParticipationsInput>, Prisma.UserUncheckedUpdateWithoutParticipationsInput>
} }
export type UserCreateWithoutOrganizerVerificationInput = { export type UserCreateWithoutAccountsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
@@ -543,6 +564,91 @@ export type UserCreateWithoutOrganizerVerificationInput = {
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
}
export type UserUncheckedCreateWithoutAccountsInput = {
id?: string
name: string
email: string
password?: string | null
image?: string | null
acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
}
export type UserCreateOrConnectWithoutAccountsInput = {
where: Prisma.UserWhereUniqueInput
create: Prisma.XOR<Prisma.UserCreateWithoutAccountsInput, Prisma.UserUncheckedCreateWithoutAccountsInput>
}
export type UserUpsertWithoutAccountsInput = {
update: Prisma.XOR<Prisma.UserUpdateWithoutAccountsInput, Prisma.UserUncheckedUpdateWithoutAccountsInput>
create: Prisma.XOR<Prisma.UserCreateWithoutAccountsInput, Prisma.UserUncheckedCreateWithoutAccountsInput>
where?: Prisma.UserWhereInput
}
export type UserUpdateToOneWithWhereWithoutAccountsInput = {
where?: Prisma.UserWhereInput
data: Prisma.XOR<Prisma.UserUpdateWithoutAccountsInput, Prisma.UserUncheckedUpdateWithoutAccountsInput>
}
export type UserUpdateWithoutAccountsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
}
export type UserUncheckedUpdateWithoutAccountsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
}
export type UserCreateWithoutOrganizerVerificationInput = {
id?: string
name: string
email: string
password?: string | null
image?: string | null
acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null
createdAt?: Date | string
updatedAt?: Date | string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
} }
@@ -550,12 +656,13 @@ export type UserUncheckedCreateWithoutOrganizerVerificationInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
@@ -571,12 +678,13 @@ export type UserCreateWithoutReviewedVerificationsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
@@ -587,12 +695,13 @@ export type UserUncheckedCreateWithoutReviewedVerificationsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
@@ -619,12 +728,13 @@ export type UserUpdateWithoutOrganizerVerificationInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
@@ -635,12 +745,13 @@ export type UserUncheckedUpdateWithoutOrganizerVerificationInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
@@ -662,12 +773,13 @@ export type UserUpdateWithoutReviewedVerificationsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
@@ -678,12 +790,13 @@ export type UserUncheckedUpdateWithoutReviewedVerificationsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
@@ -694,12 +807,13 @@ export type UserCreateWithoutTripsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
@@ -710,12 +824,13 @@ export type UserUncheckedCreateWithoutTripsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
@@ -742,12 +857,13 @@ export type UserUpdateWithoutTripsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
@@ -758,12 +874,13 @@ export type UserUncheckedUpdateWithoutTripsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
@@ -774,12 +891,13 @@ export type UserCreateWithoutTripReviewsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
@@ -790,12 +908,13 @@ export type UserUncheckedCreateWithoutTripReviewsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
@@ -822,12 +941,13 @@ export type UserUpdateWithoutTripReviewsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
@@ -838,12 +958,13 @@ export type UserUncheckedUpdateWithoutTripReviewsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
@@ -854,12 +975,13 @@ export type UserCreateWithoutParticipationsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
@@ -870,12 +992,13 @@ export type UserUncheckedCreateWithoutParticipationsInput = {
id?: string id?: string
name: string name: string
email: string email: string
password: string password?: string | null
image?: string | null image?: string | null
acceptedTermsAndPrivacy?: boolean acceptedTermsAndPrivacy?: boolean
acceptedAt?: Date | string | null acceptedAt?: Date | string | null
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
@@ -902,12 +1025,13 @@ export type UserUpdateWithoutParticipationsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
@@ -918,12 +1042,13 @@ export type UserUncheckedUpdateWithoutParticipationsInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
@@ -936,6 +1061,7 @@ export type UserUncheckedUpdateWithoutParticipationsInput = {
*/ */
export type UserCountOutputType = { export type UserCountOutputType = {
accounts: number
trips: number trips: number
participations: number participations: number
tripReviews: number tripReviews: number
@@ -943,6 +1069,7 @@ export type UserCountOutputType = {
} }
export type UserCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type UserCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
accounts?: boolean | UserCountOutputTypeCountAccountsArgs
trips?: boolean | UserCountOutputTypeCountTripsArgs trips?: boolean | UserCountOutputTypeCountTripsArgs
participations?: boolean | UserCountOutputTypeCountParticipationsArgs participations?: boolean | UserCountOutputTypeCountParticipationsArgs
tripReviews?: boolean | UserCountOutputTypeCountTripReviewsArgs tripReviews?: boolean | UserCountOutputTypeCountTripReviewsArgs
@@ -959,6 +1086,13 @@ export type UserCountOutputTypeDefaultArgs<ExtArgs extends runtime.Types.Extensi
select?: Prisma.UserCountOutputTypeSelect<ExtArgs> | null select?: Prisma.UserCountOutputTypeSelect<ExtArgs> | null
} }
/**
* UserCountOutputType without action
*/
export type UserCountOutputTypeCountAccountsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.AccountWhereInput
}
/** /**
* UserCountOutputType without action * UserCountOutputType without action
*/ */
@@ -998,6 +1132,7 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
acceptedAt?: boolean acceptedAt?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
trips?: boolean | Prisma.User$tripsArgs<ExtArgs> trips?: boolean | Prisma.User$tripsArgs<ExtArgs>
participations?: boolean | Prisma.User$participationsArgs<ExtArgs> participations?: boolean | Prisma.User$participationsArgs<ExtArgs>
tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs> tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs>
@@ -1044,6 +1179,7 @@ export type UserSelectScalar = {
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "image" | "acceptedTermsAndPrivacy" | "acceptedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]> export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "image" | "acceptedTermsAndPrivacy" | "acceptedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]>
export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
accounts?: boolean | Prisma.User$accountsArgs<ExtArgs>
trips?: boolean | Prisma.User$tripsArgs<ExtArgs> trips?: boolean | Prisma.User$tripsArgs<ExtArgs>
participations?: boolean | Prisma.User$participationsArgs<ExtArgs> participations?: boolean | Prisma.User$participationsArgs<ExtArgs>
tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs> tripReviews?: boolean | Prisma.User$tripReviewsArgs<ExtArgs>
@@ -1057,6 +1193,7 @@ export type UserIncludeUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensi
export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
name: "User" name: "User"
objects: { objects: {
accounts: Prisma.$AccountPayload<ExtArgs>[]
trips: Prisma.$TripPayload<ExtArgs>[] trips: Prisma.$TripPayload<ExtArgs>[]
participations: Prisma.$TripParticipantPayload<ExtArgs>[] participations: Prisma.$TripParticipantPayload<ExtArgs>[]
tripReviews: Prisma.$TripReviewPayload<ExtArgs>[] tripReviews: Prisma.$TripReviewPayload<ExtArgs>[]
@@ -1067,7 +1204,10 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
id: string id: string
name: string name: string
email: string email: string
password: string /**
* Hash bcrypt. Null untuk user yang sign-in via OAuth (mis. Google).
*/
password: string | null
image: string | null image: string | null
/** /**
* Apakah user telah menyetujui Syarat & Ketentuan dan Kebijakan Privasi * Apakah user telah menyetujui Syarat & Ketentuan dan Kebijakan Privasi
@@ -1473,6 +1613,7 @@ readonly fields: UserFieldRefs;
*/ */
export interface Prisma__UserClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> { export interface Prisma__UserClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> {
readonly [Symbol.toStringTag]: "PrismaPromise" readonly [Symbol.toStringTag]: "PrismaPromise"
accounts<T extends Prisma.User$accountsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$accountsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$AccountPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
trips<T extends Prisma.User$tripsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$tripsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null> trips<T extends Prisma.User$tripsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$tripsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
participations<T extends Prisma.User$participationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$participationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripParticipantPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null> participations<T extends Prisma.User$participationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$participationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripParticipantPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
tripReviews<T extends Prisma.User$tripReviewsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$tripReviewsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripReviewPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null> tripReviews<T extends Prisma.User$tripReviewsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$tripReviewsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$TripReviewPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
@@ -1908,6 +2049,30 @@ export type UserDeleteManyArgs<ExtArgs extends runtime.Types.Extensions.Internal
limit?: number limit?: number
} }
/**
* User.accounts
*/
export type User$accountsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the Account
*/
select?: Prisma.AccountSelect<ExtArgs> | null
/**
* Omit specific fields from the Account
*/
omit?: Prisma.AccountOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.AccountInclude<ExtArgs> | null
where?: Prisma.AccountWhereInput
orderBy?: Prisma.AccountOrderByWithRelationInput | Prisma.AccountOrderByWithRelationInput[]
cursor?: Prisma.AccountWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.AccountScalarFieldEnum | Prisma.AccountScalarFieldEnum[]
}
/** /**
* User.trips * User.trips
*/ */
+9
View File
@@ -5,6 +5,7 @@ import { signIn } from "next-auth/react";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { GoogleSignInButton } from "@/components/shared/google-sign-in-button";
function safeInternalPath(raw: string | null): string { function safeInternalPath(raw: string | null): string {
if (!raw || !raw.startsWith("/") || raw.startsWith("//")) return "/"; if (!raw || !raw.startsWith("/") || raw.startsWith("//")) return "/";
@@ -84,6 +85,14 @@ function LoginForm() {
</div> </div>
)} )}
<GoogleSignInButton callbackUrl={safeInternalPath(searchParams.get("callbackUrl"))} />
<div className="my-4 flex items-center gap-3 text-xs text-neutral-400">
<span className="h-px flex-1 bg-neutral-200" />
<span>atau</span>
<span className="h-px flex-1 bg-neutral-200" />
</div>
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div> <div>
<label htmlFor="email" className="mb-1.5 block text-sm font-semibold text-neutral-700"> <label htmlFor="email" className="mb-1.5 block text-sm font-semibold text-neutral-700">
+9
View File
@@ -6,6 +6,7 @@ import { signIn } from "next-auth/react";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { registerAction } from "@/features/auth/actions"; import { registerAction } from "@/features/auth/actions";
import { GoogleSignInButton } from "@/components/shared/google-sign-in-button";
export default function RegisterPage() { export default function RegisterPage() {
const router = useRouter(); const router = useRouter();
@@ -83,6 +84,14 @@ export default function RegisterPage() {
</div> </div>
)} )}
<GoogleSignInButton label="Daftar dengan Google" />
<div className="my-4 flex items-center gap-3 text-xs text-neutral-400">
<span className="h-px flex-1 bg-neutral-200" />
<span>atau</span>
<span className="h-px flex-1 bg-neutral-200" />
</div>
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div> <div>
<label htmlFor="name" className="mb-1.5 block text-sm font-semibold text-neutral-700"> <label htmlFor="name" className="mb-1.5 block text-sm font-semibold text-neutral-700">
+15 -1
View File
@@ -14,6 +14,20 @@ export default async function VerifyPage() {
const verification = await organizerService.getStatusForUser(session.user.id); const verification = await organizerService.getStatusForUser(session.user.id);
const initial = verification
? {
fullName: verification.fullName,
nik: organizerService.decryptNik(verification.nikEncrypted),
birthDate: verification.birthDate,
address: verification.address,
ktpImageKey: verification.ktpImageKey,
selfieKey: verification.selfieKey,
bankName: verification.bankName,
bankAccountNumber: verification.bankAccountNumber,
bankAccountName: verification.bankAccountName,
}
: null;
return ( return (
<div className="mx-auto max-w-2xl px-4 py-8 sm:py-12"> <div className="mx-auto max-w-2xl px-4 py-8 sm:py-12">
<div className="mb-6"> <div className="mb-6">
@@ -66,7 +80,7 @@ export default async function VerifyPage() {
)} )}
{verification?.status !== "APPROVED" && verification?.status !== "PENDING" && ( {verification?.status !== "APPROVED" && verification?.status !== "PENDING" && (
<VerifyForm initial={verification ?? null} /> <VerifyForm initial={initial} />
)} )}
<p className="mt-6 text-center text-sm text-neutral-500"> <p className="mt-6 text-center text-sm text-neutral-500">
@@ -0,0 +1,46 @@
"use client";
import { signIn } from "next-auth/react";
import { useState } from "react";
export function GoogleSignInButton({
callbackUrl = "/",
label = "Lanjutkan dengan Google",
}: {
callbackUrl?: string;
label?: string;
}) {
const [loading, setLoading] = useState(false);
return (
<button
type="button"
disabled={loading}
onClick={() => {
setLoading(true);
signIn("google", { callbackUrl });
}}
className="flex w-full items-center justify-center gap-2 rounded-xl border border-neutral-200 bg-white py-2.5 text-sm font-semibold text-neutral-700 shadow-sm transition-colors hover:bg-neutral-50 disabled:opacity-50"
>
<svg width="18" height="18" viewBox="0 0 18 18" aria-hidden>
<path
fill="#4285F4"
d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.13 4.13 0 0 1-1.79 2.71v2.26h2.9c1.7-1.57 2.69-3.88 2.69-6.61z"
/>
<path
fill="#34A853"
d="M9 18c2.43 0 4.47-.81 5.96-2.18l-2.9-2.26c-.8.54-1.83.86-3.06.86-2.35 0-4.34-1.59-5.05-3.72H.96v2.34A9 9 0 0 0 9 18z"
/>
<path
fill="#FBBC05"
d="M3.95 10.7A5.41 5.41 0 0 1 3.66 9c0-.59.1-1.16.29-1.7V4.96H.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.04l2.99-2.34z"
/>
<path
fill="#EA4335"
d="M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58A9 9 0 0 0 9 0 9 9 0 0 0 .96 4.96l2.99 2.34C4.66 5.17 6.65 3.58 9 3.58z"
/>
</svg>
{loading ? "Menghubungkan..." : label}
</button>
);
}
-2
View File
@@ -1,5 +1,3 @@
version: "3.9"
services: services:
postgres: postgres:
image: postgres:15 image: postgres:15
+12
View File
@@ -3,3 +3,15 @@ NEXTAUTH_SECRET="3GaP/mqi1IYbafyLfyI54ouPRDE0IUK5vFqpKJQM5hg="
NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_URL="http://localhost:3000"
NEXT_PUBLIC_SITE_URL="https://arifal.imola.ai" NEXT_PUBLIC_SITE_URL="https://arifal.imola.ai"
ADMIN_EMAILS=admin@setrip.id ADMIN_EMAILS=admin@setrip.id
# 32-byte key (hex) for AES-256-GCM encryption of KYC data (NIK + KTP/selfie files)
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
KYC_ENCRYPTION_KEY=
# 32-byte hex secret used as HMAC pepper for NIK uniqueness lookup
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
KYC_NIK_PEPPER=
# Absolute path for private KYC uploads (default: <cwd>/uploads/private)
KYC_UPLOAD_DIR=
GOOGLE_CLIENT_ID="xxxxxxxx"
GOOGLE_CLIENT_SECRET="xxxxxxxx"
+16
View File
@@ -1,7 +1,10 @@
"use server"; "use server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { registerSchema } from "./schemas"; import { registerSchema } from "./schemas";
import { authService } from "@/server/services/auth.service"; import { authService } from "@/server/services/auth.service";
import { userRepo } from "@/server/repositories/user.repo";
export async function registerAction(formData: FormData) { export async function registerAction(formData: FormData) {
const raw = { const raw = {
@@ -29,3 +32,16 @@ export async function registerAction(formData: FormData) {
return { error: (err as Error).message }; return { error: (err as Error).message };
} }
} }
export async function acceptTermsAction() {
const session = await getServerSession(authOptions);
if (!session?.user) {
return { error: "Kamu harus login terlebih dahulu" };
}
try {
await userRepo.markAcceptedTerms(session.user.id);
return { success: true };
} catch (err) {
return { error: (err as Error).message };
}
}
+2 -2
View File
@@ -18,8 +18,8 @@ export async function submitVerificationAction(formData: FormData) {
nik: formData.get("nik") as string, nik: formData.get("nik") as string,
birthDate: formData.get("birthDate") as string, birthDate: formData.get("birthDate") as string,
address: formData.get("address") as string, address: formData.get("address") as string,
ktpImageUrl: formData.get("ktpImageUrl") as string, ktpImageKey: formData.get("ktpImageKey") as string,
selfieUrl: formData.get("selfieUrl") as string, selfieKey: formData.get("selfieKey") as string,
bankName: formData.get("bankName") as string, bankName: formData.get("bankName") as string,
bankAccountNumber: formData.get("bankAccountNumber") as string, bankAccountNumber: formData.get("bankAccountNumber") as string,
bankAccountName: formData.get("bankAccountName") as string, bankAccountName: formData.get("bankAccountName") as string,
+16 -13
View File
@@ -2,17 +2,15 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import Image from "next/image";
import { reviewVerificationAction } from "@/features/organizer/actions"; import { reviewVerificationAction } from "@/features/organizer/actions";
type Verification = { type Verification = {
id: string; id: string;
fullName: string; fullName: string;
/** NIK plaintext, sudah di-decrypt di server sebelum sampai ke komponen ini. */
nik: string; nik: string;
birthDate: Date; birthDate: Date;
address: string; address: string;
ktpImageUrl: string;
selfieUrl: string;
bankName: string; bankName: string;
bankAccountNumber: string; bankAccountNumber: string;
bankAccountName: string; bankAccountName: string;
@@ -90,8 +88,14 @@ export function ReviewCard({ verification }: { verification: Verification }) {
</div> </div>
<div className="mt-5 grid gap-4 sm:grid-cols-2"> <div className="mt-5 grid gap-4 sm:grid-cols-2">
<ImagePreview label="Foto KTP" url={verification.ktpImageUrl} /> <ImagePreview
<ImagePreview label="Selfie + KTP" url={verification.selfieUrl} /> label="Foto KTP"
src={`/api/files/kyc/${verification.id}/ktp`}
/>
<ImagePreview
label="Selfie + KTP"
src={`/api/files/kyc/${verification.id}/selfie`}
/>
</div> </div>
{verification.status === "REJECTED" && verification.rejectionReason && ( {verification.status === "REJECTED" && verification.rejectionReason && (
@@ -196,26 +200,25 @@ function Field({
); );
} }
function ImagePreview({ label, url }: { label: string; url: string }) { function ImagePreview({ label, src }: { label: string; src: string }) {
return ( return (
<div> <div>
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-neutral-500"> <p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-neutral-500">
{label} {label}
</p> </p>
<a <a
href={url} href={src}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="block overflow-hidden rounded-xl border border-neutral-200 bg-neutral-100" className="block overflow-hidden rounded-xl border border-neutral-200 bg-neutral-100"
> >
<div className="relative aspect-[4/3] w-full"> <div className="relative aspect-[4/3] w-full">
<Image {/* Secure endpoint sends Cache-Control: private,no-store. Use plain <img> to skip Next/Image optimizer. */}
src={url} {/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={src}
alt={label} alt={label}
fill className="h-full w-full object-cover"
unoptimized
className="object-cover"
sizes="(min-width: 640px) 50vw, 100vw"
/> />
</div> </div>
</a> </a>
+117 -28
View File
@@ -9,13 +9,18 @@ type Initial = {
nik: string; nik: string;
birthDate: Date; birthDate: Date;
address: string; address: string;
ktpImageUrl: string; ktpImageKey: string;
selfieUrl: string; selfieKey: string;
bankName: string; bankName: string;
bankAccountNumber: string; bankAccountNumber: string;
bankAccountName: string; bankAccountName: string;
} | null; } | null;
type UploadKind = "ktp" | "selfie";
const ACCEPT_MIME = "image/jpeg,image/png,image/webp";
const MAX_BYTES = 5 * 1024 * 1024;
function toYmd(d: Date): string { function toYmd(d: Date): string {
const y = d.getUTCFullYear(); const y = d.getUTCFullYear();
const m = String(d.getUTCMonth() + 1).padStart(2, "0"); const m = String(d.getUTCMonth() + 1).padStart(2, "0");
@@ -27,12 +32,20 @@ export function VerifyForm({ initial }: { initial: Initial }) {
const router = useRouter(); const router = useRouter();
const [error, setError] = useState(""); const [error, setError] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [ktpKey, setKtpKey] = useState(initial?.ktpImageKey ?? "");
const [selfieKey, setSelfieKey] = useState(initial?.selfieKey ?? "");
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) { async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault(); e.preventDefault();
setError(""); setError("");
if (!ktpKey || !selfieKey) {
setError("Foto KTP dan selfie wajib diunggah");
return;
}
setLoading(true); setLoading(true);
const formData = new FormData(e.currentTarget); const formData = new FormData(e.currentTarget);
formData.set("ktpImageKey", ktpKey);
formData.set("selfieKey", selfieKey);
const result = await submitVerificationAction(formData); const result = await submitVerificationAction(formData);
setLoading(false); setLoading(false);
if (result.error) { if (result.error) {
@@ -119,37 +132,25 @@ export function VerifyForm({ initial }: { initial: Initial }) {
<section> <section>
<h2 className="mb-3 text-base font-bold text-neutral-900">🖼 Foto</h2> <h2 className="mb-3 text-base font-bold text-neutral-900">🖼 Foto</h2>
<p className="mb-3 text-xs text-neutral-500"> <p className="mb-3 text-xs text-neutral-500">
Upload foto ke hosting (imgur, imgbb, dll) lalu paste URL-nya. Foto akan Foto disimpan terenkripsi di server SeTrip dan hanya bisa dilihat oleh
dilihat tim admin saat review. tim admin saat review. Maks 5MB, JPG/PNG/WebP.
</p> </p>
<div className="space-y-4"> <div className="space-y-4">
<div> <FileUpload
<label className="mb-1.5 block text-sm font-semibold text-neutral-700"> label="Foto KTP"
URL Foto KTP kind="ktp"
</label> value={ktpKey}
<input onChange={setKtpKey}
name="ktpImageUrl" onError={setError}
type="url"
required
defaultValue={initial?.ktpImageUrl ?? ""}
className={inputCls}
placeholder="https://i.imgur.com/xxxx.jpg"
/> />
</div> <FileUpload
<div> label="Selfie dengan KTP"
<label className="mb-1.5 block text-sm font-semibold text-neutral-700"> kind="selfie"
URL Selfie dengan KTP value={selfieKey}
</label> onChange={setSelfieKey}
<input onError={setError}
name="selfieUrl"
type="url"
required
defaultValue={initial?.selfieUrl ?? ""}
className={inputCls}
placeholder="https://i.imgur.com/yyyy.jpg"
/> />
</div> </div>
</div>
</section> </section>
<section> <section>
@@ -213,3 +214,91 @@ export function VerifyForm({ initial }: { initial: Initial }) {
</form> </form>
); );
} }
function FileUpload({
label,
kind,
value,
onChange,
onError,
}: {
label: string;
kind: UploadKind;
value: string;
onChange: (key: string) => void;
onError: (msg: string) => void;
}) {
const [busy, setBusy] = useState(false);
const [previewUrl, setPreviewUrl] = useState<string>("");
async function onPick(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (!file) return;
if (file.size > MAX_BYTES) {
onError(`${label} maksimal 5MB`);
e.target.value = "";
return;
}
if (!ACCEPT_MIME.split(",").includes(file.type)) {
onError(`${label} harus JPG, PNG, atau WebP`);
e.target.value = "";
return;
}
setBusy(true);
onError("");
try {
const fd = new FormData();
fd.set("kind", kind);
fd.set("file", file);
const res = await fetch("/api/upload/kyc", { method: "POST", body: fd });
const json = await res.json();
if (!res.ok) {
onError(json.error ?? `Gagal mengunggah ${label}`);
return;
}
onChange(json.key);
const obj = URL.createObjectURL(file);
setPreviewUrl((old) => {
if (old) URL.revokeObjectURL(old);
return obj;
});
} catch {
onError(`Gagal mengunggah ${label}`);
} finally {
setBusy(false);
e.target.value = "";
}
}
return (
<div>
<label className="mb-1.5 block text-sm font-semibold text-neutral-700">
{label}
</label>
<div className="flex items-center gap-3">
<label className="inline-flex cursor-pointer items-center rounded-xl border border-neutral-200 bg-neutral-50 px-4 py-2 text-sm font-medium text-neutral-700 hover:bg-neutral-100">
{busy ? "Mengunggah..." : value ? "Ganti file" : "Pilih file"}
<input
type="file"
accept={ACCEPT_MIME}
onChange={onPick}
disabled={busy}
className="sr-only"
/>
</label>
{value && !busy && (
<span className="text-xs text-neutral-500"> Terunggah</span>
)}
</div>
{previewUrl && (
// eslint-disable-next-line @next/next/no-img-element
<img
src={previewUrl}
alt={`${label} preview`}
className="mt-2 max-h-40 rounded-lg border border-neutral-200"
/>
)}
</div>
);
}
+4 -8
View File
@@ -22,18 +22,14 @@ export const submitVerificationSchema = z.object({
.trim() .trim()
.min(5, "Alamat minimal 5 karakter") .min(5, "Alamat minimal 5 karakter")
.max(LIMITS.MAX_ADDRESS_LENGTH, `Alamat maksimal ${LIMITS.MAX_ADDRESS_LENGTH} karakter`), .max(LIMITS.MAX_ADDRESS_LENGTH, `Alamat maksimal ${LIMITS.MAX_ADDRESS_LENGTH} karakter`),
ktpImageUrl: z ktpImageKey: z
.string() .string()
.trim() .trim()
.min(1, "Foto KTP wajib diisi") .regex(/^ktp\/[A-Za-z0-9_-]+\.(jpg|png|webp)$/, "Foto KTP wajib diunggah"),
.max(LIMITS.MAX_URL_LENGTH, "URL foto KTP terlalu panjang") selfieKey: z
.pipe(z.url("URL foto KTP tidak valid")),
selfieUrl: z
.string() .string()
.trim() .trim()
.min(1, "Foto selfie dengan KTP wajib diisi") .regex(/^selfie\/[A-Za-z0-9_-]+\.(jpg|png|webp)$/, "Foto selfie wajib diunggah"),
.max(LIMITS.MAX_URL_LENGTH, "URL foto selfie terlalu panjang")
.pipe(z.url("URL foto selfie tidak valid")),
bankName: z bankName: z
.string() .string()
.trim() .trim()
+27 -1
View File
@@ -1,10 +1,22 @@
import { AuthOptions } from "next-auth"; import { AuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials"; import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
// Adapter dipakai untuk persist User + Account saat OAuth (Google).
// Session tetap pakai JWT supaya kompatibel dengan CredentialsProvider.
export const authOptions: AuthOptions = { export const authOptions: AuthOptions = {
adapter: PrismaAdapter(prisma),
providers: [ providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
// Auto-link kalau email Google sama dengan email user yang sudah register
// via Credentials. Aman karena Google selalu memverifikasi email pemilik akun.
allowDangerousEmailAccountLinking: true,
}),
CredentialsProvider({ CredentialsProvider({
name: "credentials", name: "credentials",
credentials: { credentials: {
@@ -24,6 +36,10 @@ export const authOptions: AuthOptions = {
throw new Error("Email tidak ditemukan"); throw new Error("Email tidak ditemukan");
} }
if (!user.password) {
throw new Error("Akun ini terdaftar via Google. Silakan login dengan Google.");
}
const isPasswordValid = await bcrypt.compare( const isPasswordValid = await bcrypt.compare(
credentials.password, credentials.password,
user.password user.password
@@ -46,15 +62,25 @@ export const authOptions: AuthOptions = {
strategy: "jwt", strategy: "jwt",
}, },
callbacks: { callbacks: {
async jwt({ token, user }) { async jwt({ token, user, trigger }) {
if (user) { if (user) {
token.id = user.id; token.id = user.id;
} }
// Hidrasi `acceptedTermsAndPrivacy` dari DB pada login pertama dan setiap
// kali client memanggil `useSession().update()` (setelah user accept).
if (token.id && (trigger === "update" || token.acceptedTermsAndPrivacy === undefined)) {
const dbUser = await prisma.user.findUnique({
where: { id: token.id as string },
select: { acceptedTermsAndPrivacy: true },
});
token.acceptedTermsAndPrivacy = dbUser?.acceptedTermsAndPrivacy ?? false;
}
return token; return token;
}, },
async session({ session, token }) { async session({ session, token }) {
if (session.user) { if (session.user) {
session.user.id = token.id as string; session.user.id = token.id as string;
session.user.acceptedTermsAndPrivacy = token.acceptedTermsAndPrivacy ?? false;
} }
return session; return session;
}, },
+55
View File
@@ -0,0 +1,55 @@
import crypto from "node:crypto";
const ALGO = "aes-256-gcm";
const IV_LEN = 12;
const TAG_LEN = 16;
function readKey(envName: string): Buffer {
const hex = process.env[envName];
if (!hex) throw new Error(`Missing env ${envName}`);
if (hex.length !== 64) {
throw new Error(`${envName} must be 64 hex chars (32 bytes)`);
}
return Buffer.from(hex, "hex");
}
function getEncKey(): Buffer {
return readKey("KYC_ENCRYPTION_KEY");
}
function getNikPepper(): Buffer {
return readKey("KYC_NIK_PEPPER");
}
/** Encrypt a Buffer with AES-256-GCM. Output layout: [iv(12) | tag(16) | ciphertext]. */
export function encryptBuffer(plain: Buffer): Buffer {
const iv = crypto.randomBytes(IV_LEN);
const cipher = crypto.createCipheriv(ALGO, getEncKey(), iv);
const ct = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();
return Buffer.concat([iv, tag, ct]);
}
export function decryptBuffer(blob: Buffer): Buffer {
if (blob.length < IV_LEN + TAG_LEN) throw new Error("Ciphertext too short");
const iv = blob.subarray(0, IV_LEN);
const tag = blob.subarray(IV_LEN, IV_LEN + TAG_LEN);
const ct = blob.subarray(IV_LEN + TAG_LEN);
const decipher = crypto.createDecipheriv(ALGO, getEncKey(), iv);
decipher.setAuthTag(tag);
return Buffer.concat([decipher.update(ct), decipher.final()]);
}
/** Encrypt UTF-8 string -> base64 string. Used for short PII like NIK. */
export function encryptString(plain: string): string {
return encryptBuffer(Buffer.from(plain, "utf8")).toString("base64");
}
export function decryptString(b64: string): string {
return decryptBuffer(Buffer.from(b64, "base64")).toString("utf8");
}
/** Deterministic HMAC-SHA256 of a normalized value, hex-encoded. Used for unique-lookup of NIK without storing plaintext. */
export function hmacHex(value: string): string {
return crypto.createHmac("sha256", getNikPepper()).update(value).digest("hex");
}
+102
View File
@@ -0,0 +1,102 @@
import { promises as fs } from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import { encryptBuffer, decryptBuffer } from "@/lib/crypto";
export type KycKind = "ktp" | "selfie";
const KIND_DIRS: Record<KycKind, string> = {
ktp: "ktp",
selfie: "selfie",
};
/** Bytes. ~5MB matches the form limit; raise here if you change the upload route. */
export const MAX_KYC_FILE_BYTES = 5 * 1024 * 1024;
export const ALLOWED_KYC_MIME = new Set([
"image/jpeg",
"image/png",
"image/webp",
]);
const EXT_BY_MIME: Record<string, string> = {
"image/jpeg": "jpg",
"image/png": "png",
"image/webp": "webp",
};
function rootDir(): string {
const fromEnv = process.env.KYC_UPLOAD_DIR;
if (fromEnv && fromEnv.trim().length > 0) return fromEnv;
return path.join(process.cwd(), "uploads", "private");
}
function dirFor(kind: KycKind): string {
return path.join(rootDir(), KIND_DIRS[kind]);
}
/** Storage key written into DB: `<kind>/<id>.<ext>`. The kind segment is enforced to match the route. */
export type StoredFileMeta = {
key: string;
mime: string;
size: number;
};
export function isKycKind(value: string): value is KycKind {
return value === "ktp" || value === "selfie";
}
/** Resolve a storage key (`ktp/abc.jpg`) to an absolute path inside the upload dir. Throws on traversal. */
function resolveKey(kind: KycKind, key: string): string {
const expectedPrefix = `${KIND_DIRS[kind]}/`;
if (!key.startsWith(expectedPrefix)) {
throw new Error("Storage key does not match kind");
}
const relative = key.slice(expectedPrefix.length);
if (!/^[A-Za-z0-9_-]+\.(jpg|png|webp)$/.test(relative)) {
throw new Error("Storage key has invalid characters");
}
const abs = path.join(dirFor(kind), relative);
const dir = dirFor(kind);
if (!abs.startsWith(dir + path.sep) && abs !== dir) {
throw new Error("Storage key escapes upload directory");
}
return abs;
}
export async function saveEncrypted(
kind: KycKind,
data: Buffer,
mime: string,
): Promise<StoredFileMeta> {
if (!ALLOWED_KYC_MIME.has(mime)) throw new Error("Tipe file tidak didukung");
if (data.length === 0) throw new Error("File kosong");
if (data.length > MAX_KYC_FILE_BYTES) throw new Error("File terlalu besar");
const ext = EXT_BY_MIME[mime];
const id = crypto.randomBytes(16).toString("hex");
const key = `${KIND_DIRS[kind]}/${id}.${ext}`;
const abs = resolveKey(kind, key);
await fs.mkdir(path.dirname(abs), { recursive: true });
const blob = encryptBuffer(data);
await fs.writeFile(abs, blob, { mode: 0o600 });
return { key, mime, size: data.length };
}
export async function readDecrypted(kind: KycKind, key: string): Promise<Buffer> {
const abs = resolveKey(kind, key);
const blob = await fs.readFile(abs);
return decryptBuffer(blob);
}
export async function deleteFile(kind: KycKind, key: string): Promise<void> {
const abs = resolveKey(kind, key);
await fs.rm(abs, { force: true });
}
export function mimeFromKey(key: string): string {
if (key.endsWith(".jpg")) return "image/jpeg";
if (key.endsWith(".png")) return "image/png";
if (key.endsWith(".webp")) return "image/webp";
return "application/octet-stream";
}
+11
View File
@@ -8,6 +8,7 @@
"name": "setrip", "name": "setrip",
"version": "0.2.0", "version": "0.2.0",
"dependencies": { "dependencies": {
"@next-auth/prisma-adapter": "^1.0.7",
"@prisma/adapter-pg": "^7.7.0", "@prisma/adapter-pg": "^7.7.0",
"@prisma/client": "^7.7.0", "@prisma/client": "^7.7.0",
"axios": "^1.15.0", "axios": "^1.15.0",
@@ -1645,6 +1646,16 @@
"@tybys/wasm-util": "^0.10.0" "@tybys/wasm-util": "^0.10.0"
} }
}, },
"node_modules/@next-auth/prisma-adapter": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@next-auth/prisma-adapter/-/prisma-adapter-1.0.7.tgz",
"integrity": "sha512-Cdko4KfcmKjsyHFrWwZ//lfLUbcLqlyFqjd/nYE2m3aZ7tjMNUjpks47iw7NTCnXf+5UWz5Ypyt1dSs1EP5QJw==",
"license": "ISC",
"peerDependencies": {
"@prisma/client": ">=2.26.0 || >=3",
"next-auth": "^4"
}
},
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "16.2.3", "version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.3.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.3.tgz",
+1
View File
@@ -13,6 +13,7 @@
"seed": "npx tsx prisma/seed.ts" "seed": "npx tsx prisma/seed.ts"
}, },
"dependencies": { "dependencies": {
"@next-auth/prisma-adapter": "^1.0.7",
"@prisma/adapter-pg": "^7.7.0", "@prisma/adapter-pg": "^7.7.0",
"@prisma/client": "^7.7.0", "@prisma/client": "^7.7.0",
"axios": "^1.15.0", "axios": "^1.15.0",
@@ -0,0 +1,27 @@
/*
Warnings:
- You are about to drop the column `ktpImageUrl` on the `OrganizerVerification` table. All the data in the column will be lost.
- You are about to drop the column `nik` on the `OrganizerVerification` table. All the data in the column will be lost.
- You are about to drop the column `selfieUrl` on the `OrganizerVerification` table. All the data in the column will be lost.
- A unique constraint covering the columns `[nikHash]` on the table `OrganizerVerification` will be added. If there are existing duplicate values, this will fail.
- Added the required column `ktpImageKey` to the `OrganizerVerification` table without a default value. This is not possible if the table is not empty.
- Added the required column `nikEncrypted` to the `OrganizerVerification` table without a default value. This is not possible if the table is not empty.
- Added the required column `nikHash` to the `OrganizerVerification` table without a default value. This is not possible if the table is not empty.
- Added the required column `selfieKey` to the `OrganizerVerification` table without a default value. This is not possible if the table is not empty.
*/
-- DropIndex
DROP INDEX "OrganizerVerification_nik_key";
-- AlterTable
ALTER TABLE "OrganizerVerification" DROP COLUMN "ktpImageUrl",
DROP COLUMN "nik",
DROP COLUMN "selfieUrl",
ADD COLUMN "ktpImageKey" TEXT NOT NULL,
ADD COLUMN "nikEncrypted" TEXT NOT NULL,
ADD COLUMN "nikHash" TEXT NOT NULL,
ADD COLUMN "selfieKey" TEXT NOT NULL;
-- CreateIndex
CREATE UNIQUE INDEX "OrganizerVerification_nikHash_key" ON "OrganizerVerification"("nikHash");
@@ -0,0 +1,26 @@
-- AlterTable
ALTER TABLE "User" ALTER COLUMN "password" DROP NOT NULL;
-- CreateTable
CREATE TABLE "Account" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
-- AddForeignKey
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+32 -7
View File
@@ -11,7 +11,8 @@ model User {
id String @id @default(cuid()) id String @id @default(cuid())
name String name String
email String @unique email String @unique
password String /// Hash bcrypt. Null untuk user yang sign-in via OAuth (mis. Google).
password String?
image String? image String?
/// Apakah user telah menyetujui Syarat & Ketentuan dan Kebijakan Privasi /// Apakah user telah menyetujui Syarat & Ketentuan dan Kebijakan Privasi
acceptedTermsAndPrivacy Boolean @default(false) acceptedTermsAndPrivacy Boolean @default(false)
@@ -20,6 +21,7 @@ model User {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
accounts Account[]
trips Trip[] trips Trip[]
participations TripParticipant[] participations TripParticipant[]
tripReviews TripReview[] tripReviews TripReview[]
@@ -28,6 +30,27 @@ model User {
reviewedVerifications OrganizerVerification[] @relation("OrganizerVerificationReviewer") reviewedVerifications OrganizerVerification[] @relation("OrganizerVerificationReviewer")
} }
/// Tabel link akun OAuth pihak ketiga (Google, dst). Diisi oleh PrismaAdapter NextAuth.
/// Session tidak pakai DB — kita pakai JWT, jadi Session/VerificationToken tidak perlu.
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model OrganizerVerification { model OrganizerVerification {
id String @id @default(cuid()) id String @id @default(cuid())
userId String @unique userId String @unique
@@ -35,15 +58,17 @@ model OrganizerVerification {
/// Nama lengkap sesuai KTP /// Nama lengkap sesuai KTP
fullName String fullName String
/// Nomor Induk Kependudukan (PII — perlakukan sensitif) /// NIK terenkripsi (AES-256-GCM, base64). Plaintext tidak disimpan.
nik String @unique nikEncrypted String
/// HMAC-SHA256(NIK + pepper) untuk uniqueness lookup tanpa membuka plaintext.
nikHash String @unique
birthDate DateTime birthDate DateTime
address String address String
/// URL foto KTP (untuk MVP pakai hosting; pindah ke storage privat untuk produksi) /// Storage key foto KTP (mis. `ktp/<id>.jpg`). File disimpan terenkripsi di luar /public.
ktpImageUrl String ktpImageKey String
/// URL selfie memegang KTP /// Storage key selfie memegang KTP.
selfieUrl String selfieKey String
bankName String bankName String
bankAccountNumber String bankAccountNumber String
+11 -6
View File
@@ -2,6 +2,7 @@ import "dotenv/config";
import { PrismaClient } from "../app/generated/prisma/client"; import { PrismaClient } from "../app/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg"; import { PrismaPg } from "@prisma/adapter-pg";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import { encryptString, hmacHex } from "../lib/crypto";
const adapter = new PrismaPg({ const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!, connectionString: process.env.DATABASE_URL!,
@@ -97,16 +98,19 @@ async function main() {
// ==================== ORGANIZER VERIFICATIONS ==================== // ==================== ORGANIZER VERIFICATIONS ====================
const verifiedAt = new Date(); const verifiedAt = new Date();
const dedeNik = "3201010101010001";
const panjiNik = "3201010101010002";
await prisma.organizerVerification.createMany({ await prisma.organizerVerification.createMany({
data: [ data: [
{ {
userId: dede.id, userId: dede.id,
fullName: "Dede Inoen", fullName: "Dede Inoen",
nik: "3201010101010001", nikEncrypted: encryptString(dedeNik),
nikHash: hmacHex(dedeNik),
birthDate: new Date(Date.UTC(1990, 0, 1)), birthDate: new Date(Date.UTC(1990, 0, 1)),
address: "Jl. Pendaki No. 1, Garut, Jawa Barat", address: "Jl. Pendaki No. 1, Garut, Jawa Barat",
ktpImageUrl: "https://placehold.co/600x400/png?text=KTP+Dede", ktpImageKey: "ktp/seed-dede.jpg",
selfieUrl: "https://placehold.co/600x400/png?text=Selfie+Dede", selfieKey: "selfie/seed-dede.jpg",
bankName: "BCA", bankName: "BCA",
bankAccountNumber: "1234567890", bankAccountNumber: "1234567890",
bankAccountName: "Dede Inoen", bankAccountName: "Dede Inoen",
@@ -117,11 +121,12 @@ async function main() {
{ {
userId: panji.id, userId: panji.id,
fullName: "Panji Petualang", fullName: "Panji Petualang",
nik: "3201010101010002", nikEncrypted: encryptString(panjiNik),
nikHash: hmacHex(panjiNik),
birthDate: new Date(Date.UTC(1985, 5, 15)), birthDate: new Date(Date.UTC(1985, 5, 15)),
address: "Jl. Adventure No. 7, Kuningan, Jawa Barat", address: "Jl. Adventure No. 7, Kuningan, Jawa Barat",
ktpImageUrl: "https://placehold.co/600x400/png?text=KTP+Panji", ktpImageKey: "ktp/seed-panji.jpg",
selfieUrl: "https://placehold.co/600x400/png?text=Selfie+Panji", selfieKey: "selfie/seed-panji.jpg",
bankName: "Mandiri", bankName: "Mandiri",
bankAccountNumber: "9876543210", bankAccountNumber: "9876543210",
bankAccountName: "Panji Petualang", bankAccountName: "Panji Petualang",
+37
View File
@@ -0,0 +1,37 @@
import { NextResponse, type NextRequest } from "next/server";
import { getToken } from "next-auth/jwt";
// Path yang boleh diakses oleh user yang login tapi belum accept Terms & Privacy.
const ALLOWED_WHEN_NOT_ACCEPTED = [
"/accept-terms",
"/terms",
"/privacy",
];
export async function proxy(req: NextRequest) {
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
if (!token) return NextResponse.next();
if (token.acceptedTermsAndPrivacy) return NextResponse.next();
const { pathname } = req.nextUrl;
if (pathname.startsWith("/api/auth")) return NextResponse.next();
if (
ALLOWED_WHEN_NOT_ACCEPTED.some(
(p) => pathname === p || pathname.startsWith(`${p}/`),
)
) {
return NextResponse.next();
}
const url = req.nextUrl.clone();
url.pathname = "/accept-terms";
url.search = "";
return NextResponse.redirect(url);
}
export const config = {
matcher: [
// Lewati internal Next.js dan asset statis. Sisanya diperiksa proxy.
"/((?!_next/static|_next/image|favicon.ico|images/|.*\\.(?:png|jpg|jpeg|svg|webp|ico|css|js|map|txt|xml)$).*)",
],
};
+2 -2
View File
@@ -10,8 +10,8 @@ export const organizerRepo = {
return prisma.organizerVerification.findUnique({ where: { id } }); return prisma.organizerVerification.findUnique({ where: { id } });
}, },
async findByNik(nik: string) { async findByNikHash(nikHash: string) {
return prisma.organizerVerification.findUnique({ where: { nik } }); return prisma.organizerVerification.findUnique({ where: { nikHash } });
}, },
async upsertForUser( async upsertForUser(
+7
View File
@@ -27,4 +27,11 @@ export const userRepo = {
async create(data: Prisma.UserCreateInput) { async create(data: Prisma.UserCreateInput) {
return prisma.user.create({ data }); return prisma.user.create({ data });
}, },
async markAcceptedTerms(id: string) {
return prisma.user.update({
where: { id },
data: { acceptedTermsAndPrivacy: true, acceptedAt: new Date() },
});
},
}; };
+14 -6
View File
@@ -1,12 +1,13 @@
import { organizerRepo } from "@/server/repositories/organizer.repo"; import { organizerRepo } from "@/server/repositories/organizer.repo";
import { decryptString, encryptString, hmacHex } from "@/lib/crypto";
type SubmitInput = { type SubmitInput = {
fullName: string; fullName: string;
nik: string; nik: string;
birthDate: Date; birthDate: Date;
address: string; address: string;
ktpImageUrl: string; ktpImageKey: string;
selfieUrl: string; selfieKey: string;
bankName: string; bankName: string;
bankAccountNumber: string; bankAccountNumber: string;
bankAccountName: string; bankAccountName: string;
@@ -22,18 +23,20 @@ export const organizerService = {
throw new Error("Pengajuan kamu masih dalam proses review"); throw new Error("Pengajuan kamu masih dalam proses review");
} }
const dupNik = await organizerRepo.findByNik(data.nik); const nikHash = hmacHex(data.nik);
const dupNik = await organizerRepo.findByNikHash(nikHash);
if (dupNik && dupNik.userId !== userId) { if (dupNik && dupNik.userId !== userId) {
throw new Error("NIK ini sudah dipakai akun lain"); throw new Error("NIK ini sudah dipakai akun lain");
} }
return organizerRepo.upsertForUser(userId, { return organizerRepo.upsertForUser(userId, {
fullName: data.fullName, fullName: data.fullName,
nik: data.nik, nikEncrypted: encryptString(data.nik),
nikHash,
birthDate: data.birthDate, birthDate: data.birthDate,
address: data.address, address: data.address,
ktpImageUrl: data.ktpImageUrl, ktpImageKey: data.ktpImageKey,
selfieUrl: data.selfieUrl, selfieKey: data.selfieKey,
bankName: data.bankName, bankName: data.bankName,
bankAccountNumber: data.bankAccountNumber, bankAccountNumber: data.bankAccountNumber,
bankAccountName: data.bankAccountName, bankAccountName: data.bankAccountName,
@@ -74,4 +77,9 @@ export const organizerService = {
const v = await organizerRepo.findByUserId(userId); const v = await organizerRepo.findByUserId(userId);
return v?.status === "APPROVED"; return v?.status === "APPROVED";
}, },
/** Reveal NIK plaintext. Caller must enforce authorization (owner or admin). */
decryptNik(nikEncrypted: string): string {
return decryptString(nikEncrypted);
},
}; };
+2
View File
@@ -7,6 +7,7 @@ declare module "next-auth" {
name: string; name: string;
email: string; email: string;
image?: string | null; image?: string | null;
acceptedTermsAndPrivacy: boolean;
}; };
} }
} }
@@ -14,5 +15,6 @@ declare module "next-auth" {
declare module "next-auth/jwt" { declare module "next-auth/jwt" {
interface JWT { interface JWT {
id: string; id: string;
acceptedTermsAndPrivacy?: boolean;
} }
} }