krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v3.4.0: Hutch/Networking/RepositoryACLService.swift · raw

  1import Foundation
  2
  3protocol RepositoryACLServicing {
  4    func fetchACLs(repositoryRid: String) async throws -> [RepositoryACLEntry]
  5    func upsertACL(repositoryId: Int, entity: String, mode: AccessMode) async throws -> RepositoryACLEntry
  6    func deleteACL(entryId: Int) async throws
  7}
  8
  9private struct RepositoryACLQueryResponse: Decodable, Sendable {
 10    let repository: RepositoryACLQueryRepository?
 11}
 12
 13private struct RepositoryACLQueryRepository: Decodable, Sendable {
 14    let acls: RepositoryACLPage
 15}
 16
 17private struct RepositoryACLPage: Decodable, Sendable {
 18    let results: [RepositoryACLEntry]
 19}
 20
 21private struct RepositoryACLMutationResponse: Decodable, Sendable {
 22    let updateACL: RepositoryACLEntry
 23}
 24
 25private struct RepositoryACLDeleteResponse: Decodable, Sendable {
 26    let deleteACL: RepositoryACLDeletedEntry
 27}
 28
 29private struct RepositoryACLDeletedEntry: Decodable, Sendable {
 30    let id: Int
 31}
 32
 33struct RepositoryACLService: RepositoryACLServicing {
 34    private let client: SRHTClient
 35    private let service: SRHTService
 36
 37    init(client: SRHTClient, service: SRHTService) {
 38        self.client = client
 39        self.service = service
 40    }
 41
 42    func fetchACLs(repositoryRid: String) async throws -> [RepositoryACLEntry] {
 43        let response = try await client.execute(
 44            service: service,
 45            query: Self.aclsQuery,
 46            variables: ["rid": repositoryRid],
 47            responseType: RepositoryACLQueryResponse.self
 48        )
 49        return response.repository?.acls.results ?? []
 50    }
 51
 52    func upsertACL(repositoryId: Int, entity: String, mode: AccessMode) async throws -> RepositoryACLEntry {
 53        let response = try await client.execute(
 54            service: service,
 55            query: Self.upsertACLMutation,
 56            variables: [
 57                "repoId": repositoryId,
 58                "entity": entity,
 59                "mode": mode.rawValue
 60            ],
 61            responseType: RepositoryACLMutationResponse.self
 62        )
 63        return response.updateACL
 64    }
 65
 66    func deleteACL(entryId: Int) async throws {
 67        _ = try await client.execute(
 68            service: service,
 69            query: Self.deleteACLMutation,
 70            variables: ["id": entryId],
 71            responseType: RepositoryACLDeleteResponse.self
 72        )
 73    }
 74}
 75
 76private extension RepositoryACLService {
 77    static let aclsQuery = """
 78    query repositoryACLs($rid: ID!) {
 79        repository(rid: $rid) {
 80            acls {
 81                results {
 82                    id
 83                    mode
 84                    entity { canonicalName }
 85                }
 86            }
 87        }
 88    }
 89    """
 90
 91    static let upsertACLMutation = """
 92    mutation updateACL($repoId: Int!, $mode: AccessMode!, $entity: String!) {
 93        updateACL(repoId: $repoId, mode: $mode, entity: $entity) {
 94            id
 95            mode
 96            entity { canonicalName }
 97        }
 98    }
 99    """
100
101    static let deleteACLMutation = """
102    mutation deleteACL($id: Int!) {
103        deleteACL(id: $id) { id }
104    }
105    """
106}