Skip to content

Commit

Permalink
Admin Page
Browse files Browse the repository at this point in the history
  • Loading branch information
maxtyson123 committed Feb 20, 2024
1 parent f8b08b4 commit 4dae702
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 27 deletions.
2 changes: 2 additions & 0 deletions website/src/lib/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export interface UserPermissions {
update: {
publicAccess: boolean;
internalAccess: boolean;
admin: boolean;
};
};
};
Expand Down Expand Up @@ -264,6 +265,7 @@ export const getDefaultPermissions = () : UserPermissions => {
update: {
publicAccess: false,
internalAccess: true,
admin: false,
},
},

Expand Down
2 changes: 1 addition & 1 deletion website/src/pages/admin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default function Admin(){
setLoadingMessage("Fetching logs...")


const aplQuery = "['vercel'] | where message contains '' | limit 100"
const aplQuery = "['vercel'] | where message contains '' and not(['vercel.source'] contains 'build') | top 100 by _time desc"

const res = await client.query(aplQuery);
if (!res.matches || res.matches.length === 0) {
Expand Down
107 changes: 86 additions & 21 deletions website/src/pages/admin/users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {loginSection} from "@/pages/account";
import {useSession} from "next-auth/react";
import {Loading} from "@/components/loading";
import {Error} from "@/components/error";
import {checkUserPermissions, RongoaUser} from "@/lib/users";
import {ADMIN_USER_TYPE, checkUserPermissions, EDITOR_USER_TYPE, MEMBER_USER_TYPE, RongoaUser} from "@/lib/users";
import {makeCachedRequest, makeRequestWithToken} from "@/lib/api_tools";
import {globalStyles} from "@/lib/global_css";
import { useLogger } from 'next-axiom';
Expand All @@ -25,7 +25,7 @@ export default function Admin(){
const { data: session } = useSession()

// Stats
const [pla, setPlants] = useState([] as PlantData[])
const [users, setUsers] = useState([] as RongoaUser[])

// Load the data
const [loading, setLoading] = useState(true)
Expand Down Expand Up @@ -64,26 +64,85 @@ export default function Admin(){
setLoading(true)

// Download the plants from the database
const plants = await makeCachedRequest("plant_admin_data", "/api/plants/search?getNames=true&getExtras=true&mushrooms=include")
if(!plants){
setError("Failed to fetch the plant data.")
const users = await makeCachedRequest("user_admin_data", "/api/auth/random?amount=9999999&extraData=true")
if(!users){
setError("Failed to fetch the user data.")
setLoading(false)
return
}

// Convert the data to the PlantData type
const plantData = plants as PlantData[]
for(let i = 0; i < plantData.length; i++)
plantData[i] = macronsForDisplay(plantData[i])
// Set the users
let userData = users as RongoaUser[]
for(let i = 0; i < userData.length; i++){
userData[i].database = userData[i] as any;
}

setUsers(userData)
setLoading(false)
}


const updateUser = async (id: number) => {
setLoading(true)
setLoadingMessage("Updating user...")

// Get the input values
const name = (document.getElementById(`name_${id}`) as HTMLInputElement).value
const email = (document.getElementById(`email_${id}`) as HTMLInputElement).value
const type = (document.getElementById(`type_${id}`) as HTMLInputElement).value
let permValue = 0

// Check the if correct type
switch (type){
case "Admin":
permValue = ADMIN_USER_TYPE
break
case "Editor":
permValue = EDITOR_USER_TYPE
break
case "Member":
permValue = MEMBER_USER_TYPE
break
default:
setError("Invalid user type")
setLoading(false)
return
}

console.log(plantData)
// Check if name is not empty
if(name == ""){
setError("Name cannot be empty")
setLoading(false)
return
}

// Check if email is not empty
if(email == ""){
setError("Email cannot be empty")
setLoading(false)
return
}

const adminData = {
id: id,
name: name,
email: email,
type: permValue
}

const response = await makeRequestWithToken("get", "/api/user/update?adminData=" + JSON.stringify(adminData))

// Remove the item in the local storage
localStorage.removeItem("user_admin_data")

// Set the plant data
setPlants(plantData)
setLoading(false)
}


const reload = () => {
window.location.reload()
}

const adminPage = () => {
return (
<>
Expand Down Expand Up @@ -112,24 +171,27 @@ export default function Admin(){
<Section autoPadding>
<div className={styles.plantTable}>
<div className={globalStyles.gridCentre}>
<p> Type can be Admin, Member or Editor </p>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Type</th>
<th>View Restricted</th>
<th>Last Logged In</th>
<th>Edit</th>
<th>Delete</th>
<th>Update</th>
</tr>

{pla.map((plant, index) => (
{users.map((user, index) => (
<tr key={index}>
<td> {plant.id} </td>
<td> {getNamesInPreference(plant)[0]} </td>
<td> {plant.plant_type} </td>
<td> {new Date(plant.last_modified).toLocaleString()} </td>
<td><Link href={"/plants/create?id=" + plant.id}>Edit</Link></td>
<td><Link href={"/plants/create?id=" + plant.id}>Delete</Link></td>
<td> {user.id} </td>
<td><input id={`name_${user.id}`} defaultValue={user.database.user_name}/></td>
<td><input id={`email_${user.id}`} defaultValue={user.database.user_email}/></td>
<td><input id={`type_${user.id}`} defaultValue={user.database.user_type == 2 ? "Admin" : user.database.user_type == 1 ? "Editor" : "Member"}/></td>
<td> {user.database.user_restricted_access ? "Yes" : "No"} </td>
<td> {new Date(user.database.user_last_login).toLocaleString()} </td>
<td><button onClick={() => {updateUser(user.database.id)}}>Update</button></td>
</tr>
))}
</table>
Expand Down Expand Up @@ -164,6 +226,9 @@ export default function Admin(){

<Section autoPadding>
<Error error={error}/>
<div className={globalStyles.gridCentre}>
<button className={styles.reloadButton} onClick={reload}>Retry</button>
</div>
</Section>

:
Expand Down
6 changes: 5 additions & 1 deletion website/src/pages/api/auth/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ export default async function handler(
// Check if the user is permitted to access the API
const session = await getServerSession(request, response, authOptions)
const permission = await checkApiPermissions(request, response, session, client, makeQuery, "api:auth:random:access")
const canGetAll = await checkApiPermissions(request, response, session, client, makeQuery, "data:account:viewPrivateDetails")
if(!permission) return response.status(401).json({error: "Not Authorized"})

// Try querying the database
try {


const selector = canGetAll ? "*" : "id";

// Get x random plant ids from the database
const plantIds = await makeQuery(`SELECT id FROM users ORDER BY ${USE_POSTGRES ? "RANDOM" : "RAND"}() LIMIT ${amount}`, client);
const plantIds = await makeQuery(`SELECT ${selector} FROM users ORDER BY ${USE_POSTGRES ? "RANDOM" : "RAND"}() LIMIT ${amount}`, client);

// If there are no plants, return an error
if (!plantIds) {
Expand Down
28 changes: 24 additions & 4 deletions website/src/pages/api/user/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,23 @@ export default async function handler(
const tables = getTables();

// Get the variables
const { id, name, email, image } = request.query;
const { id,
name,
email,
image,
adminData
} = request.query;

// If there is a missing variable then return an error
if(!id && !name && !email) {
return response.status(400).json({ error: 'Missing variables, must have id, name and email', id, name, email });
}
if(!adminData)
if(!id || !name || !email) {
return response.status(400).json({ error: 'Missing variables, must have id, name and email', id, name, email });
}

// Check if the user is permitted to access the API
const session = await getServerSession(request, response, authOptions)
const permission = await checkApiPermissions(request, response, session, client, makeQuery, "api:user:update:access")
const adminPermission = await checkApiPermissions(request, response, session, client, makeQuery, "api:user:update:admin")
if(!permission) return response.status(401).json({error: "Not Authorized"})

try {
Expand All @@ -41,6 +48,19 @@ export default async function handler(

let query = `UPDATE users SET ${tables.user_name} = '${name}', ${tables.user_email} = '${email}' ${imageQuery} WHERE id = ${id}`;


// If it is an admin update then add the admin data
if(adminData) {

// If not an admin then return an error
if(!adminPermission) {
return response.status(401).json({error: "Not Authorized"})
}

let data = JSON.parse(adminData as any);
query = `UPDATE users SET ${tables.user_name} = '${data.name}', ${tables.user_email} = '${data.email}', ${tables.user_type} = '${data.user_type}' WHERE id = ${data.id}`;
}

console.log("====================================");
console.log(query);
console.log("====================================");
Expand Down
10 changes: 10 additions & 0 deletions website/src/styles/pages/admin.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,14 @@
.plantTable button:hover{
background-color: var(--darker-secondary-gray);
color: var(--secondary-gray)
}

.reloadButton{
margin-top: 50px;
background-color: var(--main-green);
padding: 8px;
border-radius: 8px;
width: 100%;
color: var(--text-light);
cursor: pointer;
}

0 comments on commit 4dae702

Please sign in to comment.