add admin checks for admin pages and run biome formating 🔨
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 11m8s

This commit is contained in:
2025-07-25 13:31:12 +05:00
parent aedf7cdf7d
commit 9b2f2c1528
127 changed files with 6577 additions and 6334 deletions

View File

@ -59,7 +59,10 @@ export async function logout({ token }: { token: string }) {
export async function checkIdOrPhone({
id_card,
phone_number,
}: { id_card?: string; phone_number?: string }) {
}: {
id_card?: string;
phone_number?: string;
}) {
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/auth/users/filter/?id_card=${id_card}&mobile=${phone_number}`,
{
@ -76,7 +79,10 @@ export async function checkIdOrPhone({
export async function checkTempIdOrPhone({
id_card,
phone_number,
}: { id_card?: string; phone_number?: string }) {
}: {
id_card?: string;
phone_number?: string;
}) {
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/auth/users/temp/filter/?id_card=${id_card}&mobile=${phone_number}`,
{

View File

@ -4,7 +4,10 @@ import { revalidatePath } from "next/cache";
import { getServerSession } from "next-auth";
import { authOptions } from "@/app/auth";
import { BlockDeviceFormState } from "@/components/block-device-dialog";
import type { AddDeviceFormState, initialState } from "@/components/user/add-device-dialog";
import type {
AddDeviceFormState,
initialState,
} from "@/components/user/add-device-dialog";
import type { ApiError, ApiResponse, Device } from "@/lib/backend-types";
import { checkSession } from "@/utils/session";
import { handleApiResponse } from "@/utils/tryCatch";
@ -24,7 +27,10 @@ export async function getDevices(params: GetDevicesProps, allDevices = false) {
// Build query string from all defined params
const query = Object.entries(params)
.filter(([_, value]) => value !== undefined && value !== "")
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
.map(
([key, value]) =>
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
)
.join("&");
const response = await fetch(
@ -56,21 +62,23 @@ export async function getDevice({ deviceId }: { deviceId: string }) {
return handleApiResponse<Device>(response, "getDevice");
}
export async function addDeviceAction(
prevState: AddDeviceFormState,
formData: FormData
formData: FormData,
): Promise<AddDeviceFormState> {
const name = formData.get("name") as string;
const mac_address = formData.get("mac_address") as string;
const errors: typeof initialState.fieldErrors = {};
if (!name || name.length < 2) {
errors.name = ["Device name is required and must be at least 2 characters."];
errors.name = [
"Device name is required and must be at least 2 characters.",
];
}
if (!mac_address || !/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(mac_address)) {
if (
!mac_address ||
!/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(mac_address)
) {
errors.mac_address = ["Invalid MAC address format."];
}
@ -85,7 +93,11 @@ export async function addDeviceAction(
try {
const session = await getServerSession(authOptions);
if (!session?.apiToken) {
return { message: "Authentication required.", fieldErrors: {}, payload: formData };
return {
message: "Authentication required.",
fieldErrors: {},
payload: formData,
};
}
const response = await fetch(
@ -107,17 +119,24 @@ export async function addDeviceAction(
await handleApiResponse<Device>(response, "addDeviceAction");
revalidatePath("/devices");
return { message: "Device successfully added!", fieldErrors: {}, payload: formData };
return {
message: "Device successfully added!",
fieldErrors: {},
payload: formData,
};
} catch (error: unknown) {
console.error("Server Action Error:", error);
return { message: (error as ApiError).message || "An unexpected error occurred.", fieldErrors: {}, payload: formData };
return {
message: (error as ApiError).message || "An unexpected error occurred.",
fieldErrors: {},
payload: formData,
};
}
}
export async function blockDeviceAction(
prevState: BlockDeviceFormState,
formData: FormData
formData: FormData,
): Promise<BlockDeviceFormState> {
const deviceId = formData.get("deviceId") as string;
const reason_for_blocking = formData.get("reason_for_blocking") as string;
@ -131,19 +150,26 @@ export async function blockDeviceAction(
success: false,
message: "Authentication required.",
fieldErrors: {},
payload: formData
payload: formData,
};
}
// Validation only for admin block with reason
if (action === "block" && session?.user?.is_superuser && (!reason_for_blocking || reason_for_blocking.trim().length < 5)) {
if (
action === "block" &&
session?.user?.is_superuser &&
(!reason_for_blocking || reason_for_blocking.trim().length < 5)
) {
return {
success: false,
message: "Reason for blocking is required and must be at least 5 characters.",
message:
"Reason for blocking is required and must be at least 5 characters.",
fieldErrors: {
reason_for_blocking: ["Reason is required and must be at least 5 characters."]
reason_for_blocking: [
"Reason is required and must be at least 5 characters.",
],
},
payload: formData
payload: formData,
};
}
@ -160,32 +186,39 @@ export async function blockDeviceAction(
body: JSON.stringify({
blocked: isBlocking,
reason_for_blocking: session?.user?.is_superuser
? reason_for_blocking || (action === "simple-block" ? "Blocked by admin" : "")
: isBlocking ? "Blocked by parent" : "",
? reason_for_blocking ||
(action === "simple-block" ? "Blocked by admin" : "")
: isBlocking
? "Blocked by parent"
: "",
blocked_by: session?.user?.is_superuser ? blocked_by : "PARENT",
}),
},
);
const result = await handleApiResponse<Device>(response, "blockDeviceAction");
const result = await handleApiResponse<Device>(
response,
"blockDeviceAction",
);
revalidatePath("/devices");
revalidatePath("/parental-control");
return {
success: true,
message: isBlocking ? "Device blocked successfully!" : "Device unblocked successfully!",
message: isBlocking
? "Device blocked successfully!"
: "Device unblocked successfully!",
fieldErrors: {},
payload: formData
payload: formData,
};
} catch (error: unknown) {
console.error("Block Device Action Error:", error);
return {
success: false,
message: (error as ApiError).message || "An unexpected error occurred.",
fieldErrors: {},
payload: formData
payload: formData,
};
}
}
}

View File

@ -1,48 +1,49 @@
'use server'
"use server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/app/auth";
import type { ApiResponse } from "@/lib/backend-types";
import type { UserProfile } from "@/lib/types/user";
import { handleApiResponse } from "@/utils/tryCatch";
type ParamProps = {
[key: string]: string | number | undefined;
[key: string]: string | number | undefined;
};
export async function getUsers(params: ParamProps) {
const session = await getServerSession(authOptions);
const session = await getServerSession(authOptions);
const query = Object.entries(params)
.filter(([_, value]) => value !== undefined && value !== "")
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
.join("&");
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/auth/users/?${query}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Token ${session?.apiToken}`,
},
},
);
const query = Object.entries(params)
.filter(([_, value]) => value !== undefined && value !== "")
.map(
([key, value]) =>
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
)
.join("&");
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/auth/users/?${query}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Token ${session?.apiToken}`,
},
},
);
return handleApiResponse<ApiResponse<UserProfile>>(response, "getUsers");
return handleApiResponse<ApiResponse<UserProfile>>(response, "getUsers");
}
export async function getProfileById(userId: string) {
const session = await getServerSession(authOptions);
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/auth/users/${userId}/`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Token ${session?.apiToken}`,
},
},
);
const session = await getServerSession(authOptions);
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/auth/users/${userId}/`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Token ${session?.apiToken}`,
},
},
);
return handleApiResponse<UserProfile>(response, "getProfilebyId");
}
return handleApiResponse<UserProfile>(response, "getProfilebyId");
}