ephemeris_forge_github/reconcile/
access.rs1use ephemeris_forge::{Access, AccessOperation, Caller, RepoRef, TeamName};
2
3use super::Client;
4use crate::api::{Api, ForgeError};
5use crate::operation::access::Operation;
6use crate::{Live, Permission};
7
8impl<A: Api> Client<A> {
9 pub(super) async fn read_access(
10 &self,
11 repository: &RepoRef,
12 config: Option<&Access<Permission>>,
13 live: &mut Live,
14 ) -> Result<(), ForgeError> {
15 let Some(access) = config else {
16 return Ok(());
17 };
18 let owned = access.mode == ephemeris_forge::Mode::Owned;
19 if owned || !access.teams.is_empty() {
20 for team in self.api.teams(repository).await? {
21 let Ok(name) = TeamName::try_from(team.slug) else {
22 continue;
23 };
24 if team.inherited {
25 live.access.inherited_teams.insert(name.clone());
26 }
27 live.access.teams.insert(name, team.permission);
28 }
29 }
30 if !access.teams.is_empty() {
31 for team in self.api.organization_teams(repository.owner()).await? {
32 let Ok(name) = TeamName::try_from(team.slug) else {
33 continue;
34 };
35 live.access.organization_teams.insert(name, team.permission);
36 }
37 }
38 if owned || !access.collaborators.is_empty() {
39 live.access.collaborators = self
40 .api
41 .collaborators(repository)
42 .await?
43 .into_iter()
44 .map(|collaborator| (collaborator.user, collaborator.permission))
45 .collect();
46 live.invitations = self
47 .api
48 .invitations(repository)
49 .await?
50 .into_iter()
51 .map(|invitation| (invitation.user.clone(), invitation))
52 .collect();
53 }
54 let custom = access
55 .teams
56 .values()
57 .chain(access.collaborators.values())
58 .any(|permission| permission.custom().is_some());
59 if custom {
60 live.owner = Some(self.api.owner_kind(repository.owner()).await?);
61 }
62 live.access.caller = Some(self.read_caller(repository.owner()).await?);
63 Ok(())
64 }
65
66 pub(super) async fn read_caller(&self, organization: &str) -> Result<Caller, ForgeError> {
67 if let Some(caller) = &self.caller {
68 return Ok(caller.clone());
69 }
70 let login = self.api.current_user().await?;
71 let teams = self
72 .api
73 .user_teams()
74 .await?
75 .into_iter()
76 .filter(|membership| membership.organization.eq_ignore_ascii_case(organization))
77 .filter_map(|membership| TeamName::try_from(membership.team).ok())
78 .collect();
79 Ok(Caller::user(login, teams)?)
80 }
81
82 pub(super) async fn apply_access(
83 &self,
84 repository: &RepoRef,
85 operation: &Operation,
86 ) -> Result<(), ForgeError> {
87 match operation {
88 Operation::Grant(AccessOperation::AddTeam { team, permission }) => {
89 self.api
90 .add_team(repository, team.as_str(), permission)
91 .await
92 }
93 Operation::Grant(AccessOperation::RemoveTeam { team }) => {
94 self.api.remove_team(repository, team.as_str()).await
95 }
96 Operation::Grant(AccessOperation::AddCollaborator { user, permission }) => {
97 self.api
98 .add_collaborator(repository, user, permission)
99 .await
100 }
101 Operation::Grant(AccessOperation::RemoveCollaborator { user }) => {
102 self.api.remove_collaborator(repository, user).await
103 }
104 Operation::SetInvitationPermission {
105 id,
106 user: _,
107 permission,
108 } => {
109 self.api
110 .update_invitation(repository, *id, permission)
111 .await
112 }
113 Operation::CancelInvitation { id, user: _ } => {
114 self.api.cancel_invitation(repository, *id).await
115 }
116 }
117 }
118}