Skip to content

Commit

Permalink
Merge pull request #625 from CannonLock/registry-crud
Browse files Browse the repository at this point in the history
Add Registry UI
  • Loading branch information
haoming29 authored Jan 10, 2024
2 parents ca26ba8 + 934025d commit 87e8d86
Show file tree
Hide file tree
Showing 22 changed files with 1,147 additions and 102 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
README.dev.md
docs/parameters.json
local
1 change: 1 addition & 0 deletions images/dev-config.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
OriginUrl: https://localhost:8444
TLSSkipVerify: true

10 changes: 8 additions & 2 deletions registry/registry_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,12 @@ func updateNamespace(ns *Namespace) error {
if err != nil || existingNs == nil {
return errors.Wrap(err, "Failed to get namespace")
}
if ns.Prefix == "" {
ns.Prefix = existingNs.Prefix
}
if ns.Pubkey == "" {
ns.Pubkey = existingNs.Pubkey
}
existingNsAdmin := existingNs.AdminMetadata
// We prevent the following fields from being modified by the user for now.
// They are meant for "internal" use only and we don't support changing
Expand All @@ -602,12 +608,12 @@ func updateNamespace(ns *Namespace) error {

// We intentionally exclude updating "identity" as this should only be updated
// when user registered through Pelican client with identity
query := `UPDATE namespace SET pubkey = ?, admin_metadata = ? WHERE id = ?`
query := `UPDATE namespace SET prefix = ?, pubkey = ?, admin_metadata = ? WHERE id = ?`
tx, err := db.Begin()
if err != nil {
return err
}
_, err = tx.Exec(query, ns.Pubkey, strAdminMetadata, ns.ID)
_, err = tx.Exec(query, ns.Prefix, ns.Pubkey, strAdminMetadata, ns.ID)
if err != nil {
if errRoll := tx.Rollback(); errRoll != nil {
log.Errorln("Failed to rollback transaction:", errRoll)
Expand Down
10 changes: 6 additions & 4 deletions registry/registry_ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ func createUpdateNamespace(ctx *gin.Context, isUpdate bool) {
ctx.JSON(400, gin.H{"error": "Invalid create or update namespace request"})
return
}
// Assign ID from path param because the request data doesn't have ID set
ns.ID = id
// Basic validation (type, required, etc)
errs := config.GetValidate().Struct(ns)
if errs != nil {
Expand Down Expand Up @@ -376,25 +378,25 @@ func createUpdateNamespace(ctx *gin.Context, isUpdate bool) {
// Then check if the user has previlege to update
isAdmin, _ := web_ui.CheckAdmin(user)
if !isAdmin { // Not admin, need to check if the namespace belongs to the user
found, err := namespaceBelongsToUserId(id, user)
found, err := namespaceBelongsToUserId(ns.ID, user)
if err != nil {
log.Error("Error checking if namespace belongs to the user: ", err)
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error checking if namespace belongs to the user"})
return
}
if !found {
log.Errorf("Namespace not found for id: %d", id)
log.Errorf("Namespace not found for id: %d", ns.ID)
ctx.JSON(http.StatusNotFound, gin.H{"error": "Namespace not found. Check the id or if you own the namespace"})
return
}
existingStatus, err := getNamespaceStatusById(id)
existingStatus, err := getNamespaceStatusById(ns.ID)
if err != nil {
log.Error("Error checking namespace status: ", err)
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error checking namespace status"})
return
}
if existingStatus == Approved {
log.Errorf("User '%s' is trying to modify approved namespace registration with id=%d", user, id)
log.Errorf("User '%s' is trying to modify approved namespace registration with id=%d", user, ns.ID)
ctx.JSON(http.StatusForbidden, gin.H{"error": "You don't have permission to modify an approved registration. Please contact your federation administrator"})
return
}
Expand Down
2 changes: 1 addition & 1 deletion web_ui/frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ as they would in production.
# From repo root
make web-build
goreleaser --clean --snapshot
docker run --rm -it -p 8444:8444 -w /app -v $PWD/dist/pelican_linux_arm64/:/app hub.opensciencegrid.org/pelican_platform/pelican-dev:latest-itb /bin/bash
docker run --rm -it -p 8444:8444 -w /app -v $PWD/dist/pelican_linux_arm64/:/app -v $PWD/local/:/etc/pelican/ pelican-dev /bin/bash
```

```shell
Expand Down
1 change: 1 addition & 0 deletions web_ui/frontend/app/(login)/components/PasswordInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default function PasswordInput({FormControlProps, TextFieldProps}: Passwo
<TextField
label="Password"
id="outlined-start-adornment"
size={"small"}
sx={{ m: 1, width: '50ch' }}
type={showPassword ? 'text' : 'password'}
{...TextFieldProps}
Expand Down
58 changes: 47 additions & 11 deletions web_ui/frontend/app/(login)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

"use client"

import {Box, Grow, Typography} from "@mui/material";
import {Box, Grow, Typography, Button} from "@mui/material";
import { useRouter } from 'next/navigation'
import { useState } from "react";
import {useEffect, useState} from "react";

import LoadingButton from "../components/LoadingButton";

Expand All @@ -31,8 +31,19 @@ export default function Home() {
const router = useRouter()
let [password, setPassword] = useState <string>("")
let [loading, setLoading] = useState(false);
let [enabledServers, setEnabledServers] = useState<string[]>([])
let [error, setError] = useState<string | undefined>(undefined);

useEffect(() => {
(async () => {
const response = await fetch("/api/v1.0/servers")
if (response.ok) {
const data = await response.json()
setEnabledServers(data)
}
})()
}, []);

async function submit(password: string) {

setLoading(true)
Expand Down Expand Up @@ -88,18 +99,43 @@ export default function Home() {
</Typography>
</Box>
<Box pt={2} mx={"auto"}>
{ enabledServers !== undefined && enabledServers.includes("registry") &&
<>
<Typography textAlign={"center"} variant={"h6"} component={"h2"}>
For Outside Administrators
</Typography>
<Box display={"flex"} justifyContent={"center"} my={2} mb={3}>
<Button
size={"large"}
href={"/api/v1.0/auth/cilogon/login?next_url=/view/registry/"}
variant={"contained"}
>
Login with CILogon
</Button>
</Box>
<Typography sx={{color: "#646464"}} textAlign={"center"} variant={"subtitle1"} component={"h2"}>
For Registry Administrator
</Typography>
</>
}
<form onSubmit={onSubmit} action="#">
<Box>
<PasswordInput TextFieldProps={{
InputProps: {
onChange: (e) => {
setPassword(e.target.value)
setError(undefined)
<Box display={"flex"} justifyContent={"center"}>
<PasswordInput
FormControlProps={{
sx: {width: "50%"},
}}
TextFieldProps={{
InputProps: {
sx: {width: "50%"},
onChange: (e) => {
setPassword(e.target.value)
setError(undefined)
}
}
}
}}/>
}}
/>
</Box>
<Box mt={3} display={"flex"} flexDirection={"column"}>
<Box display={"flex"} flexDirection={"column"}>
<Grow in={error !== undefined}>
<Typography
textAlign={"center"}
Expand Down
15 changes: 12 additions & 3 deletions web_ui/frontend/app/registry/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import Link from "next/link";
import Image from "next/image";
import PelicanLogo from "@/public/static/images/PelicanPlatformLogo_Icon.png";
import IconButton from "@mui/material/IconButton";
import BuildIcon from "@mui/icons-material/Build";
import {Add, Build} from "@mui/icons-material";

export const metadata = {
title: 'Pelican Registry',
Expand All @@ -38,19 +38,28 @@ export default function RootLayout({
return (
<Box display={"flex"} flexDirection={"row"}>
<Sidebar>
<Link href={"/index.html"}>
<Link href={"/registry/index.html"}>
<Image
src={PelicanLogo}
alt={"Pelican Logo"}
width={36}
height={36}
/>
</Link>
<Box pt={1}>
<Tooltip title={"Register Namespace"} placement={"right"}>
<Link href={"/registry/namespace/register/index.html"}>
<IconButton>
<Add/>
</IconButton>
</Link>
</Tooltip>
</Box>
<Box pt={1}>
<Tooltip title={"Config"} placement={"right"}>
<Link href={"/config/index.html"}>
<IconButton>
<BuildIcon/>
<Build/>
</IconButton>
</Link>
</Tooltip>
Expand Down
Loading

0 comments on commit 87e8d86

Please sign in to comment.