feat(admin): add admin panel with user management, daily puzzle CRUD, and activity graph

- Add admin page at /admin (restricted to ADMIN_EMAIL via proxy)
- Implement user ban/unban and deletion
- Add daily puzzle creation, modification, deletion
- Include 14-day activity chart with hover details
- Add User.banned field to schema and migrate database
- Block banned users from logging in
- Add ADMIN_EMAIL to .env.local configuration
- Update Prisma client after schema changes
This commit is contained in:
jessy-david-dev
2026-04-11 15:10:08 +02:00
parent 5d8f7eae45
commit 8ff64b3470
22 changed files with 899 additions and 122 deletions
+26 -26
View File
@@ -28,6 +28,11 @@ export type StringFilter<$PrismaModel = never> = {
not?: Prisma.NestedStringFilter<$PrismaModel> | string
}
export type BoolFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
}
export type DateTimeFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[]
@@ -56,6 +61,14 @@ export type StringWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedStringFilter<$PrismaModel>
}
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedBoolFilter<$PrismaModel>
_max?: Prisma.NestedBoolFilter<$PrismaModel>
}
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[]
@@ -92,11 +105,6 @@ export type FloatFilter<$PrismaModel = never> = {
not?: Prisma.NestedFloatFilter<$PrismaModel> | number
}
export type BoolFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
}
export type IntWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
in?: number[]
@@ -129,14 +137,6 @@ export type FloatWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedFloatFilter<$PrismaModel>
}
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedBoolFilter<$PrismaModel>
_max?: Prisma.NestedBoolFilter<$PrismaModel>
}
export type NestedStringFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[]
@@ -151,6 +151,11 @@ export type NestedStringFilter<$PrismaModel = never> = {
not?: Prisma.NestedStringFilter<$PrismaModel> | string
}
export type NestedBoolFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
}
export type NestedDateTimeFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[]
@@ -190,6 +195,14 @@ export type NestedIntFilter<$PrismaModel = never> = {
not?: Prisma.NestedIntFilter<$PrismaModel> | number
}
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedBoolFilter<$PrismaModel>
_max?: Prisma.NestedBoolFilter<$PrismaModel>
}
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[]
@@ -215,11 +228,6 @@ export type NestedFloatFilter<$PrismaModel = never> = {
not?: Prisma.NestedFloatFilter<$PrismaModel> | number
}
export type NestedBoolFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
}
export type NestedIntWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
in?: number[]
@@ -252,12 +260,4 @@ export type NestedFloatWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedFloatFilter<$PrismaModel>
}
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedBoolFilter<$PrismaModel>
_max?: Prisma.NestedBoolFilter<$PrismaModel>
}
File diff suppressed because one or more lines are too long
@@ -744,6 +744,7 @@ export const UserScalarFieldEnum = {
name: 'name',
email: 'email',
password: 'password',
banned: 'banned',
createdAt: 'createdAt'
} as const
@@ -811,6 +812,13 @@ export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel,
/**
* Reference to a field of type 'Boolean'
*/
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
/**
* Reference to a field of type 'DateTime'
*/
@@ -831,13 +839,6 @@ export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'In
export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'>
/**
* Reference to a field of type 'Boolean'
*/
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
/**
* Batch Payload for updateMany & deleteMany & createMany
*/
@@ -75,6 +75,7 @@ export const UserScalarFieldEnum = {
name: 'name',
email: 'email',
password: 'password',
banned: 'banned',
createdAt: 'createdAt'
} as const
-4
View File
@@ -535,10 +535,6 @@ export type FloatFieldUpdateOperationsInput = {
divide?: number
}
export type BoolFieldUpdateOperationsInput = {
set?: boolean
}
export type GameCreateWithoutUserInput = {
id?: string
mode: string
+41 -1
View File
@@ -29,6 +29,7 @@ export type UserMinAggregateOutputType = {
name: string | null
email: string | null
password: string | null
banned: boolean | null
createdAt: Date | null
}
@@ -37,6 +38,7 @@ export type UserMaxAggregateOutputType = {
name: string | null
email: string | null
password: string | null
banned: boolean | null
createdAt: Date | null
}
@@ -45,6 +47,7 @@ export type UserCountAggregateOutputType = {
name: number
email: number
password: number
banned: number
createdAt: number
_all: number
}
@@ -55,6 +58,7 @@ export type UserMinAggregateInputType = {
name?: true
email?: true
password?: true
banned?: true
createdAt?: true
}
@@ -63,6 +67,7 @@ export type UserMaxAggregateInputType = {
name?: true
email?: true
password?: true
banned?: true
createdAt?: true
}
@@ -71,6 +76,7 @@ export type UserCountAggregateInputType = {
name?: true
email?: true
password?: true
banned?: true
createdAt?: true
_all?: true
}
@@ -152,6 +158,7 @@ export type UserGroupByOutputType = {
name: string
email: string
password: string
banned: boolean
createdAt: Date
_count: UserCountAggregateOutputType | null
_min: UserMinAggregateOutputType | null
@@ -181,6 +188,7 @@ export type UserWhereInput = {
name?: Prisma.StringFilter<"User"> | string
email?: Prisma.StringFilter<"User"> | string
password?: Prisma.StringFilter<"User"> | string
banned?: Prisma.BoolFilter<"User"> | boolean
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
games?: Prisma.GameListRelationFilter
dailyResults?: Prisma.DailyResultListRelationFilter
@@ -191,6 +199,7 @@ export type UserOrderByWithRelationInput = {
name?: Prisma.SortOrder
email?: Prisma.SortOrder
password?: Prisma.SortOrder
banned?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
games?: Prisma.GameOrderByRelationAggregateInput
dailyResults?: Prisma.DailyResultOrderByRelationAggregateInput
@@ -204,6 +213,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[]
name?: Prisma.StringFilter<"User"> | string
password?: Prisma.StringFilter<"User"> | string
banned?: Prisma.BoolFilter<"User"> | boolean
createdAt?: Prisma.DateTimeFilter<"User"> | Date | string
games?: Prisma.GameListRelationFilter
dailyResults?: Prisma.DailyResultListRelationFilter
@@ -214,6 +224,7 @@ export type UserOrderByWithAggregationInput = {
name?: Prisma.SortOrder
email?: Prisma.SortOrder
password?: Prisma.SortOrder
banned?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
_count?: Prisma.UserCountOrderByAggregateInput
_max?: Prisma.UserMaxOrderByAggregateInput
@@ -228,6 +239,7 @@ export type UserScalarWhereWithAggregatesInput = {
name?: Prisma.StringWithAggregatesFilter<"User"> | string
email?: Prisma.StringWithAggregatesFilter<"User"> | string
password?: Prisma.StringWithAggregatesFilter<"User"> | string
banned?: Prisma.BoolWithAggregatesFilter<"User"> | boolean
createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string
}
@@ -236,6 +248,7 @@ export type UserCreateInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
games?: Prisma.GameCreateNestedManyWithoutUserInput
dailyResults?: Prisma.DailyResultCreateNestedManyWithoutUserInput
@@ -246,6 +259,7 @@ export type UserUncheckedCreateInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
games?: Prisma.GameUncheckedCreateNestedManyWithoutUserInput
dailyResults?: Prisma.DailyResultUncheckedCreateNestedManyWithoutUserInput
@@ -256,6 +270,7 @@ export type UserUpdateInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
games?: Prisma.GameUpdateManyWithoutUserNestedInput
dailyResults?: Prisma.DailyResultUpdateManyWithoutUserNestedInput
@@ -266,6 +281,7 @@ export type UserUncheckedUpdateInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
games?: Prisma.GameUncheckedUpdateManyWithoutUserNestedInput
dailyResults?: Prisma.DailyResultUncheckedUpdateManyWithoutUserNestedInput
@@ -276,6 +292,7 @@ export type UserCreateManyInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
}
@@ -284,6 +301,7 @@ export type UserUpdateManyMutationInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
}
@@ -292,6 +310,7 @@ export type UserUncheckedUpdateManyInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
}
@@ -300,6 +319,7 @@ export type UserCountOrderByAggregateInput = {
name?: Prisma.SortOrder
email?: Prisma.SortOrder
password?: Prisma.SortOrder
banned?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
}
@@ -308,6 +328,7 @@ export type UserMaxOrderByAggregateInput = {
name?: Prisma.SortOrder
email?: Prisma.SortOrder
password?: Prisma.SortOrder
banned?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
}
@@ -316,6 +337,7 @@ export type UserMinOrderByAggregateInput = {
name?: Prisma.SortOrder
email?: Prisma.SortOrder
password?: Prisma.SortOrder
banned?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
}
@@ -328,6 +350,10 @@ export type StringFieldUpdateOperationsInput = {
set?: string
}
export type BoolFieldUpdateOperationsInput = {
set?: boolean
}
export type DateTimeFieldUpdateOperationsInput = {
set?: Date | string
}
@@ -365,6 +391,7 @@ export type UserCreateWithoutGamesInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
dailyResults?: Prisma.DailyResultCreateNestedManyWithoutUserInput
}
@@ -374,6 +401,7 @@ export type UserUncheckedCreateWithoutGamesInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
dailyResults?: Prisma.DailyResultUncheckedCreateNestedManyWithoutUserInput
}
@@ -399,6 +427,7 @@ export type UserUpdateWithoutGamesInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
dailyResults?: Prisma.DailyResultUpdateManyWithoutUserNestedInput
}
@@ -408,6 +437,7 @@ export type UserUncheckedUpdateWithoutGamesInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
dailyResults?: Prisma.DailyResultUncheckedUpdateManyWithoutUserNestedInput
}
@@ -417,6 +447,7 @@ export type UserCreateWithoutDailyResultsInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
games?: Prisma.GameCreateNestedManyWithoutUserInput
}
@@ -426,6 +457,7 @@ export type UserUncheckedCreateWithoutDailyResultsInput = {
name: string
email: string
password: string
banned?: boolean
createdAt?: Date | string
games?: Prisma.GameUncheckedCreateNestedManyWithoutUserInput
}
@@ -451,6 +483,7 @@ export type UserUpdateWithoutDailyResultsInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
games?: Prisma.GameUpdateManyWithoutUserNestedInput
}
@@ -460,6 +493,7 @@ export type UserUncheckedUpdateWithoutDailyResultsInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
banned?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
games?: Prisma.GameUncheckedUpdateManyWithoutUserNestedInput
}
@@ -509,6 +543,7 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
name?: boolean
email?: boolean
password?: boolean
banned?: boolean
createdAt?: boolean
games?: boolean | Prisma.User$gamesArgs<ExtArgs>
dailyResults?: boolean | Prisma.User$dailyResultsArgs<ExtArgs>
@@ -520,6 +555,7 @@ export type UserSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensio
name?: boolean
email?: boolean
password?: boolean
banned?: boolean
createdAt?: boolean
}, ExtArgs["result"]["user"]>
@@ -528,6 +564,7 @@ export type UserSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensio
name?: boolean
email?: boolean
password?: boolean
banned?: boolean
createdAt?: boolean
}, ExtArgs["result"]["user"]>
@@ -536,10 +573,11 @@ export type UserSelectScalar = {
name?: boolean
email?: boolean
password?: boolean
banned?: boolean
createdAt?: boolean
}
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "createdAt", ExtArgs["result"]["user"]>
export type UserOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "banned" | "createdAt", ExtArgs["result"]["user"]>
export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
games?: boolean | Prisma.User$gamesArgs<ExtArgs>
dailyResults?: boolean | Prisma.User$dailyResultsArgs<ExtArgs>
@@ -559,6 +597,7 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
name: string
email: string
password: string
banned: boolean
createdAt: Date
}, ExtArgs["result"]["user"]>
composites: {}
@@ -989,6 +1028,7 @@ export interface UserFieldRefs {
readonly name: Prisma.FieldRef<"User", 'String'>
readonly email: Prisma.FieldRef<"User", 'String'>
readonly password: Prisma.FieldRef<"User", 'String'>
readonly banned: Prisma.FieldRef<"User", 'Boolean'>
readonly createdAt: Prisma.FieldRef<"User", 'DateTime'>
}