nsarchive 2.0.0b2__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/archives.py +24 -7
- nsarchive/cls/base.py +139 -81
- nsarchive/cls/economy.py +59 -3
- nsarchive/cls/entities.py +279 -67
- nsarchive/cls/republic.py +40 -2
- nsarchive/instances/_economy.py +85 -24
- nsarchive/instances/_entities.py +69 -153
- nsarchive/instances/_republic.py +64 -20
- nsarchive-3.0.0a2.dist-info/METADATA +19 -0
- nsarchive-3.0.0a2.dist-info/RECORD +15 -0
- nsarchive/cls/exceptions.py +0 -25
- nsarchive-2.0.0b2.dist-info/METADATA +0 -177
- nsarchive-2.0.0b2.dist-info/RECORD +0 -16
- {nsarchive-2.0.0b2.dist-info → nsarchive-3.0.0a2.dist-info}/LICENSE +0 -0
- {nsarchive-2.0.0b2.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/archives.py
CHANGED
@@ -3,7 +3,24 @@ import time
|
|
3
3
|
from .base import *
|
4
4
|
|
5
5
|
class Archive:
|
6
|
-
def __init__(self, author:
|
6
|
+
def __init__(self, author: NSID = '0', target: NSID = '0'):
|
7
|
+
"""
|
8
|
+
Classe de référence pour toutes les archives.
|
9
|
+
|
10
|
+
## Attributs de base
|
11
|
+
- date: `int`\n
|
12
|
+
Date (timestamp) de l'exécution de l'archive
|
13
|
+
- id: `NSID`\n
|
14
|
+
Clé d'identification des archives (basée sur la date)
|
15
|
+
- author: `NSID`\n
|
16
|
+
ID de l'auteur de l'action
|
17
|
+
- target: `NSID`:
|
18
|
+
ID de la cible de l'action
|
19
|
+
- action: `str`:\n
|
20
|
+
Action effectuée
|
21
|
+
- details: `dict`\n
|
22
|
+
Ensemble de détails que les différents bots peuvent utiliser
|
23
|
+
"""
|
7
24
|
self.date: int = round(time.time())
|
8
25
|
|
9
26
|
self.id: NSID = NSID(self.date)
|
@@ -19,7 +36,7 @@ class Archive:
|
|
19
36
|
# Entities
|
20
37
|
|
21
38
|
class Sanction(Archive):
|
22
|
-
def __init__(self, author:
|
39
|
+
def __init__(self, author: NSID, target: NSID) -> None:
|
23
40
|
super().__init__(author, target)
|
24
41
|
|
25
42
|
self.details: dict = {
|
@@ -29,7 +46,7 @@ class Sanction(Archive):
|
|
29
46
|
}
|
30
47
|
|
31
48
|
class Report(Archive):
|
32
|
-
def __init__(self, author:
|
49
|
+
def __init__(self, author: NSID, target: NSID) -> None:
|
33
50
|
super().__init__(author, target)
|
34
51
|
|
35
52
|
self.details: dict = {
|
@@ -41,7 +58,7 @@ class Report(Archive):
|
|
41
58
|
# Community
|
42
59
|
|
43
60
|
class Election(Archive):
|
44
|
-
def __init__(self, author:
|
61
|
+
def __init__(self, author: NSID, target: NSID, position: str) -> None:
|
45
62
|
super().__init__(author, target)
|
46
63
|
|
47
64
|
self.details = {
|
@@ -51,7 +68,7 @@ class Election(Archive):
|
|
51
68
|
}
|
52
69
|
|
53
70
|
class Promotion(Archive):
|
54
|
-
def __init__(self, author:
|
71
|
+
def __init__(self, author: NSID, target: NSID, position: str) -> None:
|
55
72
|
super().__init__(author, target)
|
56
73
|
|
57
74
|
self.details = {
|
@@ -59,14 +76,14 @@ class Promotion(Archive):
|
|
59
76
|
}
|
60
77
|
|
61
78
|
class Demotion(Archive):
|
62
|
-
def __init__(self, author:
|
79
|
+
def __init__(self, author: NSID, target: NSID) -> None:
|
63
80
|
super().__init__(author, target)
|
64
81
|
|
65
82
|
|
66
83
|
# Bank
|
67
84
|
|
68
85
|
class Transaction(Archive):
|
69
|
-
def __init__(self, author:
|
86
|
+
def __init__(self, author: NSID, target: NSID) -> None:
|
70
87
|
super().__init__(author, target)
|
71
88
|
|
72
89
|
self.details = {
|
nsarchive/cls/base.py
CHANGED
@@ -1,9 +1,15 @@
|
|
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):
|
8
|
+
"""
|
9
|
+
Nation Server ID
|
10
|
+
|
11
|
+
ID unique et universel pour l'ensemble des entités et évènements. Il prend les `int`, les `str` et les autres instances `NSID` pour les convertir en un identifiant hexadécimal.
|
12
|
+
"""
|
7
13
|
unknown = "0"
|
8
14
|
admin = "1"
|
9
15
|
gov = "2"
|
@@ -35,134 +41,178 @@ class NSID(str):
|
|
35
41
|
return instance
|
36
42
|
|
37
43
|
class Instance:
|
38
|
-
|
39
|
-
|
44
|
+
"""
|
45
|
+
Instance qui servira de base à toutes les instances.
|
46
|
+
"""
|
47
|
+
|
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']}")
|
40
69
|
|
41
|
-
def
|
70
|
+
def _get_item(self, endpoint: str, body: dict = None, headers: dict = None) -> dict:
|
42
71
|
"""
|
43
|
-
Récupère des données JSON
|
72
|
+
Récupère des données JSON depuis l'API
|
44
73
|
|
45
74
|
## Paramètres
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
75
|
+
endpoint: `str`:
|
76
|
+
Endpoint de l'URL
|
77
|
+
headers: `dict` (optional)
|
78
|
+
Headers à envoyer
|
79
|
+
body: `dict` (optional)
|
80
|
+
Données à envoyer
|
52
81
|
|
53
82
|
## Renvoie
|
54
83
|
- `list` de tous les élements correspondants
|
55
84
|
- `None` si aucune donnée n'est trouvée
|
56
85
|
"""
|
57
86
|
|
58
|
-
if
|
59
|
-
|
60
|
-
else:
|
61
|
-
res = self.db.from_(table).select("*").execute()
|
87
|
+
if not headers:
|
88
|
+
headers = self.default_headers
|
62
89
|
|
63
|
-
|
64
|
-
return res.data
|
65
|
-
else:
|
66
|
-
return None
|
90
|
+
res = requests.get(f"{self.url}/{endpoint}", headers = headers, json = body, timeout = 5)
|
67
91
|
|
68
|
-
|
69
|
-
|
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']}")
|
70
100
|
|
71
|
-
|
72
|
-
|
101
|
+
def _get_by_ID(self, _class: str, id: NSID) -> dict:
|
102
|
+
_data = self._get_item(f"/model/{_class}/{id}")
|
73
103
|
|
74
104
|
return _data
|
75
105
|
|
76
|
-
def _put_in_db(self,
|
106
|
+
def _put_in_db(self, endpoint: str, body: dict, headers: dict = None, use_PUT: bool = False) -> None:
|
77
107
|
"""
|
78
|
-
Publie des données JSON dans une table
|
108
|
+
Publie des données JSON dans une table nation-db.
|
79
109
|
|
80
|
-
|
81
|
-
:
|
82
|
-
|
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
|
83
117
|
"""
|
84
118
|
|
85
|
-
|
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)
|
86
126
|
|
87
|
-
|
127
|
+
if 200 <= res.status_code < 300:
|
128
|
+
return res.json()
|
129
|
+
else:
|
130
|
+
print(res.text)
|
131
|
+
res.raise_for_status()
|
88
132
|
|
89
|
-
def
|
133
|
+
def _delete(self, _class: str, ids: list[NSID]) -> None:
|
90
134
|
"""
|
91
|
-
Supprime
|
135
|
+
Supprime des données JSON dans une table nation-db.
|
92
136
|
|
93
137
|
## Paramètres
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
value: `str`
|
99
|
-
Valeur de la clé à vérifier pour trouver l'enregistrement à supprimer
|
100
|
-
|
101
|
-
## Renvoie
|
102
|
-
- `True` si la suppression a réussi
|
103
|
-
- `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
|
104
142
|
"""
|
105
143
|
|
106
|
-
res =
|
144
|
+
res = requests.post(f"{self.url}/delete_{_class}", json = { "ids": ids })
|
107
145
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
def fetch(self, table: str, **query: typing.Any) -> list:
|
116
|
-
matches = []
|
117
|
-
|
118
|
-
for key, value in query.items():
|
119
|
-
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']}")
|
120
152
|
|
121
|
-
|
122
|
-
|
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)
|
123
156
|
|
124
|
-
|
125
|
-
|
157
|
+
def fetch(self, _class: str, **query: typing.Any) -> list:
|
158
|
+
res = requests.get(f"{self.url}/fetch/{_class}", params = query)
|
126
159
|
|
127
|
-
if
|
128
|
-
|
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()
|
129
166
|
|
130
|
-
|
167
|
+
return matches
|
131
168
|
|
132
|
-
return _res
|
133
169
|
|
134
|
-
def
|
170
|
+
def _upload_file(self, bucket: str, name: str, data: bytes, overwrite: bool = False, headers: dict = None) -> dict:
|
135
171
|
"""
|
136
|
-
Envoie un fichier dans un bucket
|
172
|
+
Envoie un fichier dans un bucket nation-db.
|
137
173
|
|
138
174
|
## Paramètres
|
139
|
-
bucket: `str
|
175
|
+
bucket: `str`
|
140
176
|
Nom du bucket où le fichier sera stocké
|
141
|
-
|
177
|
+
name: `str`
|
178
|
+
Nom du fichier dans le drive
|
179
|
+
data: `bytes`
|
142
180
|
Données à uploader
|
143
|
-
|
144
|
-
|
181
|
+
overwrite: `bool` (optional)
|
182
|
+
Overwrite ou non
|
183
|
+
headers: `dict` (optional)
|
184
|
+
Headers à envoyer
|
145
185
|
|
146
186
|
## Renvoie
|
147
187
|
- `dict` contenant les informations de l'upload si réussi
|
148
188
|
- `None` en cas d'échec
|
149
189
|
"""
|
150
190
|
|
151
|
-
|
191
|
+
if not headers:
|
192
|
+
headers = self.default_headers
|
193
|
+
headers['Content-Type'] = 'image/png'
|
152
194
|
|
153
|
-
|
154
|
-
|
195
|
+
body = {
|
196
|
+
"name": name,
|
197
|
+
"overwrite": json.dumps(overwrite)
|
198
|
+
}
|
155
199
|
|
156
|
-
|
200
|
+
file = ("file", "image/png", data)
|
157
201
|
|
158
|
-
|
159
|
-
print("Erreur lors de l'upload:", res["error"])
|
202
|
+
res = requests.put(f"{self.url}/upload_file/{bucket}", headers = headers, json = body, files = [ file ])
|
160
203
|
|
161
|
-
|
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']}")
|
162
212
|
|
163
|
-
def _download_from_storage(self, bucket: str, path: str) -> bytes:
|
213
|
+
def _download_from_storage(self, bucket: str, path: str, headers: dict = None) -> bytes:
|
164
214
|
"""
|
165
|
-
Télécharge un fichier depuis le stockage
|
215
|
+
Télécharge un fichier depuis le stockage nation-db.
|
166
216
|
|
167
217
|
## Paramètres
|
168
218
|
bucket: `str`\n
|
@@ -174,6 +224,14 @@ class Instance:
|
|
174
224
|
- Le fichier demandé en `bytes`
|
175
225
|
"""
|
176
226
|
|
177
|
-
|
227
|
+
if not headers:
|
228
|
+
headers = self.default_headers
|
178
229
|
|
179
|
-
|
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/economy.py
CHANGED
@@ -1,22 +1,62 @@
|
|
1
1
|
from .base import NSID
|
2
2
|
|
3
3
|
class BankAccount:
|
4
|
-
|
4
|
+
"""
|
5
|
+
Compte en banque d'une entité, individuelle ou collective.
|
6
|
+
|
7
|
+
## Attributs
|
8
|
+
- id: `NSID`\n
|
9
|
+
Identifiant du compte
|
10
|
+
- owner: `NSID`\n
|
11
|
+
Identifiant du titulaire du compte
|
12
|
+
- amount: `int`\n
|
13
|
+
Somme d'argent totale sur le compte
|
14
|
+
- frozen: `bool`\n
|
15
|
+
État gelé ou non du compte
|
16
|
+
- bank: `NSID`\n
|
17
|
+
Identifiant de la banque qui détient le compte
|
18
|
+
- income: `int`\n
|
19
|
+
Somme entrante sur le compte depuis la dernière réinitialisation (tous les ~ 28 jours)
|
20
|
+
"""
|
21
|
+
|
22
|
+
def __init__(self, id: NSID) -> None:
|
5
23
|
self.id: NSID = NSID(id)
|
6
24
|
self.owner: NSID = NSID(0)
|
7
25
|
self.amount: int = 0
|
8
26
|
self.frozen: bool = False
|
9
|
-
self.bank:
|
27
|
+
self.bank: NSID = NSID("6")
|
10
28
|
|
11
29
|
self.income: int = 0
|
12
30
|
|
13
31
|
class Item:
|
14
|
-
|
32
|
+
"""
|
33
|
+
Article d'inventaire qui peut circuler sur le serveur
|
34
|
+
|
35
|
+
## Attributs
|
36
|
+
- id: `NSID`\n
|
37
|
+
Identifiant de l'objet
|
38
|
+
- title: `str`\n
|
39
|
+
Nom de l'objet
|
40
|
+
- emoji: `str`\n
|
41
|
+
Emoji lié à l'objet
|
42
|
+
"""
|
43
|
+
|
44
|
+
def __init__(self, id: NSID) -> None:
|
15
45
|
self.id: NSID = NSID(id)
|
16
46
|
self.title: str = "Unknown Object"
|
17
47
|
self.emoji: str = ":light_bulb:"
|
18
48
|
|
19
49
|
class Inventory:
|
50
|
+
"""
|
51
|
+
Inventaire d'un membre
|
52
|
+
|
53
|
+
## Attributs
|
54
|
+
- owner_id: `NSID`\n
|
55
|
+
ID du propriétaire de l'inventaire
|
56
|
+
- objects: `dict[str, NSID]`\n
|
57
|
+
Collection d'objets et leur quantité
|
58
|
+
"""
|
59
|
+
|
20
60
|
def __init__(self, owner_id: NSID) -> None:
|
21
61
|
self.owner_id: NSID = NSID(owner_id)
|
22
62
|
self.objects: dict[str, NSID] = {}
|
@@ -35,6 +75,22 @@ class Inventory:
|
|
35
75
|
self.objects[item.id] = 0
|
36
76
|
|
37
77
|
class Sale:
|
78
|
+
"""
|
79
|
+
Vente mettant en jeu un objet
|
80
|
+
|
81
|
+
## Attributs
|
82
|
+
- id: `NSID`\n
|
83
|
+
Identifiant de la vente
|
84
|
+
- item: `NSID`\n
|
85
|
+
Identifiant de l'objet mis en vente
|
86
|
+
- quantity: `int`\n
|
87
|
+
Quantité d'objets mis en vente
|
88
|
+
- price: `int`\n
|
89
|
+
Prix total du lot
|
90
|
+
- seller_id: `NSID`\n
|
91
|
+
Identifiant du vendeur
|
92
|
+
"""
|
93
|
+
|
38
94
|
def __init__(self, id: NSID, item: Item) -> None:
|
39
95
|
self.id: NSID = NSID(id)
|
40
96
|
self.item: NSID = NSID(item.id)
|