web routing is POG now
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
//! Reads everything the workspace shows.
|
||||
//! Reads the context every one of the five pages shows.
|
||||
//!
|
||||
//! One loader serves them all, because they all need the same thing: which
|
||||
//! table is being worked on, and what it currently is. Four calls, in this
|
||||
//! order — the column-type catalog is the vocabulary the append panel offers,
|
||||
//! the profile tree names the tables, the profile details describe the
|
||||
//! selected table's columns and scripts, and the rename history explains how
|
||||
//! those columns got their names.
|
||||
//!
|
||||
//! Four calls, in this order: the column-type catalog is the vocabulary the
|
||||
//! append panel offers, the profile tree names the profiles and their tables,
|
||||
//! the profile details describe the selected table's columns and scripts, and
|
||||
//! the rename history explains how those columns got their names.
|
||||
//! Nothing here trusts the posted selection — a profile or table that is gone
|
||||
//! is dropped from the selection rather than reported as an error, because the
|
||||
//! commonest way to get here with a stale one is having just deleted it.
|
||||
@@ -13,7 +16,7 @@ use tonic::transport::Channel;
|
||||
|
||||
use crate::{
|
||||
AppState,
|
||||
auth::{GetAuthorizationRequest, ListGrantableObjectsRequest, ListRolePermissionsRequest, ListRolesRequest},
|
||||
auth::GetAuthorizationRequest,
|
||||
definitions::{
|
||||
common::Empty,
|
||||
table_definition::{
|
||||
@@ -26,8 +29,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::state::{
|
||||
DetailColumn, GLOBAL_SCOPE, LoadError, PageInputs, RenameEntry, ScriptView, TableDefinitionPageState,
|
||||
TableDetailView, TablePermissionAction, TableRolePermissions, TableSummary,
|
||||
DetailColumn, GLOBAL_SCOPE, LoadError, PageInputs, RenameEntry, ScriptView,
|
||||
TableDefinitionPageState, TableDetailView, TableSummary,
|
||||
};
|
||||
|
||||
/// Reads the column-type vocabulary on its own.
|
||||
@@ -92,11 +95,13 @@ pub(crate) async fn load_page(
|
||||
let profiles = tree
|
||||
.profiles
|
||||
.iter()
|
||||
.map(|profile| profile.name.clone())
|
||||
.map(|profile| profile.name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// A profile that no longer exists takes the table selection with it.
|
||||
if inputs.selection.profile != GLOBAL_SCOPE && !profiles.contains(&inputs.selection.profile) {
|
||||
if inputs.selection.profile != GLOBAL_SCOPE
|
||||
&& !profiles.contains(&inputs.selection.profile.as_str())
|
||||
{
|
||||
inputs.selection.profile.clear();
|
||||
inputs.selection.table.clear();
|
||||
}
|
||||
@@ -127,7 +132,6 @@ pub(crate) async fn load_page(
|
||||
format!("{} ({})", dependency.table_name, dependency.column_name)
|
||||
})
|
||||
.collect(),
|
||||
row_display_columns: table.row_display_columns.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
@@ -195,8 +199,6 @@ pub(crate) async fn load_page(
|
||||
})
|
||||
.collect(),
|
||||
row_display_columns: table.row_display_columns,
|
||||
table_kind: table.table_kind,
|
||||
name: table.name,
|
||||
})
|
||||
}
|
||||
false => None,
|
||||
@@ -230,84 +232,8 @@ pub(crate) async fn load_page(
|
||||
false => Vec::new(),
|
||||
};
|
||||
|
||||
let mut permission_object = String::new();
|
||||
let mut role_permissions = Vec::new();
|
||||
if inputs.selection.has_table()
|
||||
&& crate::authz::can_manage(&authorization, crate::authz::STRUCT_ROLE)
|
||||
{
|
||||
let expected_object = crate::authz::table_object(
|
||||
&inputs.selection.profile,
|
||||
&inputs.selection.table,
|
||||
);
|
||||
let roles = auth
|
||||
.list_roles(
|
||||
authenticated_request(headers, ListRolesRequest {})
|
||||
.map_err(|_| LoadError::Unauthenticated)?,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| LoadError::Backend(error.message().to_string()))?
|
||||
.into_inner()
|
||||
.roles;
|
||||
for role in roles.into_iter().filter(|role| role.kind == "data") {
|
||||
let grantable = auth
|
||||
.list_grantable_objects(
|
||||
authenticated_request(
|
||||
headers,
|
||||
ListGrantableObjectsRequest {
|
||||
target_role: role.name.clone(),
|
||||
},
|
||||
)
|
||||
.map_err(|_| LoadError::Unauthenticated)?,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| LoadError::Backend(error.message().to_string()))?
|
||||
.into_inner()
|
||||
.objects
|
||||
.into_iter()
|
||||
.find(|object| object.object == expected_object);
|
||||
let Some(grantable) = grantable else {
|
||||
continue;
|
||||
};
|
||||
permission_object = expected_object.clone();
|
||||
let permissions = auth
|
||||
.list_role_permissions(
|
||||
authenticated_request(
|
||||
headers,
|
||||
ListRolePermissionsRequest {
|
||||
role: role.name.clone(),
|
||||
},
|
||||
)
|
||||
.map_err(|_| LoadError::Unauthenticated)?,
|
||||
)
|
||||
.await
|
||||
.map_err(|error| LoadError::Backend(error.message().to_string()))?
|
||||
.into_inner();
|
||||
role_permissions.push(TableRolePermissions {
|
||||
role: role.name,
|
||||
actions: grantable
|
||||
.allowed_actions
|
||||
.into_iter()
|
||||
.map(|action| TablePermissionAction {
|
||||
direct: crate::authz::is_direct_permission(
|
||||
&permissions.permissions,
|
||||
&expected_object,
|
||||
&action,
|
||||
),
|
||||
effective: crate::authz::permissions_permit(
|
||||
&permissions.effective_permissions,
|
||||
&expected_object,
|
||||
&action,
|
||||
),
|
||||
action,
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(TableDefinitionPageState {
|
||||
nav: crate::ui::Nav::new(headers, "admin").with_authorization(&authorization),
|
||||
profiles,
|
||||
tables,
|
||||
detail,
|
||||
history,
|
||||
@@ -320,7 +246,8 @@ pub(crate) async fn load_page(
|
||||
error: inputs.error,
|
||||
sql: inputs.sql,
|
||||
generated: inputs.generated,
|
||||
permission_object,
|
||||
role_permissions,
|
||||
// Overwritten by the handler, which is the only thing that knows
|
||||
// which of the pages it is answering for.
|
||||
active: "",
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user