From 0418b31e5cf75b7c0c6b43a49dd105ba60ded10c Mon Sep 17 00:00:00 2001 From: emsoraffa Date: Thu, 25 Apr 2024 21:07:48 +0200 Subject: [PATCH 1/5] feat: algo prototype --- backend/root/utils/permission_algorithm.py | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 backend/root/utils/permission_algorithm.py diff --git a/backend/root/utils/permission_algorithm.py b/backend/root/utils/permission_algorithm.py new file mode 100644 index 000000000..faacecc25 --- /dev/null +++ b/backend/root/utils/permission_algorithm.py @@ -0,0 +1,88 @@ +from collections import OrderedDict +# TODO:use collections? improve performance? + + +class Permissions: + # FIX: permissions added multipletimes. + def __init__(self, dictionary): + self.dict = dictionary + self.index_array = list(dictionary.keys()) + + def __getitem__(self, key): + return self.dict[key] + + def __str__(self): + return str(self.dict) + + def get(self, index): + return self.dict[self.index_array[index]] + + def set(self, key, value): + self.dict[key] = value + + def get_index_array(self): + return self.index_array + + def clean(self): + for key, value in self.dict.items(): + self.dict[key] = ''.join(sorted(set(value))) + + +class Graph: + # TODO: implement using set. + def __init__(self, vertices): + self.V = vertices + + def printAdjMatrix(self, reach): + print('Following matrix transitive closure of the given graph ') + for i in range(self.V): + for j in range(self.V): + if i == j: + print('%7d\t' % (1), end=' ') + else: + print('%7d\t' % (reach[i][j]), end=' ') + print() + + def compute_permissions(self, graph, permissions): + reach = [i[:] for i in graph] + index_array = permissions.get_index_array() + + for k in range(self.V): + for i in range(self.V): + for j in range(self.V): + reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]) + if reach[i][j] == 1: + permissions.set( + index_array[j], + permissions.get(j) + permissions[index_array[i]], + ) + + self.printAdjMatrix(reach) + print('') + + permissions.clean() + print(permissions) + + return permissions + + +g = Graph(5) + +graph = [ + [1, 0, 1, 0, 0], + [0, 1, 1, 0, 1], + [0, 0, 1, 1, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1], +] + +p = Permissions( + { + 'Ansatt': 'B', + 'Hest': 'A', + 'Mellomleder': 'C', + 'Sjef': 'D', + 'Baltazar': 'E', + } +) +g.compute_permissions(graph, p) From bf38ac9eb377872f9ca99c05f8b2fdaa53c1e80c Mon Sep 17 00:00:00 2001 From: emsoraffa Date: Thu, 25 Apr 2024 22:08:14 +0200 Subject: [PATCH 2/5] feat: add annotations --- backend/root/utils/compute_permissions.py | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 backend/root/utils/compute_permissions.py diff --git a/backend/root/utils/compute_permissions.py b/backend/root/utils/compute_permissions.py new file mode 100644 index 000000000..73b6d0ce8 --- /dev/null +++ b/backend/root/utils/compute_permissions.py @@ -0,0 +1,43 @@ +from __future__ import annotations + + +class Permissions: + def __init__(self, dictionary: dict) -> None: + self.dict = dictionary + + +class Graph: + def __init__(self, vertices: list) -> None: + self.V = vertices + + def printAdjMatrix(self, reach: list) -> None: + print('Following matrix transitive closure of the given graph ') + for i in range(self, reach): + for j in range(self.V): + if i == j: + print('%7d\t' % (1), end=' ') + else: + print('%7d\t' % (reach[i][j]), end=' ') + print() + + def compute_permissions(self, graph: Graph, permissions: Permissions) -> Permissions: + reach = [i[:] for i in graph] + index_array = permissions.get_index_array() + + for k in range(self.V): + for i in range(self.V): + for j in range(self.V): + reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]) + if reach[i][j] == 1: + permissions.set( + index_array[j], + permissions.get(j) + permissions[index_array[i]], + ) + + self.printAdjMatrix(reach) + print('') + + permissions.clean() + print(permissions) + + return permissions From 1b012d96fb205af3463a24e9b2cdaf1b2eb3d641 Mon Sep 17 00:00:00 2001 From: emsoraffa Date: Tue, 14 May 2024 20:28:24 +0200 Subject: [PATCH 3/5] feat: added tests --- backend/root/utils/permission_algorithm.py | 100 +++++++-------------- backend/samfundet/tests/test_permission.py | 52 +++++++++++ 2 files changed, 84 insertions(+), 68 deletions(-) create mode 100644 backend/samfundet/tests/test_permission.py diff --git a/backend/root/utils/permission_algorithm.py b/backend/root/utils/permission_algorithm.py index faacecc25..3ae13d895 100644 --- a/backend/root/utils/permission_algorithm.py +++ b/backend/root/utils/permission_algorithm.py @@ -1,88 +1,52 @@ -from collections import OrderedDict -# TODO:use collections? improve performance? - +from __future__ import annotations class Permissions: - # FIX: permissions added multipletimes. - def __init__(self, dictionary): - self.dict = dictionary + def __init__(self, dictionary: dict): + self.dict = {k: set(v) for k, v in dictionary.items()} self.index_array = list(dictionary.keys()) - def __getitem__(self, key): - return self.dict[key] + def __getitem__(self, key: int) -> str: + return ''.join(sorted(self.dict[self.index_array[key]])) - def __str__(self): - return str(self.dict) + def __str__(self) -> str: + return str({k: ''.join(sorted(v)) for k, v in self.dict.items()}) - def get(self, index): + def get(self, index: int) -> set: return self.dict[self.index_array[index]] - def set(self, key, value): - self.dict[key] = value + def set(self, key: str, value: str) -> None: + if key in self.dict: + self.dict[key].update(value) + else: + raise KeyError("Key not found in permissions dictionary") - def get_index_array(self): + def get_index_array(self) -> list: return self.index_array - def clean(self): - for key, value in self.dict.items(): - self.dict[key] = ''.join(sorted(set(value))) - class Graph: - # TODO: implement using set. - def __init__(self, vertices): + def __init__(self, vertices: int, graph: list): self.V = vertices - - def printAdjMatrix(self, reach): - print('Following matrix transitive closure of the given graph ') - for i in range(self.V): - for j in range(self.V): - if i == j: - print('%7d\t' % (1), end=' ') - else: - print('%7d\t' % (reach[i][j]), end=' ') - print() - - def compute_permissions(self, graph, permissions): - reach = [i[:] for i in graph] + self.graph = graph + + def __str__(self) -> str: + matrix_str = '' + for row in self.graph: + for value in row: + matrix_str += '%7d\t' % value + matrix_str += '\n' + return matrix_str + + def compute_permissions(self, permissions: Permissions) -> Permissions: + reach = [row[:] for row in self.graph] index_array = permissions.get_index_array() for k in range(self.V): for i in range(self.V): for j in range(self.V): - reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]) - if reach[i][j] == 1: - permissions.set( - index_array[j], - permissions.get(j) + permissions[index_array[i]], - ) - - self.printAdjMatrix(reach) - print('') - - permissions.clean() - print(permissions) - + if reach[i][j] or (reach[i][k] and reach[k][j]): + reach[i][j] = 1 + permissions.set(index_array[j], permissions.get(i)) + # Update the graph's own matrix to reflect the transitive closure + self.graph = reach return permissions - - -g = Graph(5) - -graph = [ - [1, 0, 1, 0, 0], - [0, 1, 1, 0, 1], - [0, 0, 1, 1, 0], - [0, 0, 0, 1, 0], - [0, 0, 0, 0, 1], -] - -p = Permissions( - { - 'Ansatt': 'B', - 'Hest': 'A', - 'Mellomleder': 'C', - 'Sjef': 'D', - 'Baltazar': 'E', - } -) -g.compute_permissions(graph, p) diff --git a/backend/samfundet/tests/test_permission.py b/backend/samfundet/tests/test_permission.py new file mode 100644 index 000000000..4ad3deda6 --- /dev/null +++ b/backend/samfundet/tests/test_permission.py @@ -0,0 +1,52 @@ +from __future__ import annotations +import pytest +from samfundet.root.utils import Graph, Permissions # Adjust the import according to your project structure. + +def test_graph_compute_permissions(): + # Setup graph and permissions data. + graph_data = [ + [1, 0, 1, 0, 0], + [0, 1, 1, 0, 1], + [0, 0, 1, 1, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1], + ] + permissions_data = { + 'Ansatt': 'B', + 'Hest': 'A', + 'Mellomleder': 'C', + 'Sjef': 'D', + 'Baltazar': 'E', + } + + # Create instances of Graph and Permissions + p = Permissions(permissions_data) + g = Graph(5, graph_data) + + # Compute permissions + updated_permissions = g.compute_permissions(p) + + # Define expected results + expected_permissions = { + 'Ansatt': 'ABCDE', + 'Hest': 'ABCDE', + 'Mellomleder': 'CD', + 'Sjef': 'D', + 'Baltazar': 'E' + } + + # Assertions to check the correctness of the permissions computation + for key, value in expected_permissions.items(): + assert ''.join(sorted(updated_permissions.dict[key])) == value, f"Mismatch in permissions for {key}" + + expected_graph = [ + [1, 1, 1, 1, 1], + [1, 1, 1, 1, 1], + [0, 0, 1, 1, 1], + [0, 0, 0, 1, 1], + [0, 0, 0, 0, 1] + ] + assert g.graph == expected_graph, "Graph transitive closure incorrect" + +if __name__ == "__main__": + pytest.main() From 785c8e678e2758155333c18849d8015f6ba79e2f Mon Sep 17 00:00:00 2001 From: emsoraffa Date: Tue, 14 May 2024 20:38:09 +0200 Subject: [PATCH 4/5] remove old file --- backend/root/utils/compute_permissions.py | 43 ----------------------- 1 file changed, 43 deletions(-) delete mode 100644 backend/root/utils/compute_permissions.py diff --git a/backend/root/utils/compute_permissions.py b/backend/root/utils/compute_permissions.py deleted file mode 100644 index 73b6d0ce8..000000000 --- a/backend/root/utils/compute_permissions.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - - -class Permissions: - def __init__(self, dictionary: dict) -> None: - self.dict = dictionary - - -class Graph: - def __init__(self, vertices: list) -> None: - self.V = vertices - - def printAdjMatrix(self, reach: list) -> None: - print('Following matrix transitive closure of the given graph ') - for i in range(self, reach): - for j in range(self.V): - if i == j: - print('%7d\t' % (1), end=' ') - else: - print('%7d\t' % (reach[i][j]), end=' ') - print() - - def compute_permissions(self, graph: Graph, permissions: Permissions) -> Permissions: - reach = [i[:] for i in graph] - index_array = permissions.get_index_array() - - for k in range(self.V): - for i in range(self.V): - for j in range(self.V): - reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]) - if reach[i][j] == 1: - permissions.set( - index_array[j], - permissions.get(j) + permissions[index_array[i]], - ) - - self.printAdjMatrix(reach) - print('') - - permissions.clean() - print(permissions) - - return permissions From 928afe6698c108e3edd7ae812a7fee52b8865079 Mon Sep 17 00:00:00 2001 From: emsoraffa Date: Tue, 14 May 2024 21:47:06 +0200 Subject: [PATCH 5/5] fix: formatting, test assertion, naming --- backend/root/utils/permission_algorithm.py | 7 +++-- backend/samfundet/tests/test_permission.py | 32 ++++++++-------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/backend/root/utils/permission_algorithm.py b/backend/root/utils/permission_algorithm.py index 3ae13d895..69e966093 100644 --- a/backend/root/utils/permission_algorithm.py +++ b/backend/root/utils/permission_algorithm.py @@ -1,6 +1,7 @@ from __future__ import annotations -class Permissions: + +class PermissionDictionary: def __init__(self, dictionary: dict): self.dict = {k: set(v) for k, v in dictionary.items()} self.index_array = list(dictionary.keys()) @@ -18,7 +19,7 @@ def set(self, key: str, value: str) -> None: if key in self.dict: self.dict[key].update(value) else: - raise KeyError("Key not found in permissions dictionary") + raise KeyError('Key not found in permissions dictionary') def get_index_array(self) -> list: return self.index_array @@ -37,7 +38,7 @@ def __str__(self) -> str: matrix_str += '\n' return matrix_str - def compute_permissions(self, permissions: Permissions) -> Permissions: + def compute_permissions(self, permissions: PermissionDictionary) -> PermissionDictionary: reach = [row[:] for row in self.graph] index_array = permissions.get_index_array() diff --git a/backend/samfundet/tests/test_permission.py b/backend/samfundet/tests/test_permission.py index 4ad3deda6..c35d51ca5 100644 --- a/backend/samfundet/tests/test_permission.py +++ b/backend/samfundet/tests/test_permission.py @@ -1,6 +1,9 @@ from __future__ import annotations + import pytest -from samfundet.root.utils import Graph, Permissions # Adjust the import according to your project structure. + +from root.utils.permission_algorithm import Graph, PermissionDictionary + def test_graph_compute_permissions(): # Setup graph and permissions data. @@ -20,33 +23,22 @@ def test_graph_compute_permissions(): } # Create instances of Graph and Permissions - p = Permissions(permissions_data) + p = PermissionDictionary(permissions_data) g = Graph(5, graph_data) # Compute permissions updated_permissions = g.compute_permissions(p) # Define expected results - expected_permissions = { - 'Ansatt': 'ABCDE', - 'Hest': 'ABCDE', - 'Mellomleder': 'CD', - 'Sjef': 'D', - 'Baltazar': 'E' - } + expected_permissions = {'Ansatt': 'B', 'Hest': 'A', 'Mellomleder': 'ABC', 'Sjef': 'ABCD', 'Baltazar': 'AE'} # Assertions to check the correctness of the permissions computation for key, value in expected_permissions.items(): - assert ''.join(sorted(updated_permissions.dict[key])) == value, f"Mismatch in permissions for {key}" - - expected_graph = [ - [1, 1, 1, 1, 1], - [1, 1, 1, 1, 1], - [0, 0, 1, 1, 1], - [0, 0, 0, 1, 1], - [0, 0, 0, 0, 1] - ] - assert g.graph == expected_graph, "Graph transitive closure incorrect" + assert ''.join(sorted(updated_permissions.dict[key])) == value, f'Mismatch in permissions for {key}' + + expected_graph = [[1, 0, 1, 1, 0], [0, 1, 1, 1, 1], [0, 0, 1, 1, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]] + assert g.graph == expected_graph, 'Graph transitive closure incorrect' + -if __name__ == "__main__": +if __name__ == '__main__': pytest.main()