nsarchive 3.0.0a1__py3-none-any.whl → 3.0.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nsarchive/__init__.py +2 -5
- nsarchive/cls/base.py +131 -81
- nsarchive/cls/entities.py +157 -64
- nsarchive/instances/_economy.py +51 -8
- nsarchive/instances/_entities.py +59 -150
- nsarchive/instances/_republic.py +33 -7
- {nsarchive-3.0.0a1.dist-info → nsarchive-3.0.0a2.dist-info}/METADATA +1 -2
- nsarchive-3.0.0a2.dist-info/RECORD +15 -0
- nsarchive/cls/exceptions.py +0 -25
- nsarchive-3.0.0a1.dist-info/RECORD +0 -16
- {nsarchive-3.0.0a1.dist-info → nsarchive-3.0.0a2.dist-info}/LICENSE +0 -0
- {nsarchive-3.0.0a1.dist-info → nsarchive-3.0.0a2.dist-info}/WHEEL +0 -0
nsarchive/__init__.py
CHANGED
@@ -1,27 +1,24 @@
|
|
1
1
|
"""
|
2
2
|
nsarchive - API-wrapper pour récupérer des données liées à Nation.
|
3
3
|
|
4
|
-
Version:
|
4
|
+
Version: 3.0.0a2
|
5
5
|
License: GPL-3.0
|
6
6
|
Auteur : happex <110610727+okayhappex@users.noreply.github.com>
|
7
7
|
|
8
8
|
Dependencies:
|
9
9
|
- Python ^3.10
|
10
|
-
- supabase ^2.9.1
|
11
10
|
- pillow ^10.4
|
12
11
|
|
13
12
|
Le fichier README.md fournit des détails supplémentaires pour l'utilisation.
|
14
13
|
"""
|
15
14
|
|
16
|
-
# Import des types
|
15
|
+
# Import des types
|
17
16
|
from .cls.base import NSID
|
18
17
|
from .cls.archives import *
|
19
18
|
from .cls.entities import *
|
20
19
|
from .cls.republic import *
|
21
20
|
from .cls.economy import *
|
22
21
|
|
23
|
-
from .cls.exceptions import *
|
24
|
-
|
25
22
|
# Import des instances
|
26
23
|
from .instances._economy import EconomyInstance
|
27
24
|
from .instances._entities import EntityInstance
|
nsarchive/cls/base.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
import io
|
1
2
|
import json
|
3
|
+
import requests
|
2
4
|
import typing
|
3
|
-
|
4
|
-
from supabase import Client
|
5
|
+
import warnings
|
5
6
|
|
6
7
|
class NSID(str):
|
7
8
|
"""
|
@@ -43,134 +44,175 @@ class Instance:
|
|
43
44
|
"""
|
44
45
|
Instance qui servira de base à toutes les instances.
|
45
46
|
"""
|
46
|
-
def __init__(self, client: Client):
|
47
|
-
self.db = client
|
48
47
|
|
49
|
-
def
|
48
|
+
def __init__(self, url: str, token: str = None):
|
49
|
+
self.url = url
|
50
|
+
self.token = token
|
51
|
+
|
52
|
+
self.default_headers = {
|
53
|
+
"Authorization": f"Bearer {self.token}",
|
54
|
+
"Content-Type": "application/json",
|
55
|
+
}
|
56
|
+
|
57
|
+
def request_token(self, username: str, password: str) -> str | None:
|
58
|
+
res = requests.post(f"{self.url}/auth/login", json = {
|
59
|
+
"username": username,
|
60
|
+
"password": password
|
61
|
+
})
|
62
|
+
|
63
|
+
if res.status_code == 200:
|
64
|
+
return res.json()["token"]
|
65
|
+
elif res.status_code in (401, 403):
|
66
|
+
raise PermissionError(res.json()['message'])
|
67
|
+
else:
|
68
|
+
raise Exception(f"Error {res.status_code}: {res.json()['message']}")
|
69
|
+
|
70
|
+
def _get_item(self, endpoint: str, body: dict = None, headers: dict = None) -> dict:
|
50
71
|
"""
|
51
|
-
Récupère des données JSON
|
72
|
+
Récupère des données JSON depuis l'API
|
52
73
|
|
53
74
|
## Paramètres
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
75
|
+
endpoint: `str`:
|
76
|
+
Endpoint de l'URL
|
77
|
+
headers: `dict` (optional)
|
78
|
+
Headers à envoyer
|
79
|
+
body: `dict` (optional)
|
80
|
+
Données à envoyer
|
60
81
|
|
61
82
|
## Renvoie
|
62
83
|
- `list` de tous les élements correspondants
|
63
84
|
- `None` si aucune donnée n'est trouvée
|
64
85
|
"""
|
65
86
|
|
66
|
-
if
|
67
|
-
|
68
|
-
else:
|
69
|
-
res = self.db.from_(table).select("*").execute()
|
87
|
+
if not headers:
|
88
|
+
headers = self.default_headers
|
70
89
|
|
71
|
-
|
72
|
-
return res.data
|
73
|
-
else:
|
74
|
-
return None
|
90
|
+
res = requests.get(f"{self.url}/{endpoint}", headers = headers, json = body, timeout = 5)
|
75
91
|
|
76
|
-
|
77
|
-
|
92
|
+
if 200 <= res.status_code < 300:
|
93
|
+
return res.json()
|
94
|
+
elif res.status_code == 404:
|
95
|
+
return
|
96
|
+
elif res.status_code in (403, 401):
|
97
|
+
raise PermissionError(res.json()['message'])
|
98
|
+
else:
|
99
|
+
raise Exception(f"Error {res.status_code}: {res.json()['message']}")
|
78
100
|
|
79
|
-
|
80
|
-
|
101
|
+
def _get_by_ID(self, _class: str, id: NSID) -> dict:
|
102
|
+
_data = self._get_item(f"/model/{_class}/{id}")
|
81
103
|
|
82
104
|
return _data
|
83
105
|
|
84
|
-
def _put_in_db(self,
|
106
|
+
def _put_in_db(self, endpoint: str, body: dict, headers: dict = None, use_PUT: bool = False) -> None:
|
85
107
|
"""
|
86
|
-
Publie des données JSON dans une table
|
108
|
+
Publie des données JSON dans une table nation-db.
|
87
109
|
|
88
|
-
|
89
|
-
:
|
90
|
-
|
110
|
+
## Paramètres
|
111
|
+
endpoint: `str`
|
112
|
+
Endpoint de l'URL
|
113
|
+
body: `dict`
|
114
|
+
Données à envoyer
|
115
|
+
headers: `dict` (optionnel)
|
116
|
+
Headers à envoyer
|
91
117
|
"""
|
92
118
|
|
93
|
-
|
119
|
+
if not headers:
|
120
|
+
headers = headers
|
121
|
+
|
122
|
+
if use_PUT:
|
123
|
+
res = requests.put(f"{self.url}/{endpoint}", headers = headers, json = body)
|
124
|
+
else:
|
125
|
+
res = requests.post(f"{self.url}/{endpoint}", headers = headers, json = body)
|
94
126
|
|
95
|
-
|
127
|
+
if 200 <= res.status_code < 300:
|
128
|
+
return res.json()
|
129
|
+
else:
|
130
|
+
print(res.text)
|
131
|
+
res.raise_for_status()
|
96
132
|
|
97
|
-
def
|
133
|
+
def _delete(self, _class: str, ids: list[NSID]) -> None:
|
98
134
|
"""
|
99
|
-
Supprime
|
135
|
+
Supprime des données JSON dans une table nation-db.
|
100
136
|
|
101
137
|
## Paramètres
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
value: `str`
|
107
|
-
Valeur de la clé à vérifier pour trouver l'enregistrement à supprimer
|
108
|
-
|
109
|
-
## Renvoie
|
110
|
-
- `True` si la suppression a réussi
|
111
|
-
- `False` si aucune donnée n'a été trouvée ou si la suppression a échoué
|
138
|
+
_class: `str`
|
139
|
+
Classe des entités à supprimer
|
140
|
+
ids: `list[NSID]`
|
141
|
+
ID des entités à supprimer
|
112
142
|
"""
|
113
143
|
|
114
|
-
res =
|
144
|
+
res = requests.post(f"{self.url}/delete_{_class}", json = { "ids": ids })
|
115
145
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
def fetch(self, table: str, **query: typing.Any) -> list:
|
124
|
-
matches = []
|
125
|
-
|
126
|
-
for key, value in query.items():
|
127
|
-
entity = self._select_from_db(table, key, value)
|
146
|
+
if 200 <= res.status_code < 300:
|
147
|
+
return res.json()
|
148
|
+
elif res.status_code in (403, 401):
|
149
|
+
raise PermissionError(res.json()['message'])
|
150
|
+
else:
|
151
|
+
raise Exception(f"Error {res.status_code}: {res.json()['message']}")
|
128
152
|
|
129
|
-
|
130
|
-
|
153
|
+
def _delete_by_ID(self, _class: str, id: NSID):
|
154
|
+
warnings.showwarning("Method '_delete_by_id' is deprecated. Use '_delete' instead.")
|
155
|
+
self._delete(_class, id)
|
131
156
|
|
132
|
-
|
133
|
-
|
157
|
+
def fetch(self, _class: str, **query: typing.Any) -> list:
|
158
|
+
res = requests.get(f"{self.url}/fetch/{_class}", params = query)
|
134
159
|
|
135
|
-
if
|
136
|
-
|
160
|
+
if res.status_code == 200:
|
161
|
+
matches = res.json()
|
162
|
+
elif res.status_code in (401, 403):
|
163
|
+
matches = []
|
164
|
+
else:
|
165
|
+
res.raise_for_status()
|
137
166
|
|
138
|
-
|
167
|
+
return matches
|
139
168
|
|
140
|
-
return _res
|
141
169
|
|
142
|
-
def
|
170
|
+
def _upload_file(self, bucket: str, name: str, data: bytes, overwrite: bool = False, headers: dict = None) -> dict:
|
143
171
|
"""
|
144
|
-
Envoie un fichier dans un bucket
|
172
|
+
Envoie un fichier dans un bucket nation-db.
|
145
173
|
|
146
174
|
## Paramètres
|
147
|
-
bucket: `str
|
175
|
+
bucket: `str`
|
148
176
|
Nom du bucket où le fichier sera stocké
|
149
|
-
|
177
|
+
name: `str`
|
178
|
+
Nom du fichier dans le drive
|
179
|
+
data: `bytes`
|
150
180
|
Données à uploader
|
151
|
-
|
152
|
-
|
181
|
+
overwrite: `bool` (optional)
|
182
|
+
Overwrite ou non
|
183
|
+
headers: `dict` (optional)
|
184
|
+
Headers à envoyer
|
153
185
|
|
154
186
|
## Renvoie
|
155
187
|
- `dict` contenant les informations de l'upload si réussi
|
156
188
|
- `None` en cas d'échec
|
157
189
|
"""
|
158
190
|
|
159
|
-
|
191
|
+
if not headers:
|
192
|
+
headers = self.default_headers
|
193
|
+
headers['Content-Type'] = 'image/png'
|
160
194
|
|
161
|
-
|
162
|
-
|
195
|
+
body = {
|
196
|
+
"name": name,
|
197
|
+
"overwrite": json.dumps(overwrite)
|
198
|
+
}
|
163
199
|
|
164
|
-
|
200
|
+
file = ("file", "image/png", data)
|
165
201
|
|
166
|
-
|
167
|
-
print("Erreur lors de l'upload:", res["error"])
|
202
|
+
res = requests.put(f"{self.url}/upload_file/{bucket}", headers = headers, json = body, files = [ file ])
|
168
203
|
|
169
|
-
|
204
|
+
if res.status_code == 200:
|
205
|
+
return res.json()
|
206
|
+
elif res.status_code in (403, 401):
|
207
|
+
raise PermissionError(res.json()['message'])
|
208
|
+
elif res.status_code == 409:
|
209
|
+
raise FileExistsError(res.json()['message'])
|
210
|
+
else:
|
211
|
+
raise Exception(f"Error {res.status_code}: {res.json()['message']}")
|
170
212
|
|
171
|
-
def _download_from_storage(self, bucket: str, path: str) -> bytes:
|
213
|
+
def _download_from_storage(self, bucket: str, path: str, headers: dict = None) -> bytes:
|
172
214
|
"""
|
173
|
-
Télécharge un fichier depuis le stockage
|
215
|
+
Télécharge un fichier depuis le stockage nation-db.
|
174
216
|
|
175
217
|
## Paramètres
|
176
218
|
bucket: `str`\n
|
@@ -182,6 +224,14 @@ class Instance:
|
|
182
224
|
- Le fichier demandé en `bytes`
|
183
225
|
"""
|
184
226
|
|
185
|
-
|
227
|
+
if not headers:
|
228
|
+
headers = self.default_headers
|
186
229
|
|
187
|
-
|
230
|
+
res = requests.get(f"{self.url}/drive/{bucket}/{path}", headers = headers)
|
231
|
+
|
232
|
+
if res.status_code == 200:
|
233
|
+
return res.json()
|
234
|
+
elif res.status_code in (403, 401):
|
235
|
+
raise PermissionError(res.json()['message'])
|
236
|
+
else:
|
237
|
+
raise Exception(f"Error {res.status_code}: {res.json()['message']}")
|
nsarchive/cls/entities.py
CHANGED
@@ -1,36 +1,56 @@
|
|
1
|
+
import requests
|
1
2
|
import time
|
3
|
+
import typing
|
4
|
+
import urllib.parse
|
2
5
|
|
3
|
-
from .exceptions import *
|
4
6
|
from .base import NSID
|
5
7
|
|
6
8
|
from .. import utils
|
7
9
|
|
10
|
+
default_headers = {}
|
11
|
+
|
12
|
+
class Permission:
|
13
|
+
def __init__(self, initial: str = "----"):
|
14
|
+
self.append: bool
|
15
|
+
self.manage: bool
|
16
|
+
self.edit: bool
|
17
|
+
self.read: bool
|
18
|
+
|
19
|
+
self.load(initial)
|
20
|
+
|
21
|
+
def load(self, val: str) -> None:
|
22
|
+
if 'a' in val: self.append = True
|
23
|
+
if 'm' in val: self.manage = True
|
24
|
+
if 'e' in val: self.edit = True
|
25
|
+
if 'r' in val: self.read = True
|
26
|
+
|
8
27
|
class PositionPermissions:
|
9
28
|
"""
|
10
29
|
Permissions d'une position à l'échelle du serveur. Certaines sont attribuées selon l'appartenance à divers groupes ayant une position précise
|
11
30
|
"""
|
12
31
|
|
13
32
|
def __init__(self) -> None:
|
14
|
-
#
|
15
|
-
self.
|
16
|
-
self.
|
17
|
-
self.
|
18
|
-
self.
|
19
|
-
self.
|
20
|
-
self.
|
21
|
-
self.
|
22
|
-
self.
|
23
|
-
self.
|
24
|
-
self.
|
25
|
-
self.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
self.bank_accounts = Permission("a---") # APPEND = ouvrir un ou plusieurs comptes, MANAGE = voir les infos globales concernant les comptes en banque, EDIT = gérer des comptes en banque, READ = voir les infos d'un compte en banque individuel
|
34
|
+
self.bots = Permission() # APPEND = publier un message sous l'identité d'un bot, MANAGE = proposer d'héberger un bot, EDIT = changer les paramètres d'un bot, READ = /
|
35
|
+
self.constitution = Permission() # APPEND = laws.append, MANAGE = laws.manage, EDIT = modifier la constitution, READ = /
|
36
|
+
self.database = Permission() # APPEND = créer des sous-bases de données, MANAGE = gérer la abse de données, EDIT = modifier les éléments, READ = avoir accès à toutes les données sans exception
|
37
|
+
self.items = Permission("---r") # APPEND = vendre, MANAGE = gérer des items dont on n'est pas propriétaire (hors marketplace), EDIT = gérer des items dont on n'est pas propriétaire (dans le marketplace), READ = accéder au marketplace
|
38
|
+
self.laws = Permission() # APPEND = proposer un texte de loi, MANAGE = accepter ou refuser une proposition, EDIT = modifier un texte, READ = /
|
39
|
+
self.members = Permission("---r") # APPEND = créer des entités, MANAGE = modérer des entités (hors Discord), EDIT = modifier des entités, READ = voir le profil des entités
|
40
|
+
self.national_channel = Permission() # APPEND = prendre la parole sur la chaîne nationale, MANAGE = voir qui peut prendre la parole, EDIT = modifier le planning de la chaîne nationale, READ = /
|
41
|
+
self.organizations = Permission("---r") # APPEND = créer une nouvelle organisation, MANAGE = exécuter des actions administratives sur les organisations, EDIT = modifier des organisations, READ = voir le profil de n'importe quelle organisation
|
42
|
+
self.reports = Permission() # APPEND = déposer plainte, MANAGE = accépter ou refuser une plainte, EDIT = /, READ = accéder à des infos supplémentaires pour une plainte
|
43
|
+
self.state_budgets = Permission() # APPEND = débloquer un nouveau budget, MANAGE = gérer les budjets, EDIT = gérer les sommes pour chaque budjet, READ = accéder aux infos concernant les budgets
|
44
|
+
self.votes = Permission() # APPEND = déclencher un vote, MANAGE = fermer un vote, EDIT = /, READ = lire les propriétés d'un vote avant sa fermeture
|
45
|
+
|
46
|
+
def merge(self, permissions: dict[str, str] | typing.Self):
|
47
|
+
if isinstance(permissions, PositionPermissions):
|
48
|
+
permissions = permissions.__dict__
|
49
|
+
|
50
|
+
for key, val in permissions.items():
|
51
|
+
perm: Permission = self.__getattribute__(key)
|
52
|
+
perm.load(val)
|
30
53
|
|
31
|
-
def edit(self, **permissions: bool) -> None:
|
32
|
-
for perm in permissions.items():
|
33
|
-
self.__setattr__(*perm)
|
34
54
|
|
35
55
|
class Position:
|
36
56
|
"""
|
@@ -71,7 +91,9 @@ class Entity:
|
|
71
91
|
"""
|
72
92
|
|
73
93
|
def __init__(self, id: NSID) -> None:
|
74
|
-
self.
|
94
|
+
self._url = "" # URL de l'entité pour une requête GET
|
95
|
+
|
96
|
+
self.id: NSID = NSID(id) # ID hexadécimal de l'entité
|
75
97
|
self.name: str = "Entité Inconnue"
|
76
98
|
self.registerDate: int = 0
|
77
99
|
self.position: Position = Position()
|
@@ -79,19 +101,55 @@ class Entity:
|
|
79
101
|
|
80
102
|
def set_name(self, new_name: str) -> None:
|
81
103
|
if len(new_name) > 32:
|
82
|
-
raise
|
104
|
+
raise ValueError(f"Name length mustn't exceed 32 characters.")
|
105
|
+
|
106
|
+
res = requests.post(f"{self._url}/rename?name={new_name}", headers = default_headers)
|
83
107
|
|
84
|
-
|
108
|
+
if res.status_code == 200:
|
109
|
+
self.name = new_name
|
110
|
+
else:
|
111
|
+
print(res.status_code)
|
112
|
+
res.raise_for_status()
|
85
113
|
|
86
114
|
def set_position(self, position: Position) -> None:
|
87
|
-
self.position =
|
115
|
+
res = requests.post(f"{self._url}/change_position?position={position.id}", headers = default_headers)
|
116
|
+
|
117
|
+
if res.status_code == 200:
|
118
|
+
self.position = position
|
119
|
+
else:
|
120
|
+
res.raise_for_status()
|
88
121
|
|
89
122
|
def add_link(self, key: str, value: str | int) -> None:
|
90
|
-
if isinstance(value, str)
|
123
|
+
if isinstance(value, str):
|
124
|
+
_class = "string"
|
125
|
+
elif isinstance(value, int):
|
126
|
+
_class = "integer"
|
127
|
+
else:
|
128
|
+
raise TypeError("Only strings and integers can be recorded as an additional link")
|
129
|
+
|
130
|
+
params = {
|
131
|
+
"link": key,
|
132
|
+
"value": value,
|
133
|
+
"type": _class
|
134
|
+
}
|
135
|
+
|
136
|
+
query = "&".join(f"{k}={ urllib.parse.quote(v) }" for k, v in params.items())
|
137
|
+
|
138
|
+
res = requests.post(f"{self._url}/add_link?{query}", headers = default_headers)
|
139
|
+
|
140
|
+
if res.status_code == 200:
|
91
141
|
self.additional[key] = value
|
142
|
+
else:
|
143
|
+
print(res.text)
|
144
|
+
res.raise_for_status()
|
92
145
|
|
93
146
|
def unlink(self, key: str) -> None:
|
94
|
-
|
147
|
+
res = requests.post(f"{self._url}/remove_link?link={urllib.parse.quote(key)}", headers = default_headers)
|
148
|
+
|
149
|
+
if res.status_code == 200:
|
150
|
+
del self.additional[key]
|
151
|
+
else:
|
152
|
+
res.raise_for_status()
|
95
153
|
|
96
154
|
class User(Entity):
|
97
155
|
"""
|
@@ -102,9 +160,7 @@ class User(Entity):
|
|
102
160
|
- xp: `int`\n
|
103
161
|
Points d'expérience de l'entité
|
104
162
|
- boosts: `dict[str, int]`\n
|
105
|
-
Ensemble des boosts dont bénéficie l'entité
|
106
|
-
- permissions: `.PositionPermissions`\n
|
107
|
-
Fusion des permissions offertes par la position et les groupes
|
163
|
+
Ensemble des boosts dont bénéficie l'entité
|
108
164
|
- votes: `list[NSID]`\n
|
109
165
|
Liste des votes auxquels a participé l'entité
|
110
166
|
"""
|
@@ -114,11 +170,7 @@ class User(Entity):
|
|
114
170
|
|
115
171
|
self.xp: int = 0
|
116
172
|
self.boosts: dict[str, int] = {}
|
117
|
-
self.
|
118
|
-
self.votes: list[str] = []
|
119
|
-
|
120
|
-
def add_vote(self, id: NSID):
|
121
|
-
self.votes.append(NSID(id))
|
173
|
+
self.groups: list[NSID] = []
|
122
174
|
|
123
175
|
def get_level(self) -> None:
|
124
176
|
i = 0
|
@@ -128,15 +180,24 @@ class User(Entity):
|
|
128
180
|
return i
|
129
181
|
|
130
182
|
def add_xp(self, amount: int) -> None:
|
131
|
-
boost = 0 if 0 in self.boosts.values() else max(list(self.boosts.values()) + [ 1 ])
|
183
|
+
boost = 0 if 0 in self.boosts.values() or amount <= 0 else max(list(self.boosts.values()) + [ 1 ])
|
184
|
+
res = requests.post(f"{self._url}/add_xp?amount={amount * boost}", headers = default_headers)
|
132
185
|
|
133
|
-
|
186
|
+
if res.status_code == 200:
|
187
|
+
self.xp += amount * boost
|
188
|
+
else:
|
189
|
+
res.raise_for_status()
|
134
190
|
|
135
191
|
def edit_boost(self, name: str, multiplier: int = -1) -> None:
|
136
|
-
|
137
|
-
|
192
|
+
res = requests.post(f"{self._url}/edit_boost?boost={name}&multiplier={multiplier}", headers = default_headers)
|
193
|
+
|
194
|
+
if res.status_code == 200:
|
195
|
+
if multiplier >= 0:
|
196
|
+
self.boosts[name] = multiplier
|
197
|
+
else:
|
198
|
+
del self.boosts[name]
|
138
199
|
else:
|
139
|
-
|
200
|
+
res.raise_for_status()
|
140
201
|
|
141
202
|
class MemberPermissions:
|
142
203
|
"""
|
@@ -145,46 +206,55 @@ class MemberPermissions:
|
|
145
206
|
|
146
207
|
def __init__(self) -> None:
|
147
208
|
self.manage_organization = False # Renommer l'organisation, changer le logo
|
148
|
-
self.manage_roles = False # Changer les rôles des membres
|
149
209
|
self.manage_shares = False # Revaloriser les actions
|
210
|
+
self.manage_roles = False # Changer les rôles des membres
|
150
211
|
self.manage_members = False # Virer quelqu'un d'une entreprise, l'y inviter
|
151
212
|
|
152
213
|
def edit(self, **permissions: bool) -> None:
|
153
214
|
for perm in permissions.values():
|
154
215
|
self.__setattr__(*perm)
|
155
216
|
|
156
|
-
class GroupMember
|
217
|
+
class GroupMember:
|
157
218
|
"""
|
158
219
|
Membre au sein d'une entité collective
|
159
220
|
|
160
221
|
## Attributs
|
161
|
-
-
|
162
|
-
- permission_level: `int`\n
|
222
|
+
- permission_level: `dict[str, int]`\n
|
163
223
|
Niveau d'accréditation du membre (0 = salarié, 4 = administrateur)
|
164
224
|
"""
|
165
225
|
|
166
226
|
def __init__(self, id: NSID) -> None:
|
167
|
-
|
168
|
-
|
169
|
-
|
227
|
+
self.id = id
|
228
|
+
self.permission_level: dict = { # Échelle de permissions selon le groupe de travail
|
229
|
+
"general": 0
|
230
|
+
}
|
170
231
|
|
171
|
-
def group_permissions(self) -> MemberPermissions:
|
232
|
+
def group_permissions(self, team: str = "general") -> MemberPermissions:
|
172
233
|
p = MemberPermissions()
|
234
|
+
team_perms = self.permission_level[team]
|
173
235
|
|
174
|
-
if
|
236
|
+
if team_perms >= 1: # Responsable
|
175
237
|
p.manage_members = True
|
176
238
|
|
177
|
-
if
|
178
|
-
p.manage_shares = True
|
179
|
-
|
180
|
-
if self.permission_level >= 3:
|
239
|
+
if team_perms >= 2: # Superviseur
|
181
240
|
p.manage_roles = True
|
182
241
|
|
183
|
-
if
|
242
|
+
if team_perms >= 3: # Chef d'équipe
|
243
|
+
pass
|
244
|
+
|
245
|
+
if team_perms >= 4: # Directeur
|
246
|
+
p.manage_shares = True
|
184
247
|
p.manage_organization = True
|
185
248
|
|
186
249
|
return p
|
187
250
|
|
251
|
+
class GroupInvite:
|
252
|
+
def __init__(self, id: NSID):
|
253
|
+
self.id: NSID = id
|
254
|
+
self.team: str = "general"
|
255
|
+
self.level: str = 0
|
256
|
+
self._expires: int = round(time.time()) + 604800
|
257
|
+
|
188
258
|
class Share:
|
189
259
|
"""
|
190
260
|
Action d'une entreprise
|
@@ -242,32 +312,49 @@ class Organization(Entity):
|
|
242
312
|
|
243
313
|
self.certifications: dict = {}
|
244
314
|
self.members: list[GroupMember] = []
|
315
|
+
self.invites: dict[GroupInvite] = []
|
245
316
|
|
246
317
|
self.parts: list[Share] = 50 * [ Share(self.owner.id, 0) ]
|
247
318
|
|
248
|
-
def add_certification(self, certification: str) -> None:
|
249
|
-
self.
|
319
|
+
def add_certification(self, certification: str, __expires: int = 2419200) -> None:
|
320
|
+
res = requests.post(f"{self._url}/add_certification?name={certification}&duration={__expires}", headers = default_headers)
|
321
|
+
|
322
|
+
if res.status_code == 200:
|
323
|
+
self.certifications[certification] = int(round(time.time()) + __expires)
|
324
|
+
else:
|
325
|
+
res.raise_for_status()
|
250
326
|
|
251
327
|
def has_certification(self, certification: str) -> bool:
|
252
328
|
return certification in self.certifications.keys()
|
253
329
|
|
254
330
|
def remove_certification(self, certification: str) -> None:
|
255
|
-
|
331
|
+
res = requests.post(f"{self._url}/remove_certification?name={certification}", headers = default_headers)
|
332
|
+
|
333
|
+
if res.status_code == 200:
|
334
|
+
del self.certifications[certification]
|
335
|
+
else:
|
336
|
+
res.raise_for_status()
|
337
|
+
|
338
|
+
def invite_member(self, member: NSID, level: int = 0, team: str = "general") -> None:
|
339
|
+
if not isinstance(member, NSID):
|
340
|
+
raise TypeError("L'entrée membre doit être de type NSID")
|
256
341
|
|
257
|
-
|
258
|
-
if not isinstance(member, GroupMember):
|
259
|
-
raise TypeError("Le membre doit être de type GroupMember")
|
342
|
+
res = requests.post(f"{self._url}/invite_member?id={member}&level={level}&team={team}", headers = default_headers)
|
260
343
|
|
261
|
-
|
344
|
+
if res.status_code == 200:
|
345
|
+
invite = GroupInvite(member)
|
346
|
+
invite.team = team
|
347
|
+
invite.level = level
|
348
|
+
|
349
|
+
self.invites.append(invite)
|
350
|
+
else:
|
351
|
+
res.raise_for_status()
|
262
352
|
|
263
353
|
def remove_member(self, member: GroupMember) -> None:
|
264
354
|
for _member in self.members:
|
265
355
|
if _member.id == member.id:
|
266
356
|
self.members.remove(_member)
|
267
357
|
|
268
|
-
def append(self, member: GroupMember) -> None:
|
269
|
-
self.add_member(member)
|
270
|
-
|
271
358
|
def remove(self, member: GroupMember) -> None:
|
272
359
|
self.remove_member(member)
|
273
360
|
|
@@ -296,4 +383,10 @@ class Organization(Entity):
|
|
296
383
|
else:
|
297
384
|
shares[share.owner] = 1
|
298
385
|
|
299
|
-
return shares
|
386
|
+
return shares
|
387
|
+
|
388
|
+
def save_avatar(self, data: bytes = None):
|
389
|
+
if not data:
|
390
|
+
return
|
391
|
+
|
392
|
+
self.avatar = data
|