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 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: 2.0.0
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 et des exceptions
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: str | NSID = '0', target: str | NSID = '0') -> None:
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: str | NSID, target: str | NSID) -> None:
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: str | NSID, target: str | NSID) -> None:
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: str | NSID, target: str | NSID, position: str) -> None:
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: str | NSID, target: str | NSID, position: str) -> None:
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: str | NSID, target: str | NSID) -> None:
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: str | NSID, target: str | NSID) -> None:
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
- def __init__(self, client: Client):
39
- self.db = client
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 _select_from_db(self, table: str, key: str = None, value: str = None) -> list:
70
+ def _get_item(self, endpoint: str, body: dict = None, headers: dict = None) -> dict:
42
71
  """
43
- Récupère des données JSON d'une table Supabase en fonction de l'ID.
72
+ Récupère des données JSON depuis l'API
44
73
 
45
74
  ## Paramètres
46
- table: `str`:\n
47
- Nom de la base
48
- key: `str`\n
49
- Clé à vérifier
50
- value: `str`\n
51
- Valeur de la clé à vérifier
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 key and value:
59
- res = self.db.from_(table).select("*").eq(key, value).execute()
60
- else:
61
- res = self.db.from_(table).select("*").execute()
87
+ if not headers:
88
+ headers = self.default_headers
62
89
 
63
- if res.data:
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
- def _get_by_ID(self, table: str, id: NSID) -> dict:
69
- _data = self._select_from_db(table, 'id', id)
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
- if _data is not None:
72
- _data = _data[0]
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, table: str, data: dict) -> None:
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 Supabase en utilisant le client Supabase.
108
+ Publie des données JSON dans une table nation-db.
79
109
 
80
- :param table: Nom de la table dans laquelle les données doivent être insérées
81
- :param data: Dictionnaire contenant les données à publier
82
- :return: Résultat de l'insertion
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
- res = self.db.from_(table).upsert(data).execute()
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
- return res
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 _delete_from_db(self, table: str, key: str, value: str):
133
+ def _delete(self, _class: str, ids: list[NSID]) -> None:
90
134
  """
91
- Supprime un enregistrement d'une table Supabase en fonction d'une clé et de sa valeur.
135
+ Supprime des données JSON dans une table nation-db.
92
136
 
93
137
  ## Paramètres
94
- table: `str`
95
- Nom de la table dans laquelle les données doivent être supprimées
96
- key: `str`
97
- Clé à vérifier (par exemple "id" ou autre clé unique)
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 = self.db.from_(table).delete().eq(key, value).execute()
144
+ res = requests.post(f"{self.url}/delete_{_class}", json = { "ids": ids })
107
145
 
108
- return res
109
-
110
- def _delete_by_ID(self, table: str, id: NSID):
111
- res = self._delete_from_db(table, 'id', id)
112
-
113
- return res
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
- if entity is not None:
122
- matches.append(entity)
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
- if query == {}:
125
- matches = [ self._select_from_db(table) ]
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 not matches or (len(matches) != len(query) and query != {}):
128
- return []
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
- _res = [ item for item in matches[0] if all(item in match for match in matches[1:]) ]
167
+ return matches
131
168
 
132
- return _res
133
169
 
134
- def _upload_to_storage(self, bucket: str, data: bytes, path: str, overwrite: bool = False, options: dict = {'content-type': 'image/png'}) -> dict:
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 Supabase.
172
+ Envoie un fichier dans un bucket nation-db.
137
173
 
138
174
  ## Paramètres
139
- bucket: `str`\n
175
+ bucket: `str`
140
176
  Nom du bucket où le fichier sera stocké
141
- data: `bytes`\n
177
+ name: `str`
178
+ Nom du fichier dans le drive
179
+ data: `bytes`
142
180
  Données à uploader
143
- path: `str`\n
144
- Chemin dans le bucket où le fichier sera stocké
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
- options["upsert"] = json.dumps(overwrite)
191
+ if not headers:
192
+ headers = self.default_headers
193
+ headers['Content-Type'] = 'image/png'
152
194
 
153
- if len(data) > 5 * 1000 ** 3:
154
- raise ValueError("La limite d'un fichier à upload est de 1Mo")
195
+ body = {
196
+ "name": name,
197
+ "overwrite": json.dumps(overwrite)
198
+ }
155
199
 
156
- res = self.db.storage.from_(bucket).upload(path, data, options)
200
+ file = ("file", "image/png", data)
157
201
 
158
- if res.json().get("error"):
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
- return res
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 Supabase.
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
- res = self.db.storage.from_(bucket).download(path)
227
+ if not headers:
228
+ headers = self.default_headers
178
229
 
179
- return res
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
- def __init__(self, id: str | NSID) -> None:
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: str = "HexaBank"
27
+ self.bank: NSID = NSID("6")
10
28
 
11
29
  self.income: int = 0
12
30
 
13
31
  class Item:
14
- def __init__(self, id: str | NSID) -> None:
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)