nsarchive 0.2a0__py3-none-any.whl → 1.0.1__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 +612 -50
- nsarchive/assets/default_avatar.png +0 -0
- nsarchive/cls/archives.py +70 -0
- nsarchive/cls/base.py +27 -0
- nsarchive/cls/economy.py +20 -0
- nsarchive/cls/entities.py +111 -53
- nsarchive/cls/exceptions.py +9 -0
- nsarchive/cls/republic.py +60 -0
- nsarchive/utils/assets.py +15 -0
- {nsarchive-0.2a0.dist-info → nsarchive-1.0.1.dist-info}/METADATA +4 -2
- nsarchive-1.0.1.dist-info/RECORD +13 -0
- nsarchive/cls/votes.py +0 -16
- nsarchive-0.2a0.dist-info/RECORD +0 -8
- {nsarchive-0.2a0.dist-info → nsarchive-1.0.1.dist-info}/LICENSE +0 -0
- {nsarchive-0.2a0.dist-info → nsarchive-1.0.1.dist-info}/WHEEL +0 -0
nsarchive/__init__.py
CHANGED
@@ -2,137 +2,699 @@ import time
|
|
2
2
|
|
3
3
|
import deta
|
4
4
|
|
5
|
+
from .cls.base import *
|
5
6
|
from .cls.entities import *
|
6
|
-
from .cls.
|
7
|
+
from .cls.archives import *
|
8
|
+
from .cls.republic import *
|
9
|
+
from .cls.economy import *
|
7
10
|
|
8
11
|
from .cls.exceptions import *
|
9
12
|
|
10
13
|
class EntityInstance:
|
14
|
+
"""
|
15
|
+
Instance qui vous permettra d'interagir avec les profils des membres ainsi que les différents métiers et secteurs d'activité.
|
16
|
+
|
17
|
+
## Informations disponibles
|
18
|
+
- Profil des membres et des entreprises: `.User | .Organization | .Entity`
|
19
|
+
- Participation d'un membre à différent votes: `.User | .Organization | .Entity`
|
20
|
+
- Appartenance et permissions d'un membre dans un groupe: `.GroupMember.MemberPermissions`
|
21
|
+
- Position légale et permissions d'une entité: `.Position.Permissions`
|
22
|
+
- Sanctions et modifications d'une entité: `.Action[ .AdminAction | .Sanction ]`
|
23
|
+
"""
|
11
24
|
def __init__(self, token: str) -> None:
|
12
25
|
self.db = deta.Deta(token)
|
13
26
|
self.base = self.db.Base('entities')
|
14
27
|
self.electors = self.db.Base('electors')
|
28
|
+
self.archives = self.db.Base('archives')
|
29
|
+
self.avatars = self.db.Drive('avatars')
|
30
|
+
self.positions = self.db.Base('positions') # Liste des métiers
|
31
|
+
|
32
|
+
def get_entity(self, id: str | NSID) -> User | Organization | Entity:
|
33
|
+
"""
|
34
|
+
Fonction permettant de récupérer le profil public d'une entité.\n
|
35
|
+
|
36
|
+
## Paramètres
|
37
|
+
id: `NSID`\n
|
38
|
+
ID héxadécimal de l'entité à récupérer
|
39
|
+
|
40
|
+
## Renvoie
|
41
|
+
- `.User` dans le cas où l'entité choisie est un membre
|
42
|
+
- `.Organization` dans le cas où c'est un groupe
|
43
|
+
- `.Entity` dans le cas où c'est indéterminé
|
44
|
+
"""
|
15
45
|
|
16
|
-
|
17
|
-
id = id.upper()
|
46
|
+
id = NSID(id)
|
18
47
|
_data = self.base.get(id)
|
48
|
+
_votes = self.electors.get(id)
|
19
49
|
|
20
50
|
if _data is None:
|
21
51
|
return Entity("0")
|
22
52
|
|
23
53
|
if _data['_type'] == 'user':
|
24
54
|
entity = User(id)
|
55
|
+
|
56
|
+
entity.xp = _data['xp']
|
57
|
+
entity.boosts = _data['boosts']
|
58
|
+
entity.votes = [ NSID(vote) for vote in _votes['votes'] ]
|
25
59
|
elif _data['_type'] == 'organization':
|
26
60
|
entity = Organization(id)
|
61
|
+
|
62
|
+
entity.owner = self.get_entity(NSID(_data['owner_id']))
|
63
|
+
|
64
|
+
for _member in _data['members']:
|
65
|
+
member = GroupMember(_member['id'])
|
66
|
+
member.permissions.__dict__ = _member['permissions']
|
67
|
+
|
68
|
+
try:
|
69
|
+
entity.avatar = self.avatars.get(id).read()
|
70
|
+
except:
|
71
|
+
entity.avatar = None
|
72
|
+
|
73
|
+
entity.certifications = _data['certifications']
|
27
74
|
else:
|
28
75
|
entity = Entity(id)
|
29
76
|
|
30
77
|
entity.name = _data['name']
|
31
78
|
entity.legalPosition = _data['legalPosition'] # Métier si c'est un utilisateur, domaine professionnel si c'est un collectif
|
32
79
|
entity.registerDate = _data['registerDate']
|
33
|
-
entity.xp = _data['xp']
|
34
80
|
|
35
|
-
if type(entity) == Organization:
|
36
|
-
entity.owner = self.get_entity(_data['owner_id'].upper())
|
37
|
-
entity.members = [
|
38
|
-
self.get_entity(_id) for _id in _data['members']
|
39
|
-
]
|
40
|
-
|
41
|
-
entity.certifications = _data['certifications']
|
42
|
-
elif type(entity) == User:
|
43
|
-
entity.boosts = _data['boosts']
|
44
|
-
|
45
81
|
return entity
|
46
82
|
|
47
83
|
def save_entity(self, entity: Entity) -> None:
|
84
|
+
"""
|
85
|
+
Fonction permettant de créer ou modifier une entité.
|
86
|
+
|
87
|
+
## Paramètres
|
88
|
+
entity: `.Entity` ( `.User | .Organization` )
|
89
|
+
L'entité à sauvegarder
|
90
|
+
"""
|
91
|
+
|
92
|
+
entity.id = NSID(entity.id)
|
93
|
+
|
48
94
|
_base = self.base
|
49
95
|
_data = {
|
50
96
|
'_type': 'user' if type(entity) == User else 'organization' if type(entity) == Organization else 'unknown',
|
51
97
|
'name': entity.name,
|
52
98
|
'legalPosition': entity.legalPosition,
|
53
|
-
'registerDate': entity.registerDate
|
54
|
-
'xp': entity.xp
|
99
|
+
'registerDate': entity.registerDate
|
55
100
|
}
|
56
101
|
|
57
102
|
if type(entity) == Organization:
|
58
|
-
_data['owner_id'] = entity.owner.id
|
59
|
-
_data['members'] = [
|
103
|
+
_data['owner_id'] = NSID(entity.owner.id) if entity.owner else NSID("0")
|
104
|
+
_data['members'] = []
|
60
105
|
_data['certifications'] = entity.certifications
|
106
|
+
|
107
|
+
for member in entity.members:
|
108
|
+
_member = {
|
109
|
+
'id': NSID(member.id),
|
110
|
+
'permissions': member.permissions.__dict__.copy()
|
111
|
+
}
|
112
|
+
|
113
|
+
_data['members'] += _member
|
114
|
+
|
115
|
+
self.avatars.put(name = entity.id, data = entity.avatar)
|
61
116
|
elif type(entity) == User:
|
117
|
+
_data['xp'] = entity.xp
|
62
118
|
_data['boosts'] = entity.boosts
|
63
119
|
|
64
|
-
_base.put(_data, entity.id
|
120
|
+
_base.put(_data, entity.id, expire_in = 3 * 31536000) # Données supprimées tous les trois ans
|
65
121
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
if _data is None:
|
71
|
-
return Elector('0')
|
72
|
-
|
73
|
-
elector = Elector(id)
|
74
|
-
elector.votes = _data['votes']
|
122
|
+
def delete_entity(self, entity: Entity) -> None:
|
123
|
+
"""
|
124
|
+
Fonction permettant de supprimer le profil d'une entité
|
75
125
|
|
76
|
-
|
126
|
+
## Paramètres
|
127
|
+
entity: `.Entity` ( `.User | .Organization` )
|
128
|
+
L'entité à supprimer
|
129
|
+
"""
|
77
130
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
131
|
+
self.base.delete(NSID(entity.id))
|
132
|
+
|
133
|
+
if type(entity) == Organization:
|
134
|
+
self.avatars.delete(NSID(entity.id))
|
135
|
+
|
136
|
+
def fetch_entities(self, query: dict = None, listquery: dict | None = None) -> list[ Entity | User | Organization ]:
|
137
|
+
"""
|
138
|
+
Récupère une liste d'entités en fonction d'une requête.
|
82
139
|
|
83
|
-
|
140
|
+
## Paramètres
|
141
|
+
query: `dict`
|
142
|
+
La requête pour filtrer les entités.
|
143
|
+
listquery: `dict | None`
|
144
|
+
Requête secondaire pour n'afficher que les listes contenant un certain élément.
|
84
145
|
|
85
|
-
|
146
|
+
## Renvoie
|
147
|
+
- `list[Entity | User | Organization]`
|
148
|
+
"""
|
86
149
|
_res = self.base.fetch(query).items
|
87
150
|
|
88
151
|
if listquery is not None:
|
89
152
|
for item in _res:
|
90
|
-
for target, value in listquery:
|
153
|
+
for target, value in listquery.items():
|
91
154
|
if value not in item[target]:
|
92
155
|
_res.remove(item)
|
156
|
+
|
157
|
+
return [ self.get_entity(NSID(entity['key'])) for entity in _res ]
|
158
|
+
|
159
|
+
def get_entity_groups(self, id: str | NSID) -> list[Organization]:
|
160
|
+
"""
|
161
|
+
Récupère les groupes auxquels appartient une entité.
|
162
|
+
|
163
|
+
## Paramètres
|
164
|
+
id: `str | NSID`
|
165
|
+
ID de l'entité.
|
166
|
+
|
167
|
+
## Renvoie
|
168
|
+
- `list[Organization]`
|
169
|
+
"""
|
170
|
+
|
171
|
+
id = NSID(id)
|
172
|
+
groups = self.fetch_entities({'_type': 'organization'}, {'members': id})
|
173
|
+
|
174
|
+
return groups
|
175
|
+
|
176
|
+
def get_position(self, id: str) -> Position:
|
177
|
+
"""
|
178
|
+
Récupère une position légale (métier, domaine professionnel).
|
179
|
+
|
180
|
+
## Paramètres
|
181
|
+
id: `str`
|
182
|
+
ID de la position (SENSIBLE À LA CASSE !)
|
183
|
+
|
184
|
+
## Renvoie
|
185
|
+
- `.Position`
|
186
|
+
"""
|
187
|
+
|
188
|
+
_data = self.positions.get(id)
|
189
|
+
|
190
|
+
if _data is None:
|
191
|
+
raise RessourceNotFoundError(f"No position with ID {id}")
|
192
|
+
|
193
|
+
position = Position(id)
|
194
|
+
position.name = _data['name']
|
195
|
+
|
196
|
+
for _permission in _data['permissions']:
|
197
|
+
position.permissions.__setattr__(_permission, True)
|
198
|
+
|
199
|
+
return position
|
200
|
+
|
201
|
+
def _add_archive(self, archive: Action) -> None:
|
202
|
+
"""
|
203
|
+
Ajoute une archive d'une action (modification au sein d'un groupe ou sanction) dans la base de données.
|
204
|
+
"""
|
205
|
+
|
206
|
+
archive.id = NSID(archive.id)
|
207
|
+
archive.author = NSID(archive.author)
|
208
|
+
archive.target = NSID(archive.target)
|
209
|
+
|
210
|
+
_data = archive.__dict__.copy()
|
211
|
+
|
212
|
+
if type(archive) == Sanction:
|
213
|
+
_data['type'] = "sanction"
|
214
|
+
elif type(archive) == AdminAction:
|
215
|
+
_data['type'] = "adminaction"
|
216
|
+
else:
|
217
|
+
_data['type'] = "unknown"
|
93
218
|
|
94
|
-
|
219
|
+
self.archives.put(key = archive.id, data = _data)
|
220
|
+
|
221
|
+
def _get_archive(self, id: str | NSID) -> Action | Sanction | AdminAction:
|
222
|
+
"""
|
223
|
+
Récupère une archive spécifique.
|
224
|
+
|
225
|
+
## Paramètres
|
226
|
+
id: `str | NSID`
|
227
|
+
ID de l'archive.
|
228
|
+
|
229
|
+
## Renvoie
|
230
|
+
- `.Action | .Sanction | .AdminAction`
|
231
|
+
"""
|
95
232
|
|
96
|
-
|
97
|
-
|
233
|
+
id = NSID(id)
|
234
|
+
_data = self.archives.get(id)
|
235
|
+
|
236
|
+
if _data is None:
|
237
|
+
return None
|
98
238
|
|
99
|
-
|
239
|
+
if _data['type'] == "sanction": # Mute, ban, GAV, kick, détention, prune (xp seulement)
|
240
|
+
archive = Sanction(_data['author'], _data['target'])
|
241
|
+
|
242
|
+
archive.details = _data['details']
|
243
|
+
archive.major = _data['major']
|
244
|
+
archive.duration = _data['duration']
|
245
|
+
elif _data['type'] == "adminaction": # Renommage, promotion, démotion (au niveau de l'état)
|
246
|
+
archive = AdminAction(_data['author'], _data['target'])
|
247
|
+
|
248
|
+
archive.details = _data['details']
|
249
|
+
archive.new_state = _data['new_state']
|
250
|
+
else:
|
251
|
+
archive = Action(_data['author'], _data['target'])
|
252
|
+
|
253
|
+
archive.id = id
|
254
|
+
archive.action = _data['action']
|
255
|
+
archive.date = _data['date']
|
256
|
+
|
257
|
+
return archive
|
258
|
+
|
259
|
+
def _fetch_archives(self, **query) -> list[ Action | Sanction | AdminAction ]:
|
260
|
+
"""
|
261
|
+
Récupère une liste d'archives correspondant à la requête.
|
262
|
+
|
263
|
+
## Paramètres
|
264
|
+
query: `dict`
|
265
|
+
Requête pour filtrer les archives.
|
266
|
+
|
267
|
+
## Renvoie
|
268
|
+
- `list[Action | Sanction | AdminAction]`
|
269
|
+
"""
|
270
|
+
|
271
|
+
_res = self.archives.fetch(query).items
|
272
|
+
|
273
|
+
return [ self._get_archive(archive['key']) for archive in _res ]
|
100
274
|
|
101
275
|
class RepublicInstance:
|
276
|
+
"""
|
277
|
+
Gère les interactions avec les votes, les archives de la république, et les fonctionnaires.
|
278
|
+
|
279
|
+
## Informations
|
280
|
+
- Résultats des votes: `.Vote | .ClosedVote`
|
281
|
+
- Différentes institutions: `.Institutions | .Administration | .Government | .Assembly | .Court | .PoliceForces`
|
282
|
+
- Occupants des différents rôles et historique de leurs actions: `.Official`
|
283
|
+
"""
|
284
|
+
|
102
285
|
def __init__(self, token: str) -> None:
|
286
|
+
"""Initialise une nouvelle RepublicInstance avec un token Deta."""
|
287
|
+
|
103
288
|
self.db = deta.Deta(token)
|
104
289
|
self.votes = self.db.Base('votes')
|
290
|
+
self.archives = self.db.Base('archives')
|
291
|
+
self.mandate = self.db.Base('mandate')
|
292
|
+
self.functions = self.db.Base('functions') # Liste des fonctionnaires
|
293
|
+
|
294
|
+
def get_vote(self, id: str | NSID) -> Vote | ClosedVote:
|
295
|
+
"""
|
296
|
+
Récupère un vote spécifique.
|
297
|
+
|
298
|
+
## Paramètres
|
299
|
+
id: `str | NSID`
|
300
|
+
ID du vote.
|
105
301
|
|
106
|
-
|
107
|
-
|
302
|
+
## Renvoie
|
303
|
+
- `.Vote | .ClosedVote`
|
304
|
+
"""
|
305
|
+
|
306
|
+
id = NSID(id)
|
108
307
|
_data = self.votes.get(id)
|
109
308
|
|
110
309
|
if _data is None:
|
111
|
-
|
112
|
-
|
310
|
+
raise RessourceNotFoundError(f"The vote #{id} does not exist.")
|
311
|
+
|
113
312
|
if _data['_type'] == 'open':
|
114
313
|
vote = Vote(id, _data['title'], tuple(_data['choices'].keys()))
|
115
314
|
elif _data['_type'] == 'closed':
|
116
315
|
vote = ClosedVote(id, _data['title'])
|
117
316
|
else:
|
118
317
|
vote = Vote('0', 'Unknown Vote', ())
|
119
|
-
|
318
|
+
|
120
319
|
vote.author = _data['author']
|
121
320
|
vote.startDate = _data['startDate']
|
122
321
|
vote.endDate = _data['endDate']
|
123
322
|
vote.choices = _data['choices']
|
124
|
-
|
323
|
+
|
125
324
|
return vote
|
126
325
|
|
127
|
-
def save_vote(self, vote: Vote | ClosedVote):
|
128
|
-
|
326
|
+
def save_vote(self, vote: Vote | ClosedVote) -> None:
|
327
|
+
"""Sauvegarde un vote dans la base de données."""
|
328
|
+
|
329
|
+
vote.id = NSID(vote.id)
|
330
|
+
|
129
331
|
_data = {
|
130
332
|
'_type': 'open' if type(vote) == Vote else 'closed' if type(vote) == ClosedVote else 'unknown',
|
131
333
|
'title': vote.title,
|
132
|
-
'author': vote.author,
|
334
|
+
'author': NSID(vote.author),
|
133
335
|
'startDate': vote.startDate,
|
134
336
|
'endDate': vote.endDate,
|
135
337
|
'choices': vote.choices
|
136
338
|
}
|
137
339
|
|
138
|
-
|
340
|
+
self.votes.put(_data, vote.id)
|
341
|
+
|
342
|
+
def get_official(self, id: str | NSID, current_mandate: bool = True) -> Official:
|
343
|
+
"""
|
344
|
+
Récupère les informations d'un fonctionnaire (mandats, contributions).
|
345
|
+
|
346
|
+
## Paramètres
|
347
|
+
id: `str | NSID`
|
348
|
+
ID du fonctionnaire.
|
349
|
+
current_mandate: `bool`
|
350
|
+
Indique si l'on doit récupérer le mandat actuel ou les anciens mandats.
|
351
|
+
|
352
|
+
## Renvoie
|
353
|
+
- `.Official`
|
354
|
+
"""
|
355
|
+
|
356
|
+
id = NSID(id)
|
357
|
+
|
358
|
+
archives = self.mandate if current_mandate else self.archives
|
359
|
+
|
360
|
+
_contributions = archives.fetch({'author': id, 'type': 'contrib'}).items
|
361
|
+
_mandates = archives.fetch({'target': id, 'type': 'election'}).items\
|
362
|
+
+ archives.fetch({'target': id, 'type': 'promotion'}).items
|
363
|
+
|
364
|
+
user = Official(id)
|
365
|
+
for mandate in _mandates:
|
366
|
+
if mandate['position'].startswith('MIN'):
|
367
|
+
mandate['position'] = 'MIN'
|
368
|
+
|
369
|
+
try:
|
370
|
+
user.mandates[mandate['position']] += 1
|
371
|
+
except KeyError:
|
372
|
+
user.mandates[mandate['position']] = 1
|
373
|
+
|
374
|
+
for contrib in _contributions:
|
375
|
+
try:
|
376
|
+
user.contributions[contrib['action']] += 1
|
377
|
+
except KeyError:
|
378
|
+
user.contributions[contrib['action']] = 1
|
379
|
+
|
380
|
+
return user
|
381
|
+
|
382
|
+
def get_institutions(self) -> Organization:
|
383
|
+
"""Récupère l'état actuel des institutions de la république."""
|
384
|
+
|
385
|
+
admin = Administration()
|
386
|
+
gov = Government(Official('0'))
|
387
|
+
assembly = Assembly()
|
388
|
+
court = Court()
|
389
|
+
police_forces = PoliceForces()
|
390
|
+
|
391
|
+
_admins = self.functions.get('ADMIN')
|
392
|
+
admin.members = [ self.get_official(user) for user in _admins['users'] ]
|
393
|
+
admin.president = self.get_official('F7DB60DD1C4300A') # happex (remplace Kheops pour l'instant)
|
394
|
+
|
395
|
+
gov.president = self.get_official(self.functions.get('PRE_REP')['users'][0])
|
396
|
+
|
397
|
+
minister = lambda code : self.get_official(self.functions.get(f'MIN_{code}')['users'][0])
|
398
|
+
gov.prime_minister = minister('PRIM')
|
399
|
+
gov.economy_minister = minister('ECO')
|
400
|
+
gov.inner_minister = minister('INN')
|
401
|
+
gov.press_minister = minister('AUD')
|
402
|
+
gov.justice_minister = minister('JUS')
|
403
|
+
gov.outer_minister = minister('OUT')
|
404
|
+
|
405
|
+
assembly.president = self.get_official(self.functions.get('PRE_AS')['users'][0])
|
406
|
+
assembly.members = [ self.get_official(id) for id in self.functions.get('REPR')['users'] ]
|
407
|
+
|
408
|
+
court.president = gov.justice_minister
|
409
|
+
court.members = [ self.get_official(id) for id in self.functions.get('JUDGE')['users'] ]
|
410
|
+
|
411
|
+
police_forces.president = gov.inner_minister
|
412
|
+
police_forces.members = [ self.get_official(id) for id in self.functions.get('POLICE')['users'] ]
|
413
|
+
|
414
|
+
instits = Institutions()
|
415
|
+
instits.administration = admin
|
416
|
+
instits.government = gov
|
417
|
+
instits.court = court
|
418
|
+
instits.assembly = assembly
|
419
|
+
instits.police = police_forces
|
420
|
+
|
421
|
+
return instits
|
422
|
+
|
423
|
+
def update_institutions(self, institutions: Institutions):
|
424
|
+
"""
|
425
|
+
Fonction communément appelée après un vote législatif ou une nomination.\n
|
426
|
+
Celle-ci met à jour: Le gouvernement (président, ministres), les différents députés et leur président, les différents juges, les différents policiers.\n
|
427
|
+
|
428
|
+
## Paramètres
|
429
|
+
institutions: `.Institutions`\n
|
430
|
+
Le nouvel état des institutions, à sauvegarder.
|
431
|
+
"""
|
432
|
+
|
433
|
+
get_ids = lambda institution : [ member.id for member in institutions.__getattribute__(institution).members ]
|
434
|
+
|
435
|
+
self.functions.put(key = 'ADMIN', data = { 'users': get_ids('administration') })
|
436
|
+
self.functions.put(key = 'REPR', data = { 'users': get_ids('assembly') })
|
437
|
+
self.functions.put(key = 'JUDGE', data = { 'users': get_ids('court') })
|
438
|
+
self.functions.put(key = 'POLICE', data = { 'users': get_ids('police') })
|
439
|
+
|
440
|
+
self.functions.put(key = 'PRE_AS', data = { 'users': [ institutions.assembly.president.id ] })
|
441
|
+
self.functions.put(key = 'PRE_REP', data = { 'users': [ institutions.government.president.id ] })
|
442
|
+
|
443
|
+
self.functions.put(key = 'MIN_PRIM', data = { 'users': [ institutions.government.prime_minister.id ] })
|
444
|
+
self.functions.put(key = 'MIN_INN', data = { 'users': [ institutions.government.inner_minister.id ] })
|
445
|
+
self.functions.put(key = 'MIN_JUS', data = { 'users': [ institutions.government.justice_minister.id ] })
|
446
|
+
self.functions.put(key = 'MIN_ECO', data = { 'users': [ institutions.government.economy_minister.id ] })
|
447
|
+
self.functions.put(key = 'MIN_AUD', data = { 'users': [ institutions.government.press_minister.id ] })
|
448
|
+
self.functions.put(key = 'MIN_OUT', data = { 'users': [ institutions.government.outer_minister.id ] })
|
449
|
+
|
450
|
+
def new_mandate(self, institutions: Institutions, weeks: int = 4) -> None:
|
451
|
+
"""
|
452
|
+
Fonction qui amène à supprimer toutes les archives du mandat précédent
|
453
|
+
"""
|
454
|
+
|
455
|
+
for item in self.mandate.fetch().items:
|
456
|
+
if item['date'] >= round(time.time()) - weeks * 604800: # On évite de supprimer les informations écrites lors de la période définie
|
457
|
+
self.mandate.delete(item['id'])
|
458
|
+
|
459
|
+
self.update_institutions(institutions)
|
460
|
+
|
461
|
+
def _add_archive(self, archive: Action) -> None:
|
462
|
+
"""Ajoute une archive d'une action (élection, promotion, ou rétrogradation) dans la base de données."""
|
463
|
+
|
464
|
+
archive.id = NSID(archive.id)
|
465
|
+
_data = archive.__dict__.copy()
|
466
|
+
|
467
|
+
if type(archive) == Election:
|
468
|
+
_data['type'] = "election"
|
469
|
+
elif type(archive) == Promotion:
|
470
|
+
_data['type'] = "promotion"
|
471
|
+
elif type(archive) == Demotion:
|
472
|
+
_data['type'] = "demotion"
|
473
|
+
else:
|
474
|
+
_data['type'] = "unknown"
|
475
|
+
|
476
|
+
self.archives.put(key = archive.id, data = _data)
|
477
|
+
self.mandate.put(key = archive.id, data = _data) # Ajouter les archives à celle du mandat actuel
|
478
|
+
|
479
|
+
def _get_archive(self, id: str | NSID) -> Action | Election | Promotion | Demotion:
|
480
|
+
"""
|
481
|
+
Récupère une archive spécifique.
|
482
|
+
|
483
|
+
## Paramètres
|
484
|
+
id: `str | NSID`
|
485
|
+
ID de l'archive.
|
486
|
+
|
487
|
+
## Renvoie
|
488
|
+
- `.Action | .Election | .Promotion | .Demotion`
|
489
|
+
"""
|
490
|
+
|
491
|
+
id = NSID(id)
|
492
|
+
_data = self.archives.get(id)
|
493
|
+
|
494
|
+
if _data is None:
|
495
|
+
return None
|
496
|
+
|
497
|
+
if _data['type'] == "election":
|
498
|
+
archive = Election(_data['author'], _data['target'], _data['position'])
|
499
|
+
|
500
|
+
archive.positive_votes = _data['positive_votes']
|
501
|
+
archive.total_votes = _data['total_votes']
|
502
|
+
elif _data['type'] == "promotion":
|
503
|
+
archive = Promotion(_data['author'], _data['target'], _data['position'])
|
504
|
+
elif _data['type'] == "demotion":
|
505
|
+
archive = Demotion(_data['author'], _data['target'])
|
506
|
+
|
507
|
+
archive.reason = _data['reason']
|
508
|
+
else:
|
509
|
+
archive = Action(_data['author'], _data['target'])
|
510
|
+
|
511
|
+
archive.id = id
|
512
|
+
archive.action = _data['action']
|
513
|
+
archive.date = _data['date']
|
514
|
+
|
515
|
+
return archive
|
516
|
+
|
517
|
+
def _fetch_archives(self, **query) -> list[ Action | Election | Promotion | Demotion ]:
|
518
|
+
"""
|
519
|
+
Récupère une liste d'archives correspondant à la requête.
|
520
|
+
|
521
|
+
## Paramètres
|
522
|
+
query: `dict`
|
523
|
+
Requête pour filtrer les archives.
|
524
|
+
|
525
|
+
## Renvoie
|
526
|
+
- `list[Action | Election | Promotion | Demotion]`
|
527
|
+
"""
|
528
|
+
|
529
|
+
_res = self.archives.fetch(query).items
|
530
|
+
|
531
|
+
return [ self._get_archive(archive['key']) for archive in _res ]
|
532
|
+
|
533
|
+
class BankInstance:
|
534
|
+
"""Gère les interactions avec les comptes bancaires, les transactions, et le marché."""
|
535
|
+
|
536
|
+
def __init__(self, token: str) -> None:
|
537
|
+
self.db = deta.Deta(token)
|
538
|
+
self.archives = self.db.Base('archives')
|
539
|
+
self.accounts = self.db.Base('accounts')
|
540
|
+
self.registry = self.db.Base('banks')
|
541
|
+
self.marketplace = self.db.Base('shop')
|
542
|
+
|
543
|
+
def get_account(self, id: str | NSID) -> BankAccount:
|
544
|
+
"""
|
545
|
+
Récupère les informations d'un compte bancaire.
|
546
|
+
|
547
|
+
## Paramètres
|
548
|
+
id: `str | NSID`
|
549
|
+
ID du compte.
|
550
|
+
|
551
|
+
## Renvoie
|
552
|
+
- `.BankAccount`
|
553
|
+
"""
|
554
|
+
|
555
|
+
id = NSID(id)
|
556
|
+
_data = self.accounts.get(id)
|
557
|
+
|
558
|
+
if _data is None:
|
559
|
+
return None
|
560
|
+
|
561
|
+
account = BankAccount(id)
|
562
|
+
account.amount = _data['amount']
|
563
|
+
account.locked = _data['locked']
|
564
|
+
account.owner = _data['owner_id']
|
565
|
+
account.bank = _data['bank']
|
566
|
+
|
567
|
+
return account
|
568
|
+
|
569
|
+
def save_account(self, account: BankAccount):
|
570
|
+
"""Sauvegarde un compte bancaire dans la base de données."""
|
571
|
+
|
572
|
+
_data = {
|
573
|
+
'amount': account.amount,
|
574
|
+
'locked': account.locked,
|
575
|
+
'owner_id': account.owner,
|
576
|
+
'bank': account.bank
|
577
|
+
}
|
578
|
+
|
579
|
+
self.accounts.put(_data, NSID(account.id))
|
580
|
+
|
581
|
+
def lock_account(self, account: BankAccount):
|
582
|
+
"""Verrouille un compte bancaire pour empêcher toute transaction."""
|
583
|
+
|
584
|
+
account.id = account.id.upper()
|
585
|
+
account.locked = True
|
586
|
+
|
587
|
+
self.save_account(account)
|
588
|
+
|
589
|
+
def get_item(self, id: str | NSID) -> Item | None:
|
590
|
+
"""
|
591
|
+
Récupère un item du marché.
|
592
|
+
|
593
|
+
## Paramètres
|
594
|
+
id: `str | NSID`
|
595
|
+
ID de l'item.
|
596
|
+
|
597
|
+
## Renvoie
|
598
|
+
- `.Item | None`
|
599
|
+
"""
|
600
|
+
|
601
|
+
id = NSID(id)
|
602
|
+
|
603
|
+
_data = self.marketplace.get(id)
|
604
|
+
|
605
|
+
if _data is None:
|
606
|
+
return None
|
607
|
+
|
608
|
+
item = Item(id)
|
609
|
+
item.title = _data['title']
|
610
|
+
item.emoji = _data['emoji']
|
611
|
+
item.seller_id = _data['seller']
|
612
|
+
item.price = _data['price']
|
613
|
+
|
614
|
+
return item
|
615
|
+
|
616
|
+
def save_item(self, item: Item) -> None:
|
617
|
+
"""Sauvegarde un item dans la base de données du marché."""
|
618
|
+
|
619
|
+
item.id = NSID(item.id)
|
620
|
+
|
621
|
+
_data = item.__dict__.copy()
|
622
|
+
|
623
|
+
self.marketplace.put(key = item.id, data = _data)
|
624
|
+
|
625
|
+
def delete_item(self, item: Item) -> None:
|
626
|
+
"""Supprime un item du marché."""
|
627
|
+
|
628
|
+
item.id = NSID(item.id)
|
629
|
+
self.marketplace.delete(item.id)
|
630
|
+
|
631
|
+
def _add_archive(self, archive: Action):
|
632
|
+
"""Ajoute une archive d'une transaction ou d'une vente dans la base de données."""
|
633
|
+
|
634
|
+
archive.id = NSID(archive.id)
|
635
|
+
archive.author = NSID(archive.author)
|
636
|
+
archive.target = NSID(archive.target)
|
637
|
+
|
638
|
+
_data = archive.__dict__.copy()
|
639
|
+
|
640
|
+
if type(archive) == Transaction:
|
641
|
+
_data['type'] = "transaction"
|
642
|
+
archive.currency = archive.currency.upper()
|
643
|
+
elif type(archive) == Sale:
|
644
|
+
_data['type'] = "sale"
|
645
|
+
else:
|
646
|
+
_data['type'] = "unknown"
|
647
|
+
|
648
|
+
self.archives.put(key = archive.id, data = _data)
|
649
|
+
|
650
|
+
def _get_archive(self, id: str | NSID) -> Action | Transaction:
|
651
|
+
"""
|
652
|
+
Récupère une archive spécifique.
|
653
|
+
|
654
|
+
## Paramètres
|
655
|
+
id: `str | NSID`
|
656
|
+
ID de l'archive.
|
657
|
+
|
658
|
+
## Renvoie
|
659
|
+
- `.Action | .Transaction`
|
660
|
+
"""
|
661
|
+
|
662
|
+
id = NSID(id)
|
663
|
+
_data = self.archives.get(id)
|
664
|
+
|
665
|
+
if _data is None:
|
666
|
+
return None
|
667
|
+
|
668
|
+
if _data['type'] == "transaction":
|
669
|
+
archive = Transaction(_data['author'], _data['target'], _data['amount'])
|
670
|
+
|
671
|
+
archive.reason = _data['reason']
|
672
|
+
archive.currency = _data['currency']
|
673
|
+
elif _data['type'] == "sale":
|
674
|
+
archive = Sale(_data['author'], _data['target'])
|
675
|
+
|
676
|
+
archive.price = _data['price']
|
677
|
+
else:
|
678
|
+
archive = Action(_data['author'], _data['target'])
|
679
|
+
|
680
|
+
archive.id = id
|
681
|
+
archive.action = _data['action']
|
682
|
+
archive.date = _data['date']
|
683
|
+
|
684
|
+
return archive
|
685
|
+
|
686
|
+
def _fetch_archives(self, **query) -> list[ Action | Transaction ]:
|
687
|
+
"""
|
688
|
+
Récupère une liste d'archives correspondant à la requête.
|
689
|
+
|
690
|
+
## Paramètres
|
691
|
+
query: `dict`
|
692
|
+
Requête pour filtrer les archives.
|
693
|
+
|
694
|
+
## Renvoie
|
695
|
+
- `list[Action | Transaction]`
|
696
|
+
"""
|
697
|
+
|
698
|
+
_res = self.archives.fetch(query).items
|
699
|
+
|
700
|
+
return [ self._get_archive(archive['key']) for archive in _res ]
|
Binary file
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
from .base import *
|
4
|
+
|
5
|
+
class Action:
|
6
|
+
def __init__(self, author: str | NSID = '0', target: str | NSID = '0') -> None:
|
7
|
+
self.date: int = round(time.time())
|
8
|
+
|
9
|
+
self.id: NSID = NSID(self.date)
|
10
|
+
self.action: str = ""
|
11
|
+
self.author: NSID = NSID(author)
|
12
|
+
self.target: NSID = NSID(target)
|
13
|
+
|
14
|
+
|
15
|
+
# Entities
|
16
|
+
|
17
|
+
class Sanction(Action):
|
18
|
+
def __init__(self, author: str | NSID, target: str | NSID) -> None:
|
19
|
+
super().__init__(author, target)
|
20
|
+
|
21
|
+
self.details: str = ""
|
22
|
+
self.major: bool = False # Sanction majeure ou non
|
23
|
+
self.duration: int = 0 # Durée en secondes, 0 = définitif
|
24
|
+
|
25
|
+
class AdminAction(Action):
|
26
|
+
def __init__(self, author: str | NSID, target: str | NSID) -> None:
|
27
|
+
super().__init__(author, target)
|
28
|
+
|
29
|
+
self.details: str = ""
|
30
|
+
self.new_state: str | int | bool = None
|
31
|
+
|
32
|
+
|
33
|
+
# Community
|
34
|
+
|
35
|
+
class Election(Action):
|
36
|
+
def __init__(self, author: str | NSID, target: str | NSID, position: str) -> None:
|
37
|
+
super().__init__(author, target)
|
38
|
+
|
39
|
+
self.position: str = position
|
40
|
+
self.positive_votes: int = 0
|
41
|
+
self.total_votes: int = 0
|
42
|
+
|
43
|
+
class Promotion(Action):
|
44
|
+
def __init__(self, author: str | NSID, target: str | NSID, position: str) -> None:
|
45
|
+
super().__init__(author, target)
|
46
|
+
|
47
|
+
self.position: str = position
|
48
|
+
|
49
|
+
class Demotion(Action):
|
50
|
+
def __init__(self, author: str | NSID, target: str | NSID) -> None:
|
51
|
+
super().__init__(author, target)
|
52
|
+
|
53
|
+
self.reason: str = None
|
54
|
+
|
55
|
+
|
56
|
+
# Bank
|
57
|
+
|
58
|
+
class Transaction(Action):
|
59
|
+
def __init__(self, author: str | NSID, target: str | NSID, amount: int) -> None:
|
60
|
+
super().__init__(author, target)
|
61
|
+
|
62
|
+
self.amount: int = amount
|
63
|
+
self.currency: str = 'HC'
|
64
|
+
self.reason: str = None
|
65
|
+
|
66
|
+
class Sale(Action):
|
67
|
+
def __init__(self, author: str | NSID = '0', target: str | NSID = '0') -> None:
|
68
|
+
super().__init__(author, target)
|
69
|
+
|
70
|
+
self.price: int = 0
|
nsarchive/cls/base.py
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class NSID(str):
|
2
|
+
unknown = "0"
|
3
|
+
admin = "01"
|
4
|
+
gov = "02"
|
5
|
+
assembly = "03"
|
6
|
+
court = "04"
|
7
|
+
office = "05"
|
8
|
+
hexabank = "06"
|
9
|
+
archives = "07"
|
10
|
+
|
11
|
+
maintenance_committee = "101"
|
12
|
+
audiovisual_department = "102"
|
13
|
+
interior_department = "103"
|
14
|
+
|
15
|
+
def __new__(cls, value):
|
16
|
+
if type(value) == int:
|
17
|
+
value = hex(value)
|
18
|
+
elif type(value) in (str, NSID):
|
19
|
+
value = hex(int(value, 16))
|
20
|
+
else:
|
21
|
+
return TypeError(f"<{value}> is not NSID serializable")
|
22
|
+
|
23
|
+
if value.startswith("0x"):
|
24
|
+
value = value[2:]
|
25
|
+
|
26
|
+
instance = super(NSID, cls).__new__(cls, value.upper())
|
27
|
+
return instance
|
nsarchive/cls/economy.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
from .base import *
|
2
|
+
|
3
|
+
class BankAccount:
|
4
|
+
def __init__(self, id: str | NSID) -> None:
|
5
|
+
self.id: NSID = NSID(id)
|
6
|
+
self.owner: NSID = NSID(0)
|
7
|
+
self.amount: int = 0
|
8
|
+
self.locked: bool = False
|
9
|
+
self.bank: str = "HexaBank"
|
10
|
+
|
11
|
+
self.income: int = 0
|
12
|
+
|
13
|
+
class Item:
|
14
|
+
def __init__(self, id: str | NSID) -> None:
|
15
|
+
self.id: NSID = NSID(id)
|
16
|
+
self.title: str = "Unknown Object"
|
17
|
+
self.emoji: str = ":light_bulb:"
|
18
|
+
|
19
|
+
self.seller_id: NSID = NSID(0)
|
20
|
+
self.price: int = 0
|
nsarchive/cls/entities.py
CHANGED
@@ -1,14 +1,69 @@
|
|
1
|
+
import io
|
1
2
|
import time
|
2
3
|
|
3
4
|
from .exceptions import *
|
5
|
+
from .base import *
|
4
6
|
|
7
|
+
from ..utils import assets
|
8
|
+
|
9
|
+
class PositionPermissions:
|
10
|
+
"""
|
11
|
+
Permissions d'une position à l'échelle du serveur. Certaines sont attribuées selon l'appartenance à divers groupes ayant une position précise
|
12
|
+
"""
|
13
|
+
|
14
|
+
def __init__(self) -> None:
|
15
|
+
# Membres
|
16
|
+
self.approve_laws = False # Approuver ou désapprouver les lois proposées (vaut aussi pour la Constitution)
|
17
|
+
self.buy_items = False # Acheter des items depuis le marketplace
|
18
|
+
self.create_organizations = False # Créer une organisation
|
19
|
+
self.edit_constitution = False # Proposer une modification de la Constitution
|
20
|
+
self.edit_laws = False # Proposer une modification des différents textes de loi
|
21
|
+
self.manage_entities = False # Gérer les membres et les organisations
|
22
|
+
self.manage_national_channel = False # Prendre la parole sur la chaîne nationale et avoir une priorité de passage sur les autres chaînes
|
23
|
+
self.manage_state_budgets = False # Gérer les différents budgets de l'État
|
24
|
+
self.moderate_members = False # Envoyer des membres en garde à vue, en détention ou toute autre sanction non présente sur le client Discord
|
25
|
+
self.propose_new_laws = self.edit_constitution # Proposer un nouveau texte de loi pris en charge par la Constitution
|
26
|
+
self.publish_official_messages = False # Publier un message sous l'identité du bot Serveur
|
27
|
+
self.sell_items = False # Vendre des objets ou services sur le marketplace
|
28
|
+
self.vote_president = False # Participer aux élections présidentielles
|
29
|
+
self.vote_representatives = False # Participer aux élections législatives
|
30
|
+
|
31
|
+
def edit(self, **permissions: bool) -> None:
|
32
|
+
for perm in permissions.values():
|
33
|
+
self.__setattr__(*perm)
|
34
|
+
|
35
|
+
class Position:
|
36
|
+
def __init__(self, id: str = 'inconnu') -> None:
|
37
|
+
self.name: str = "Inconnue"
|
38
|
+
self.id = id
|
39
|
+
self.permissions: PositionPermissions = PositionPermissions()
|
5
40
|
class Entity:
|
6
|
-
def __init__(self, id: str):
|
7
|
-
self.id:
|
8
|
-
self.name: str =
|
41
|
+
def __init__(self, id: str | NSID) -> None:
|
42
|
+
self.id: NSID = NSID(id) # ID hexadécimal de l'entité (ou nom dans le cas de l'entreprise)
|
43
|
+
self.name: str = "Entité Inconnue"
|
9
44
|
self.registerDate: int = 0
|
10
|
-
self.legalPosition:
|
45
|
+
self.legalPosition: Position = Position()
|
46
|
+
|
47
|
+
def set_name(self, new_name: str) -> None:
|
48
|
+
if len(new_name) > 32:
|
49
|
+
raise NameTooLongError(f"Name length mustn't exceed 32 characters.")
|
50
|
+
|
51
|
+
self.name = new_name
|
52
|
+
|
53
|
+
def set_position(self, position: str) -> None:
|
54
|
+
self.legalPosition = position
|
55
|
+
|
56
|
+
class User(Entity):
|
57
|
+
def __init__(self, id: str | NSID) -> None:
|
58
|
+
super().__init__(NSID(id))
|
59
|
+
|
11
60
|
self.xp: int = 0
|
61
|
+
self.boosts: dict[str, int] = {}
|
62
|
+
self.permissions: PositionPermissions = PositionPermissions() # Elles seront définies en récupérant les permissions de sa position
|
63
|
+
self.votes: list[str] = []
|
64
|
+
|
65
|
+
def add_vote(self, id: str | NSID):
|
66
|
+
self.votes.append(NSID(id))
|
12
67
|
|
13
68
|
def get_level(self) -> None:
|
14
69
|
i = 0
|
@@ -16,75 +71,78 @@ class Entity:
|
|
16
71
|
i += 1
|
17
72
|
|
18
73
|
return i
|
19
|
-
|
20
|
-
def rename(self, new_name: str) -> None:
|
21
|
-
if len(new_name) > 32:
|
22
|
-
raise NameTooLongError(f"Name length mustn't exceed 32 characters.")
|
23
|
-
|
24
|
-
self.name = new_name
|
25
|
-
|
26
|
-
def set_position(self, position: str) -> None:
|
27
|
-
self.legalPosition = position
|
28
|
-
|
74
|
+
|
29
75
|
def add_xp(self, amount: int) -> None:
|
30
76
|
boost = 0 if 0 in self.boosts.values() else max(list(self.boosts.values()) + [ 1 ])
|
31
77
|
|
32
78
|
self.xp += amount * boost
|
33
|
-
|
34
|
-
class User(Entity):
|
35
|
-
def __init__(self, id: str):
|
36
|
-
super().__init__(id)
|
37
79
|
|
38
|
-
self.boosts: dict[str, int] = {}
|
39
|
-
|
40
80
|
def edit_boost(self, name: str, multiplier: int = -1) -> None:
|
41
81
|
if multiplier >= 0:
|
42
82
|
self.boosts[name] = multiplier
|
43
83
|
else:
|
44
84
|
del self.boosts[name]
|
45
85
|
|
86
|
+
class MemberPermissions:
|
87
|
+
"""
|
88
|
+
Permissions d'un utilisateur à l'échelle d'un groupe
|
89
|
+
"""
|
90
|
+
|
91
|
+
def __init__(self) -> None:
|
92
|
+
self.manage_organization = False # Renommer ou changer le logo
|
93
|
+
self.manage_members = False # Virer quelqu'un d'une entreprise, l'y inviter, changer ses rôles
|
94
|
+
self.manage_roles = False # Promouvoir ou rétrograder les membres
|
95
|
+
|
96
|
+
def edit(self, **permissions: bool) -> None:
|
97
|
+
for perm in permissions.values():
|
98
|
+
self.__setattr__(*perm)
|
99
|
+
|
100
|
+
class GroupMember():
|
101
|
+
def __init__(self, id: str | NSID) -> None:
|
102
|
+
self.id: NSID = NSID(id)
|
103
|
+
self.permissions: MemberPermissions = MemberPermissions()
|
104
|
+
self.position: str = 'membre'
|
105
|
+
|
106
|
+
class Official:
|
107
|
+
def __init__(self, id: str | NSID) -> None:
|
108
|
+
self.id: NSID = NSID(id)
|
109
|
+
|
110
|
+
self.mandates: int = {
|
111
|
+
'PRE_REP': 0, # Président de la République
|
112
|
+
'MIN': 0, # Différents ministres
|
113
|
+
'PRE_AS': 0, # Président de l'Assemblée Nationale
|
114
|
+
'JUDGE': 0, # Juge
|
115
|
+
'REPR': 0 # Député
|
116
|
+
}
|
117
|
+
|
118
|
+
self.contributions: dict = {
|
119
|
+
'project': 0,
|
120
|
+
'approved_project': 0,
|
121
|
+
'admin_action': 0,
|
122
|
+
'law_vote': 0
|
123
|
+
}
|
124
|
+
|
46
125
|
class Organization(Entity):
|
47
|
-
def __init__(self, id: str):
|
48
|
-
super().__init__(id)
|
126
|
+
def __init__(self, id: str | NSID) -> None:
|
127
|
+
super().__init__(NSID(id))
|
49
128
|
|
50
129
|
self.owner: Entity
|
51
130
|
self.certifications: dict = {}
|
52
|
-
self.members: list = []
|
53
|
-
|
131
|
+
self.members: list[GroupMember] = []
|
132
|
+
self.avatar: bytes = assets.open('default_avatar.png')
|
133
|
+
|
54
134
|
def add_certification(self, certif: str) -> None:
|
55
135
|
self.certifications[certif] = round(time.time())
|
56
|
-
|
57
|
-
def add_member(self, member:
|
136
|
+
|
137
|
+
def add_member(self, member: GroupMember) -> None:
|
58
138
|
self.members.append(member)
|
59
|
-
|
60
|
-
def remove_member(self, member:
|
139
|
+
|
140
|
+
def remove_member(self, member: GroupMember) -> None:
|
61
141
|
if member in self.members:
|
62
142
|
self.members.remove(member)
|
63
|
-
|
143
|
+
|
64
144
|
def set_owner(self, member: User) -> None:
|
65
145
|
self.owner = member
|
66
146
|
|
67
|
-
|
68
|
-
|
69
|
-
self.id: str = id
|
70
|
-
self.votes: list[str] = []
|
71
|
-
|
72
|
-
class FunctionalUser(User):
|
73
|
-
def __init__(self, id: str):
|
74
|
-
super().__init__(id)
|
75
|
-
|
76
|
-
self.permissions: dict = {
|
77
|
-
'approve_project': False,
|
78
|
-
'create_org': False,
|
79
|
-
'destroy_gov': False,
|
80
|
-
'destroy_org': False,
|
81
|
-
'propose_projects': False
|
82
|
-
}
|
83
|
-
|
84
|
-
self.mandates: int = 0
|
85
|
-
self.contribs: dict = {
|
86
|
-
'projects': 0,
|
87
|
-
'approved_projects': 0,
|
88
|
-
'admin_actions': 0,
|
89
|
-
'law_votes': 0
|
90
|
-
}
|
147
|
+
def get_member_id(self) -> list[str]:
|
148
|
+
return [ member.id for member in self.members ]
|
nsarchive/cls/exceptions.py
CHANGED
@@ -8,9 +8,18 @@ class EntityTypeError(Exception):
|
|
8
8
|
def __init__(self, *args: object) -> None:
|
9
9
|
super().__init__(*args)
|
10
10
|
|
11
|
+
class AvatarTooLongError(Exception):
|
12
|
+
def __init__(self, *args: object) -> None:
|
13
|
+
super().__init__(*args)
|
11
14
|
|
12
15
|
# Exceptions pour le vote
|
13
16
|
|
14
17
|
class AlreadyVotedError(Exception):
|
18
|
+
def __init__(self, *args: object) -> None:
|
19
|
+
super().__init__(*args)
|
20
|
+
|
21
|
+
# Ressource pas trouvée
|
22
|
+
|
23
|
+
class RessourceNotFoundError(Exception):
|
15
24
|
def __init__(self, *args: object) -> None:
|
16
25
|
super().__init__(*args)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
from .entities import *
|
2
|
+
|
3
|
+
# Votes
|
4
|
+
|
5
|
+
class Vote:
|
6
|
+
def __init__(self, id: str | NSID, title: str, choices: tuple[str]) -> None:
|
7
|
+
self.id: NSID = NSID(id)
|
8
|
+
self.title: str = title
|
9
|
+
self.choices = { choice : 0 for choice in choices }
|
10
|
+
self.author: str = '0'
|
11
|
+
self.startDate: int = 0
|
12
|
+
self.endDate: int = 0
|
13
|
+
|
14
|
+
class ClosedVote(Vote):
|
15
|
+
def __init__(self, id: str | NSID, title: str) -> None:
|
16
|
+
super().__init__(id, title, ('yes', 'no', 'blank'))
|
17
|
+
|
18
|
+
|
19
|
+
# Institutions (defs)
|
20
|
+
|
21
|
+
class Administration:
|
22
|
+
def __init__(self) -> None:
|
23
|
+
self.president: Official
|
24
|
+
self.members: list[Official]
|
25
|
+
|
26
|
+
class Government:
|
27
|
+
def __init__(self, president: Official) -> None:
|
28
|
+
self.president: Official = president
|
29
|
+
self.prime_minister: Official
|
30
|
+
|
31
|
+
self.inner_minister: Official
|
32
|
+
self.economy_minister: Official
|
33
|
+
self.justice_minister: Official
|
34
|
+
self.press_minister: Official
|
35
|
+
self.outer_minister: Official
|
36
|
+
|
37
|
+
class Assembly:
|
38
|
+
def __init__(self) -> None:
|
39
|
+
self.president: Official
|
40
|
+
self.members: list[Official]
|
41
|
+
|
42
|
+
class Court:
|
43
|
+
def __init__(self) -> None:
|
44
|
+
self.president: Official
|
45
|
+
# On discutera de la mise en place d'un potentiel président. Pour l'instant c'est le Ministre de la Justice
|
46
|
+
self.members: list[Official]
|
47
|
+
|
48
|
+
class PoliceForces:
|
49
|
+
def __init__(self) -> None:
|
50
|
+
self.president: Official
|
51
|
+
self.members: list[Official]
|
52
|
+
|
53
|
+
class Institutions:
|
54
|
+
def __init__(self) -> None:
|
55
|
+
self.administration: Administration
|
56
|
+
self.government: Government
|
57
|
+
self.court: Court
|
58
|
+
self.assembly: Assembly
|
59
|
+
self.police: PoliceForces
|
60
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import io
|
2
|
+
import os
|
3
|
+
from PIL import Image
|
4
|
+
|
5
|
+
def open(path: str) -> Image:
|
6
|
+
curr_dir = os.path.dirname(os.path.abspath(os.path.join(__file__)))
|
7
|
+
parent_dir = os.path.dirname(curr_dir)
|
8
|
+
asset_path = os.path.join(parent_dir, 'assets', path)
|
9
|
+
|
10
|
+
image = Image.open(asset_path)
|
11
|
+
val = io.BytesIO()
|
12
|
+
|
13
|
+
image.save(val, format = 'PNG')
|
14
|
+
|
15
|
+
return val.getvalue()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nsarchive
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.1
|
4
4
|
Summary:
|
5
5
|
License: GPL-3.0
|
6
6
|
Author: happex
|
@@ -11,6 +11,8 @@ Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
14
|
+
Requires-Dist: deta (>=1.2,<2.0)
|
15
|
+
Requires-Dist: pillow (>=10.4,<11.0)
|
14
16
|
Description-Content-Type: text/markdown
|
15
17
|
|
16
18
|
# nsarchive
|
@@ -76,7 +78,7 @@ entity_instance.save_entity(entity)
|
|
76
78
|
Vous pouvez rechercher des entités avec des critères spécifiques.
|
77
79
|
|
78
80
|
```python
|
79
|
-
entities = entity_instance.
|
81
|
+
entities = entity_instance.fetch_entity(query = {'name': 'Alice'})
|
80
82
|
for entity in entities:
|
81
83
|
print(entity['name'])
|
82
84
|
```
|
@@ -0,0 +1,13 @@
|
|
1
|
+
nsarchive/__init__.py,sha256=WAGTyFj-bQEgkz7tW8KTCIYqEMKq6RvjP6sp-9RaGp0,23899
|
2
|
+
nsarchive/assets/default_avatar.png,sha256=n-4vG_WPke8LvbY3ZU6oA-H-OtRoIu7woKnRq9DCIlI,51764
|
3
|
+
nsarchive/cls/archives.py,sha256=P3xOg7D7og-Vnf3VQWeIwmJRD9g7dVQBYChvMIMM6i8,2008
|
4
|
+
nsarchive/cls/base.py,sha256=z7NTvrtbeaUF1T_o-J7PL2N8axkmJek9EoKcQ8fTF9I,715
|
5
|
+
nsarchive/cls/economy.py,sha256=RjFu3VzNunazslbd4Ia5p1Jr-jJP5CvIcbVOzkDTwTU,549
|
6
|
+
nsarchive/cls/entities.py,sha256=zz0JTphgtXpCIVH8dgb3hxc55nxwvXF3m2yIXgp_Q9k,5743
|
7
|
+
nsarchive/cls/exceptions.py,sha256=QN6Qn7cxTkGoC4lO50hBAq4gZCgo7scQvCkb-xKl6Xs,692
|
8
|
+
nsarchive/cls/republic.py,sha256=FphoO9TBE9hyfdjcePjQHqBw7NFT74f-avE9T5qTTuE,1750
|
9
|
+
nsarchive/utils/assets.py,sha256=hd0STSpa0yT-OJlUyI_wCYXJqcBiUMQds2pZTXNNg9c,382
|
10
|
+
nsarchive-1.0.1.dist-info/LICENSE,sha256=aFLFZg6LEJFpTlNQ8su3__jw4GfV-xWBmC1cePkKZVw,35802
|
11
|
+
nsarchive-1.0.1.dist-info/METADATA,sha256=CdilT_3C-x4b20ccl_uwdyiWEEAXotfrJsrhQXlKgI4,5629
|
12
|
+
nsarchive-1.0.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
13
|
+
nsarchive-1.0.1.dist-info/RECORD,,
|
nsarchive/cls/votes.py
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
import time
|
2
|
-
|
3
|
-
from .entities import FunctionalUser
|
4
|
-
|
5
|
-
class Vote:
|
6
|
-
def __init__(self, id: str, title: str, choices: tuple[str]) -> None:
|
7
|
-
self.id: str = id
|
8
|
-
self.title: str = title
|
9
|
-
self.choices = { choice : 0 for choice in choices }
|
10
|
-
self.author: FunctionalUser
|
11
|
-
self.startDate: int = 0
|
12
|
-
self.endDate: int = 0
|
13
|
-
|
14
|
-
class ClosedVote(Vote):
|
15
|
-
def __init__(self, id: str, title: str) -> None:
|
16
|
-
super().__init__(id, title, ('yes', 'no', 'blank'))
|
nsarchive-0.2a0.dist-info/RECORD
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
nsarchive/__init__.py,sha256=0eu5Tf7ZuUmMQeeZ001ePNWBisoz1njUA2__Ruy6wjU,4600
|
2
|
-
nsarchive/cls/entities.py,sha256=mhBHZBtYK1E2dfTDoFHNdw1uu5QsnOc-Utuu5EjtV7c,2556
|
3
|
-
nsarchive/cls/exceptions.py,sha256=TrH9PvHhVZi7wap9ZfBLGRWJY3OBCYgWAMnco5uadYY,420
|
4
|
-
nsarchive/cls/votes.py,sha256=vASgf9ies8YPPlKBoaQdB5jB_Sp4GS_Onl8hv3_7HJU,507
|
5
|
-
nsarchive-0.2a0.dist-info/LICENSE,sha256=aFLFZg6LEJFpTlNQ8su3__jw4GfV-xWBmC1cePkKZVw,35802
|
6
|
-
nsarchive-0.2a0.dist-info/METADATA,sha256=xlZA4CPlK_RrfnzpnPApuAKhrTZgPBef9TI-8VxplIw,5552
|
7
|
-
nsarchive-0.2a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
8
|
-
nsarchive-0.2a0.dist-info/RECORD,,
|
File without changes
|
File without changes
|