Skip to content

Commit

Permalink
fix(console): return permission field from all endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
bouassaba committed Jan 23, 2025
1 parent b5d1886 commit 0ac3e66
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 55 deletions.
7 changes: 5 additions & 2 deletions console/api/database/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@
from .generic import exists


def fetch_group(_id: str) -> Dict:
def fetch_group(_id: str, user_id: str) -> Dict:
try:
with conn.cursor() as curs:
if not exists(curs=curs, tablename="group", _id=_id):
raise NotFoundException(message=f"Group with id={_id} does not exist!")
data = curs.execute(
f"""
SELECT g.id as "group_id", g."name" as "group_name", g.create_time, g.update_time, o.id as "org_id",
o."name" as "org_name", o.create_time as "org_create_time", o.update_time as "org_update_time"
o."name" as "org_name", o.create_time as "org_create_time", o.update_time as "org_update_time",
up.permission
FROM "group" g
JOIN organization o ON g.organization_id = o.id
LEFT JOIN userpermission up ON up.resource_id = g.id AND up.user_id = '{user_id}'
WHERE g.id='{_id}'
"""
).fetchone()
Expand All @@ -42,6 +44,7 @@ def fetch_group(_id: str) -> Dict:
"createTime": data.get("org_create_time"),
"updateTime": data.get("org_update_time"),
},
"permission": data.get("permission"),
}
if data is not None
else None
Expand Down
18 changes: 13 additions & 5 deletions console/api/database/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,26 @@
from . import exists


def fetch_organization(organization_id: str) -> Dict:
def fetch_organization(organization_id: str, user_id: str) -> Dict:
try:
with conn.cursor() as curs:
if not exists(curs=curs, tablename="organization", _id=organization_id):
raise NotFoundException(message=f"Organization with id={organization_id} does not exist!")
return curs.execute(
data = curs.execute(
f"""
SELECT id, name, create_time as "createTime", update_time as "updateTime"
FROM organization
WHERE id='{organization_id}'
SELECT o.id, o.name, o.create_time, o.update_time, up.permission
FROM organization o
LEFT JOIN userpermission up ON up.resource_id = o.id AND up.user_id = '{user_id}'
WHERE o.id='{organization_id}'
"""
).fetchone()
return {
"id": data.get("id"),
"name": data.get("name"),
"permission": data.get("permission"),
"createTime": data.get("create_time"),
"updateTime": data.get("update_time"),
}
except DatabaseError as error:
raise error

Expand Down
7 changes: 5 additions & 2 deletions console/api/database/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from . import exists


def fetch_workspace(_id: str) -> Dict:
def fetch_workspace(_id: str, user_id: str) -> Dict:
try:
with conn.cursor() as curs:
if not exists(curs=curs, tablename="workspace", _id=_id):
Expand All @@ -26,9 +26,11 @@ def fetch_workspace(_id: str) -> Dict:
f"""
SELECT w.id, w.name, w.organization_id, o.name as "organizationName",
o.create_time as "organization_create_time", o.update_time as "organization_update_time",
w.storage_capacity, w.root_id, w.bucket, w.create_time, w.update_time
w.storage_capacity, w.root_id, w.bucket, w.create_time, w.update_time,
up.permission
FROM workspace w
JOIN organization o ON w.organization_id = o.id
LEFT JOIN userpermission up ON up.resource_id = w.id AND up.user_id = '{user_id}'
WHERE w.id = '{_id}'
"""
).fetchone()
Expand All @@ -46,6 +48,7 @@ def fetch_workspace(_id: str) -> Dict:
"createTime": data.get("organization_create_time"),
"updateTime": data.get("organization_update_time"),
},
"permission": data.get("permission"),
}
except DatabaseError as error:
raise error
Expand Down
8 changes: 4 additions & 4 deletions console/api/routers/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@


@group_api_router.get(path="", responses={status.HTTP_200_OK: {"model": GroupResponse}})
async def get_group(data: Annotated[GroupRequest, Depends()]):
async def get_group(data: Annotated[GroupRequest, Depends()], user_id: str = Depends(get_user_id)):
try:
group = fetch_group(_id=data.id)
group = fetch_group(_id=data.id, user_id=user_id)
return GroupResponse(**group)
except NotFoundException as e:
logger.error(e)
Expand Down Expand Up @@ -84,13 +84,13 @@ async def get_all_groups(data: Annotated[GroupListRequest, Depends()], user_id:


@group_api_router.get(path="/search", responses={status.HTTP_200_OK: {"model": GroupListResponse}})
async def get_search_groups(data: Annotated[GroupSearchRequest, Depends()]):
async def get_search_groups(data: Annotated[GroupSearchRequest, Depends()], user_id: str = Depends(get_user_id)):
try:
groups = meilisearch_client.index("group").search(data.query, {"page": data.page, "hitsPerPage": data.size})
hits = []
for group in groups["hits"]:
try:
group = fetch_group(group["id"])
group = fetch_group(group["id"], user_id)
hits.append(group)
except NotFoundException:
pass
Expand Down
10 changes: 6 additions & 4 deletions console/api/routers/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@


@organization_api_router.get(path="", responses={status.HTTP_200_OK: {"model": OrganizationResponse}})
async def get_organization(data: Annotated[OrganizationRequest, Depends()]):
async def get_organization(data: Annotated[OrganizationRequest, Depends()], user_id: str = Depends(get_user_id)):
try:
organization = fetch_organization(organization_id=data.id)
organization = fetch_organization(organization_id=data.id, user_id=user_id)
return OrganizationResponse(**organization)
except NotFoundException as e:
logger.error(e)
Expand Down Expand Up @@ -98,15 +98,17 @@ async def get_all_organizations(


@organization_api_router.get(path="/search", responses={status.HTTP_200_OK: {"model": OrganizationListResponse}})
async def get_search_organizations(data: Annotated[OrganizationSearchRequest, Depends()]):
async def get_search_organizations(
data: Annotated[OrganizationSearchRequest, Depends()], user_id: str = Depends(get_user_id)
):
try:
organizations = meilisearch_client.index("organization").search(
data.query, {"page": data.page, "hitsPerPage": data.size}
)
hits = []
for organization in organizations["hits"]:
try:
organization = fetch_organization(organization["id"])
organization = fetch_organization(organization["id"], user_id)
hits.append(organization)
except NotFoundException:
pass
Expand Down
10 changes: 6 additions & 4 deletions console/api/routers/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@


@workspace_api_router.get(path="", responses={status.HTTP_200_OK: {"model": WorkspaceResponse}})
async def get_workspace(data: Annotated[WorkspaceRequest, Depends()]):
async def get_workspace(data: Annotated[WorkspaceRequest, Depends()], user_id: str = Depends(get_user_id)):
try:
workspace = fetch_workspace(_id=data.id)
workspace = fetch_workspace(_id=data.id, user_id=user_id)
return WorkspaceResponse(**workspace)
except NotFoundException as e:
logger.error(e)
Expand Down Expand Up @@ -93,15 +93,17 @@ async def get_all_workspaces(data: Annotated[WorkspaceListRequest, Depends()], u


@workspace_api_router.get(path="/search", responses={status.HTTP_200_OK: {"model": WorkspaceListResponse}})
async def get_search_workspaces(data: Annotated[WorkspaceSearchRequest, Depends()]):
async def get_search_workspaces(
data: Annotated[WorkspaceSearchRequest, Depends()], user_id: str = Depends(get_user_id)
):
try:
workspaces = meilisearch_client.index("workspace").search(
data.query, {"page": data.page, "hitsPerPage": data.size}
)
hits = []
for workspace in workspaces["hits"]:
try:
workspace = fetch_workspace(workspace["id"])
workspace = fetch_workspace(workspace["id"], user_id)
hits.append(workspace)
except NotFoundException:
pass
Expand Down
24 changes: 13 additions & 11 deletions ui/src/pages/console/console-panel-groups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,31 +137,32 @@ const ConsolePanelGroups = () => {
},
{
title: 'Properties',
renderCell: (workspace) => (
<>
{workspace.permission ? (
<Badge colorScheme="blue">Owner</Badge>
renderCell: (group) => (
<div className={cx('flex', 'flex-row', 'gap-0.5')}>
{group.permission ? (
<Badge variant="outline">Owner</Badge>
) : null}
</>
</div>
),
},
]}
actions={[
{
label: 'Grant Owner Permission',
icon: <IconShield />,
onClick: async (workspace) => {
isHiddenFn: (group) => group.permission === 'owner',
onClick: async (group) => {
setConfirmationHeader(<>Grant Owner Permission</>)
setConfirmationBody(
<>
Do you want to grant yourself owner permission on{' '}
<span className={cx('font-bold')}>{workspace.name}</span>?
<span className={cx('font-bold')}>{group.name}</span>?
</>,
)
setConfirmationRequest(() => async () => {
await ConsoleAPI.grantUserPermission({
userId: getUserId(),
resourceId: workspace.id,
resourceId: group.id,
resourceType: 'group',
permission: 'owner',
})
Expand All @@ -175,18 +176,19 @@ const ConsolePanelGroups = () => {
label: 'Revoke Permission',
icon: <IconRemoveModerator />,
isDestructive: true,
onClick: async (workspace) => {
isHiddenFn: (group) => !group.permission,
onClick: async (group) => {
setConfirmationHeader(<>Revoke Permission</>)
setConfirmationBody(
<>
Do you want to revoke your permission on{' '}
<span className={cx('font-bold')}>{workspace.name}</span>?
<span className={cx('font-bold')}>{group.name}</span>?
</>,
)
setConfirmationRequest(() => async () => {
await ConsoleAPI.revokeUserPermission({
userId: getUserId(),
resourceId: workspace.id,
resourceId: group.id,
resourceType: 'group',
})
await mutate()
Expand Down
31 changes: 20 additions & 11 deletions ui/src/pages/console/console-panel-organizations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,31 +132,36 @@ const ConsolePanelOrganizations = () => {
},
{
title: 'Properties',
renderCell: (workspace) => (
<>
{workspace.permission ? (
<Badge colorScheme="blue">Owner</Badge>
renderCell: (organization) => (
<div className={cx('flex', 'flex-row', 'gap-0.5')}>
{organization.permission ? (
<Badge variant="outline">Owner</Badge>
) : null}
</>
</div>
),
},
]}
actions={[
{
label: 'Grant Owner Permission',
icon: <IconShield />,
onClick: async (workspace) => {
isHiddenFn: (organization) =>
organization.permission === 'owner',
onClick: async (organization) => {
setConfirmationHeader(<>Grant Owner Permission</>)
setConfirmationBody(
<>
Do you want to grant yourself owner permission on{' '}
<span className={cx('font-bold')}>{workspace.name}</span>?
<span className={cx('font-bold')}>
{organization.name}
</span>
?
</>,
)
setConfirmationRequest(() => async () => {
await ConsoleAPI.grantUserPermission({
userId: getUserId(),
resourceId: workspace.id,
resourceId: organization.id,
resourceType: 'organization',
permission: 'owner',
})
Expand All @@ -170,18 +175,22 @@ const ConsolePanelOrganizations = () => {
label: 'Revoke Permission',
icon: <IconRemoveModerator />,
isDestructive: true,
onClick: async (workspace) => {
isHiddenFn: (organization) => !organization.permission,
onClick: async (organization) => {
setConfirmationHeader(<>Revoke Permission</>)
setConfirmationBody(
<>
Do you want to revoke your permission on{' '}
<span className={cx('font-bold')}>{workspace.name}</span>?
<span className={cx('font-bold')}>
{organization.name}
</span>
?
</>,
)
setConfirmationRequest(() => async () => {
await ConsoleAPI.revokeUserPermission({
userId: getUserId(),
resourceId: workspace.id,
resourceId: organization.id,
resourceType: 'organization',
})
await mutate()
Expand Down
12 changes: 3 additions & 9 deletions ui/src/pages/console/console-panel-users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,18 +158,12 @@ const ConsolePanelUsers = () => {
renderCell: (user) => (
<div className={cx('flex', 'flex-row', 'gap-0.5')}>
{user.isAdmin ? (
<Badge mr="1" fontSize="0.8em" colorScheme="blue">
Admin
</Badge>
<Badge colorScheme="blue">Admin</Badge>
) : null}
{user.isActive ? (
<Badge mr="1" fontSize="0.8em" colorScheme="green">
Active
</Badge>
<Badge colorScheme="green">Active</Badge>
) : (
<Badge mr="1" fontSize="0.8em" colorScheme="gray">
Inactive
</Badge>
<Badge colorScheme="gray">Inactive</Badge>
)}
{getUserId() === user.id ? (
<Badge colorScheme="red">It's you</Badge>
Expand Down
8 changes: 5 additions & 3 deletions ui/src/pages/console/console-panel-workspaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,19 @@ const ConsolePanelWorkspaces = () => {
{
title: 'Properties',
renderCell: (workspace) => (
<>
<div className={cx('flex', 'flex-row', 'gap-0.5')}>
{workspace.permission ? (
<Badge colorScheme="blue">Owner</Badge>
<Badge variant="outline">Owner</Badge>
) : null}
</>
</div>
),
},
]}
actions={[
{
label: 'Grant Owner Permission',
icon: <IconShield />,
isHiddenFn: (workspace) => workspace.permission === 'owner',
onClick: async (workspace) => {
setConfirmationHeader(<>Grant Owner Permission</>)
setConfirmationBody(
Expand Down Expand Up @@ -195,6 +196,7 @@ const ConsolePanelWorkspaces = () => {
label: 'Revoke Permission',
icon: <IconRemoveModerator />,
isDestructive: true,
isHiddenFn: (workspace) => !workspace.permission,
onClick: async (workspace) => {
setConfirmationHeader(<>Revoke Permission</>)
setConfirmationBody(
Expand Down

0 comments on commit 0ac3e66

Please sign in to comment.