Skip to main content

ephemeris_forge_forgejo/reconcile/
access.rs

1use ephemeris_forge::{AccessOperation, Caller, Observed, RepoRef, TeamName, UserName};
2
3use super::Client;
4use crate::api::{Api, ForgeError};
5use crate::config::Access;
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>,
13        live: &mut Live,
14    ) -> Result<(), ForgeError> {
15        if config.is_none() {
16            return Ok(());
17        }
18        for team in self.api.teams(repository).await? {
19            let Some(name) = team.name.and_then(|name| TeamName::try_from(name).ok()) else {
20                continue;
21            };
22            if team.includes_all_repositories == Some(true) {
23                live.access.inherited_teams.insert(name.clone());
24            }
25            let permission = team.permission.as_deref().unwrap_or("none");
26            live.access.teams.insert(name, Observed::parse(permission));
27        }
28        live.access.organization_teams = self
29            .api
30            .organization_teams(repository.owner())
31            .await?
32            .into_iter()
33            .filter_map(|team| {
34                let permission = Observed::parse(team.permission.as_deref().unwrap_or("none"));
35                Some((TeamName::try_from(team.name?).ok()?, permission))
36            })
37            .collect();
38        live.access.collaborators = self
39            .api
40            .collaborators(repository)
41            .await?
42            .into_iter()
43            .filter_map(|collaborator| {
44                Some((
45                    UserName::try_from(collaborator.login).ok()?,
46                    Observed::parse(&collaborator.permission),
47                ))
48            })
49            .collect();
50        live.access.caller = Some(self.read_caller(repository.owner()).await?);
51        Ok(())
52    }
53
54    async fn read_caller(&self, organization: &str) -> Result<Caller, ForgeError> {
55        let login = self.api.current_user().await?;
56        let teams = self
57            .api
58            .user_teams()
59            .await?
60            .into_iter()
61            .filter(|team| {
62                team.organization
63                    .as_ref()
64                    .and_then(|owner| owner.username.as_deref())
65                    .is_some_and(|name| name.eq_ignore_ascii_case(organization))
66            })
67            .filter_map(|team| TeamName::try_from(team.name?).ok())
68            .collect();
69        Ok(Caller::user(login, teams)?)
70    }
71
72    pub(super) async fn apply_access(
73        &self,
74        repository: &RepoRef,
75        operation: &AccessOperation<Permission>,
76    ) -> Result<(), ForgeError> {
77        match operation {
78            AccessOperation::AddTeam { team, permission } => {
79                self.api.add_team(repository, team, *permission).await
80            }
81            AccessOperation::RemoveTeam { team } => {
82                self.api.remove_team(repository, team.as_str()).await
83            }
84            AccessOperation::AddCollaborator { user, permission } => {
85                self.api
86                    .add_collaborator(repository, user, *permission)
87                    .await
88            }
89            AccessOperation::RemoveCollaborator { user } => {
90                self.api
91                    .remove_collaborator(repository, user.as_str())
92                    .await
93            }
94        }
95    }
96}