summaryrefslogtreecommitdiff
path: root/Hutch/Networking/RepositoryACLService.swift
blob: 82a7a38417ccc1e2f3c76994037c529f8c93aad0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import Foundation

protocol RepositoryACLServicing {
    func fetchACLs(repositoryRid: String) async throws -> [RepositoryACLEntry]
    func upsertACL(repositoryId: Int, entity: String, mode: AccessMode) async throws -> RepositoryACLEntry
    func deleteACL(entryId: Int) async throws
}

private struct RepositoryACLQueryResponse: Decodable, Sendable {
    let repository: RepositoryACLQueryRepository?
}

private struct RepositoryACLQueryRepository: Decodable, Sendable {
    let acls: RepositoryACLPage
}

private struct RepositoryACLPage: Decodable, Sendable {
    let results: [RepositoryACLEntry]
}

private struct RepositoryACLMutationResponse: Decodable, Sendable {
    let updateACL: RepositoryACLEntry
}

private struct RepositoryACLDeleteResponse: Decodable, Sendable {
    let deleteACL: RepositoryACLDeletedEntry
}

private struct RepositoryACLDeletedEntry: Decodable, Sendable {
    let id: Int
}

struct RepositoryACLService: RepositoryACLServicing {
    private let client: SRHTClient
    private let service: SRHTService

    init(client: SRHTClient, service: SRHTService) {
        self.client = client
        self.service = service
    }

    func fetchACLs(repositoryRid: String) async throws -> [RepositoryACLEntry] {
        let response = try await client.execute(
            service: service,
            query: Self.aclsQuery,
            variables: ["rid": repositoryRid],
            responseType: RepositoryACLQueryResponse.self
        )
        return response.repository?.acls.results ?? []
    }

    func upsertACL(repositoryId: Int, entity: String, mode: AccessMode) async throws -> RepositoryACLEntry {
        let response = try await client.execute(
            service: service,
            query: Self.upsertACLMutation,
            variables: [
                "repoId": repositoryId,
                "entity": entity,
                "mode": mode.rawValue
            ],
            responseType: RepositoryACLMutationResponse.self
        )
        return response.updateACL
    }

    func deleteACL(entryId: Int) async throws {
        _ = try await client.execute(
            service: service,
            query: Self.deleteACLMutation,
            variables: ["id": entryId],
            responseType: RepositoryACLDeleteResponse.self
        )
    }
}

private extension RepositoryACLService {
    static let aclsQuery = """
    query repositoryACLs($rid: ID!) {
        repository(rid: $rid) {
            acls {
                results {
                    id
                    mode
                    entity { canonicalName }
                }
            }
        }
    }
    """

    static let upsertACLMutation = """
    mutation updateACL($repoId: Int!, $mode: AccessMode!, $entity: String!) {
        updateACL(repoId: $repoId, mode: $mode, entity: $entity) {
            id
            mode
            entity { canonicalName }
        }
    }
    """

    static let deleteACLMutation = """
    mutation deleteACL($id: Int!) {
        deleteACL(id: $id) { id }
    }
    """
}