feat(cli/org): wire Commands::Org admin subcommands + parse_org_role + transfer-ownership/delete-org
This commit is contained in:
@@ -441,6 +441,73 @@ pub fn run_rotate_key(dir: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_transfer_ownership(dir: &Path, member_id_prefix: &str, keep_owner: bool) -> Result<()> {
|
||||
let vault = crate::org_session::open_org_vault(Some(dir))?;
|
||||
let caller = vault.current_member()?;
|
||||
if !caller.role.can_manage_owners() {
|
||||
anyhow::bail!("only an owner can transfer ownership");
|
||||
}
|
||||
let mut members = vault.load_members()?;
|
||||
let target_id = resolve_member_id(&members, member_id_prefix)?;
|
||||
if target_id == caller.member_id {
|
||||
anyhow::bail!("you are already the owner");
|
||||
}
|
||||
// Promote the target to Owner.
|
||||
{
|
||||
let target = members.find_by_id_mut(&target_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("member not found"))?;
|
||||
target.role = OrgRole::Owner;
|
||||
}
|
||||
// Real transfer: also demote the CALLER to Admin, unless --keep-owner was
|
||||
// passed (explicit co-ownership). The spec says "owner → another member",
|
||||
// so demotion is the default.
|
||||
if !keep_owner {
|
||||
if let Some(me) = members.find_by_id_mut(&caller.member_id) {
|
||||
me.role = OrgRole::Admin;
|
||||
}
|
||||
}
|
||||
vault.save_members(&members)?;
|
||||
|
||||
let mode = if keep_owner { "co-ownership (caller kept owner)" } else { "caller demoted to admin" };
|
||||
let commit_msg = format!(
|
||||
"org: transfer ownership to {} ({mode})\n\nRelicario-Actor: {} {}\nRelicario-Action: ownership-transfer\nRelicario-Member: {}",
|
||||
target_id.as_str(), caller.display_name, caller.member_id.as_str(), target_id.as_str()
|
||||
);
|
||||
crate::org_session::org_git_run(&vault.root, &["add", "members.json"], "git add")?;
|
||||
crate::org_session::org_git_run(&vault.root, &["commit", "-m", &commit_msg], "git commit")?;
|
||||
if keep_owner {
|
||||
println!("Ownership shared with {} (you remain an owner).", target_id.as_str());
|
||||
} else {
|
||||
println!("Ownership transferred to {} (you are now an admin).", target_id.as_str());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_delete_org(dir: &Path, confirm: bool) -> Result<()> {
|
||||
let vault = crate::org_session::open_org_vault(Some(dir))?;
|
||||
let caller = vault.current_member()?;
|
||||
if !caller.role.can_manage_owners() {
|
||||
anyhow::bail!("only an owner can delete the org");
|
||||
}
|
||||
if !confirm {
|
||||
anyhow::bail!("refusing to delete org without --confirm");
|
||||
}
|
||||
let commit_msg = format!(
|
||||
"org: delete org\n\nRelicario-Actor: {} {}\nRelicario-Action: org-delete",
|
||||
caller.display_name, caller.member_id.as_str()
|
||||
);
|
||||
// Remove org files (the git history is retained as the audit record).
|
||||
for f in ["org.json", "members.json", "collections.json", "manifest.enc"] {
|
||||
let _ = fs::remove_file(vault.root.join(f));
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(vault.root.join("items"));
|
||||
let _ = std::fs::remove_dir_all(vault.root.join("keys"));
|
||||
crate::org_session::org_git_run(&vault.root, &["add", "-A"], "git add")?;
|
||||
crate::org_session::org_git_run(&vault.root, &["commit", "-m", &commit_msg], "git commit")?;
|
||||
println!("Org deleted (git history retained as audit record).");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_status(dir: &Path) -> Result<()> {
|
||||
let root = crate::org_session::org_dir(Some(dir))?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user