nsarchive 0.1a0__py3-none-any.whl → 0.1b0__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 +359 -25
- nsarchive/assets/default_avatar.png +0 -0
- nsarchive/cls/archives.py +60 -0
- nsarchive/cls/bank.py +7 -0
- nsarchive/cls/entities.py +71 -24
- nsarchive/cls/exceptions.py +3 -0
- nsarchive/cls/republic.py +59 -0
- nsarchive/utils/assets.py +15 -0
- nsarchive-0.1b0.dist-info/METADATA +175 -0
- nsarchive-0.1b0.dist-info/RECORD +12 -0
- nsarchive/cls/votes.py +0 -7
- nsarchive-0.1a0.dist-info/METADATA +0 -17
- nsarchive-0.1a0.dist-info/RECORD +0 -8
- {nsarchive-0.1a0.dist-info → nsarchive-0.1b0.dist-info}/LICENSE +0 -0
- {nsarchive-0.1a0.dist-info → nsarchive-0.1b0.dist-info}/WHEEL +0 -0
nsarchive/__init__.py
CHANGED
@@ -3,75 +3,409 @@ import time
|
|
3
3
|
import deta
|
4
4
|
|
5
5
|
from .cls.entities import *
|
6
|
+
from .cls.archives import *
|
7
|
+
from .cls.republic import *
|
8
|
+
from .cls.bank import *
|
9
|
+
|
6
10
|
from .cls.exceptions import *
|
7
11
|
|
8
12
|
class EntityInstance:
|
9
13
|
def __init__(self, token: str) -> None:
|
10
14
|
self.db = deta.Deta(token)
|
11
15
|
self.base = self.db.Base('entities')
|
16
|
+
self.electors = self.db.Base('electors')
|
17
|
+
self.archives = self.db.Base('archives')
|
18
|
+
self.avatars = self.db.Drive('avatars')
|
12
19
|
|
13
20
|
def get_entity(self, id: str) -> User | Organization | Entity:
|
14
|
-
|
15
|
-
_data =
|
21
|
+
id = id.upper()
|
22
|
+
_data = self.base.get(id)
|
16
23
|
|
17
24
|
if _data is None:
|
18
25
|
return Entity("0")
|
19
26
|
|
20
27
|
if _data['_type'] == 'user':
|
21
28
|
entity = User(id)
|
29
|
+
|
30
|
+
entity.xp = _data['xp']
|
31
|
+
entity.boosts = _data['boosts']
|
22
32
|
elif _data['_type'] == 'organization':
|
23
33
|
entity = Organization(id)
|
34
|
+
|
35
|
+
entity.owner = self.get_entity(_data['owner_id'].upper())
|
36
|
+
entity.members = [
|
37
|
+
self.get_entity(_id) for _id in _data['members']
|
38
|
+
]
|
39
|
+
|
40
|
+
entity.avatar = self.avatars.get(id).read()
|
41
|
+
|
42
|
+
entity.certifications = _data['certifications']
|
24
43
|
else:
|
25
44
|
entity = Entity(id)
|
26
45
|
|
27
46
|
entity.name = _data['name']
|
28
47
|
entity.legalPosition = _data['legalPosition'] # Métier si c'est un utilisateur, domaine professionnel si c'est un collectif
|
29
48
|
entity.registerDate = _data['registerDate']
|
30
|
-
entity.xp = _data['xp']
|
31
|
-
|
32
|
-
if type(entity) == Organization:
|
33
|
-
entity.owner = self.get_entity(_data['owner_id'])
|
34
|
-
entity.members = [
|
35
|
-
self.get_entity(_id) for _id in _data['members']
|
36
|
-
]
|
37
49
|
|
38
|
-
entity.certifications = _data['certifications']
|
39
|
-
elif type(entity) == User:
|
40
|
-
entity.boosts = _data['boosts']
|
41
|
-
|
42
50
|
return entity
|
43
|
-
|
51
|
+
|
44
52
|
def save_entity(self, entity: Entity) -> None:
|
45
53
|
_base = self.base
|
46
54
|
_data = {
|
47
55
|
'_type': 'user' if type(entity) == User else 'organization' if type(entity) == Organization else 'unknown',
|
48
56
|
'name': entity.name,
|
49
57
|
'legalPosition': entity.legalPosition,
|
50
|
-
'registerDate': entity.registerDate
|
51
|
-
'xp': entity.xp
|
58
|
+
'registerDate': entity.registerDate
|
52
59
|
}
|
53
60
|
|
54
61
|
if type(entity) == Organization:
|
55
|
-
_data['owner_id'] = entity.owner.id if entity.owner else
|
56
|
-
_data['members'] = [ member.id for member in entity.members ] if entity.members else []
|
62
|
+
_data['owner_id'] = entity.owner.id.upper() if entity.owner else "0"
|
63
|
+
_data['members'] = [ member.id.upper() for member in entity.members ] if entity.members else []
|
57
64
|
_data['certifications'] = entity.certifications
|
65
|
+
|
66
|
+
self.avatars.put(name = entity.id, data = entity.avatar)
|
58
67
|
elif type(entity) == User:
|
68
|
+
_data['xp'] = entity.xp
|
59
69
|
_data['boosts'] = entity.boosts
|
60
70
|
|
61
|
-
_base.put(_data, entity.id, expire_in = 3 * 31536000) # Données supprimées tous les trois ans
|
71
|
+
_base.put(_data, entity.id.upper(), expire_in = 3 * 31536000) # Données supprimées tous les trois ans
|
72
|
+
|
73
|
+
def delete_entity(self, entity: Entity) -> None:
|
74
|
+
self.base.delete(entity.id.upper())
|
75
|
+
|
76
|
+
if type(entity) == Organization:
|
77
|
+
self.avatars.delete(entity.id.upper())
|
78
|
+
|
79
|
+
def get_elector(self, id: str) -> Elector:
|
80
|
+
id = id.upper()
|
81
|
+
_data = self.electors.get(id)
|
82
|
+
|
83
|
+
if _data is None:
|
84
|
+
self.save_elector(Elector(id))
|
85
|
+
return Elector(id)
|
86
|
+
|
87
|
+
elector = Elector(id)
|
88
|
+
elector.votes = _data['votes']
|
89
|
+
|
90
|
+
return elector
|
91
|
+
|
92
|
+
def save_elector(self, elector: Elector):
|
93
|
+
_data = {
|
94
|
+
"votes": elector.votes
|
95
|
+
}
|
96
|
+
|
97
|
+
self.electors.put(_data, elector.id.upper())
|
98
|
+
|
99
|
+
# Les archives ne permettent pas de garder une trace des votes
|
100
|
+
# Donc je préfère aucune fonction permettant de les supprimer
|
62
101
|
|
63
|
-
def
|
102
|
+
def fetch_entities(self, query = None, listquery: dict | None = None) -> list[Entity | User | Organization]:
|
64
103
|
_res = self.base.fetch(query).items
|
65
104
|
|
66
105
|
if listquery is not None:
|
67
106
|
for item in _res:
|
68
|
-
for target, value in listquery:
|
107
|
+
for target, value in listquery.items():
|
69
108
|
if value not in item[target]:
|
70
109
|
_res.remove(item)
|
71
110
|
|
72
|
-
return _res
|
111
|
+
return [ self.get_entity(entity['key']) for entity in _res ]
|
112
|
+
|
113
|
+
def get_entity_groups(self, id: str) -> list[Organization]:
|
114
|
+
groups = self.fetch_entities({'_type': 'organization'}, {'members': id})
|
115
|
+
|
116
|
+
return [ self.get_entity(group['key']) for group in groups ]
|
117
|
+
|
118
|
+
def _add_archive(self, archive: Action):
|
119
|
+
_data = archive.__dict__.copy()
|
120
|
+
|
121
|
+
if type(archive) == Sanction:
|
122
|
+
_data['type'] = "sanction"
|
123
|
+
elif type(archive) == AdminAction:
|
124
|
+
_data['type'] = "adminaction"
|
125
|
+
else:
|
126
|
+
_data['type'] = "unknown"
|
127
|
+
|
128
|
+
del _data['id']
|
129
|
+
|
130
|
+
self.archives.put(key = archive.id, data = _data)
|
131
|
+
|
132
|
+
def _get_archive(self, id: str) -> Action | Sanction | AdminAction:
|
133
|
+
_data = self.archives.get(id)
|
134
|
+
|
135
|
+
if _data is None:
|
136
|
+
return None
|
137
|
+
|
138
|
+
if _data['type'] == "sanction": # Mute, ban, GAV, kick, détention, prune (xp seulement)
|
139
|
+
archive = Sanction(_data['author'], _data['target'])
|
140
|
+
|
141
|
+
archive.details = _data['details']
|
142
|
+
archive.major = _data['major']
|
143
|
+
archive.duration = _data['duration']
|
144
|
+
elif _data['type'] == "adminaction": # Renommage, promotion, démotion (au niveau de l'état)
|
145
|
+
archive = AdminAction(_data['author'], _data['target'])
|
146
|
+
|
147
|
+
archive.details = _data['details']
|
148
|
+
archive.new_state = _data['new_state']
|
149
|
+
else:
|
150
|
+
archive = Action(_data['author'], _data['target'])
|
151
|
+
|
152
|
+
archive.id = id
|
153
|
+
archive.action = _data['action']
|
154
|
+
archive.date = _data['date']
|
155
|
+
|
156
|
+
return archive
|
157
|
+
|
158
|
+
def _fetch_archives(self, **query) -> list[ Action | Sanction | AdminAction ]:
|
159
|
+
_res = self.archives.fetch(query).items
|
160
|
+
|
161
|
+
return [ self._get_archive(archive['key']) for archive in _res ]
|
162
|
+
|
163
|
+
class RepublicInstance:
|
164
|
+
def __init__(self, token: str) -> None:
|
165
|
+
self.db = deta.Deta(token)
|
166
|
+
self.votes = self.db.Base('votes')
|
167
|
+
self.archives = self.db.Base('archives')
|
168
|
+
self.mandate = self.db.Base('mandate')
|
169
|
+
self.functions = self.db.Base('functions') # Liste des fonctionnaires
|
170
|
+
|
171
|
+
def get_vote(self, id: str) -> Vote | ClosedVote:
|
172
|
+
id = id.upper()
|
173
|
+
_data = self.votes.get(id)
|
174
|
+
|
175
|
+
if _data is None:
|
176
|
+
return None
|
177
|
+
|
178
|
+
if _data['_type'] == 'open':
|
179
|
+
vote = Vote(id, _data['title'], tuple(_data['choices'].keys()))
|
180
|
+
elif _data['_type'] == 'closed':
|
181
|
+
vote = ClosedVote(id, _data['title'])
|
182
|
+
else:
|
183
|
+
vote = Vote('0', 'Unknown Vote', ())
|
184
|
+
|
185
|
+
vote.author = _data['author']
|
186
|
+
vote.startDate = _data['startDate']
|
187
|
+
vote.endDate = _data['endDate']
|
188
|
+
vote.choices = _data['choices']
|
189
|
+
|
190
|
+
return vote
|
191
|
+
|
192
|
+
def save_vote(self, vote: Vote | ClosedVote):
|
193
|
+
_data = {
|
194
|
+
'_type': 'open' if type(vote) == Vote else 'closed' if type(vote) == ClosedVote else 'unknown',
|
195
|
+
'title': vote.title,
|
196
|
+
'author': vote.author,
|
197
|
+
'startDate': vote.startDate,
|
198
|
+
'endDate': vote.endDate,
|
199
|
+
'choices': vote.choices
|
200
|
+
}
|
201
|
+
|
202
|
+
self.votes.put(_data, vote.id.upper())
|
203
|
+
|
204
|
+
def get_official(self, id: str, current_mandate: bool = True) -> FunctionalUser:
|
205
|
+
archives = self.mandate if current_mandate else self.archives
|
206
|
+
|
207
|
+
_contributions = archives.fetch({'author': id, 'type': 'contrib'}).items
|
208
|
+
_mandates = archives.fetch({'target': id, 'type': 'election'}).items()\
|
209
|
+
+ archives.fetch({'target': id, 'type': 'promotion'}).items()
|
210
|
+
|
211
|
+
user = FunctionalUser(id)
|
212
|
+
for mandate in _mandates:
|
213
|
+
if mandate['position'].startswith('MIN'): mandate['position'] = 'MIN'
|
214
|
+
|
215
|
+
try:
|
216
|
+
user.mandates[mandate['position']] += 1
|
217
|
+
except KeyError:
|
218
|
+
user.mandates[mandate['position']] = 1
|
219
|
+
|
220
|
+
for contrib in _contributions:
|
221
|
+
try:
|
222
|
+
user.contributions[contrib['action']] += 1
|
223
|
+
except KeyError:
|
224
|
+
user.contributions[contrib['action']] = 1
|
225
|
+
|
226
|
+
return user
|
227
|
+
|
228
|
+
def get_institutions(self) -> Organization:
|
229
|
+
admin = Administration()
|
230
|
+
gov = Government(FunctionalUser('0'))
|
231
|
+
assembly = Assembly()
|
232
|
+
court = Court()
|
233
|
+
police_forces = PoliceForces()
|
234
|
+
|
235
|
+
_admins = self.functions.get('ADMIN')
|
236
|
+
admin.members = [ self.get_official(user) for user in _admins['users'] ]
|
237
|
+
admin.president = self.get_official('F7DB60DD1C4300A') # happex (remplace Kheops pour l'instant)
|
238
|
+
|
239
|
+
gov.president = self.get_official(self.functions.get('PRE_REP')['users'][0])
|
240
|
+
|
241
|
+
minister = lambda code : self.get_official(self.functions.get(f'MIN_{code}')['users'][0])
|
242
|
+
gov.prime_minister = minister('PRIM')
|
243
|
+
gov.economy_minister = minister('ECO')
|
244
|
+
gov.inner_minister = minister('INN')
|
245
|
+
gov.press_minister = minister('AUD')
|
246
|
+
gov.justice_minister = minister('JUS')
|
247
|
+
gov.outer_minister = minister('OUT')
|
248
|
+
|
249
|
+
assembly.president = self.get_official(self.functions.get('PRE_AS')['users'][0])
|
250
|
+
assembly.members = [ self.get_official(id) for id in self.functions.get('REPR')['users'] ]
|
251
|
+
|
252
|
+
court.president = gov.justice_minister
|
253
|
+
court.members = [ self.get_official(id) for id in self.functions.get('JUDGE')['users'] ]
|
254
|
+
|
255
|
+
police_forces.president = gov.inner_minister
|
256
|
+
police_forces.members = [ self.get_official(id) for id in self.functions.get('POLICE')['users'] ]
|
257
|
+
|
258
|
+
instits = Institutions()
|
259
|
+
instits.administration = admin
|
260
|
+
instits.government = gov
|
261
|
+
instits.court = court
|
262
|
+
instits.assembly = assembly
|
263
|
+
instits.police = police_forces
|
264
|
+
|
265
|
+
return instits
|
266
|
+
|
267
|
+
def update_institutions(self, institutions: Institutions):
|
268
|
+
get_ids = lambda institution : [ member.id for member in institutions.__getattribute__(institution).members ]
|
269
|
+
|
270
|
+
self.functions.put(key = 'ADMIN', data = { 'users': get_ids('administration') })
|
271
|
+
self.functions.put(key = 'REPR', data = { 'users': get_ids('assembly') })
|
272
|
+
self.functions.put(key = 'JUDGE', data = { 'users': get_ids('court') })
|
273
|
+
self.functions.put(key = 'POLICE', data = { 'users': get_ids('police') })
|
274
|
+
|
275
|
+
self.functions.put(key = 'PRE_AS', data = { 'users': [ institutions.assembly.president.id ] })
|
276
|
+
self.functions.put(key = 'PRE_REP', data = { 'users': [ institutions.government.president.id ] })
|
277
|
+
|
278
|
+
self.functions.put(key = 'MIN_PRIM', data = { 'users': [ institutions.government.prime_minister.id ] })
|
279
|
+
self.functions.put(key = 'MIN_INN', data = { 'users': [ institutions.government.inner_minister.id ] })
|
280
|
+
self.functions.put(key = 'MIN_JUS', data = { 'users': [ institutions.government.justice_minister.id ] })
|
281
|
+
self.functions.put(key = 'MIN_ECO', data = { 'users': [ institutions.government.economy_minister.id ] })
|
282
|
+
self.functions.put(key = 'MIN_AUD', data = { 'users': [ institutions.government.press_minister.id ] })
|
283
|
+
self.functions.put(key = 'MIN_OUT', data = { 'users': [ institutions.government.outer_minister.id ] })
|
284
|
+
|
285
|
+
def new_mandate(self, institutions: Institutions, weeks: int = 4):
|
286
|
+
for item in self.mandate.fetch().items():
|
287
|
+
if item['date'] >= round(time.time()) - weeks * 604800:
|
288
|
+
self.mandate.delete(item['id'])
|
289
|
+
|
290
|
+
self.update_institutions(institutions)
|
291
|
+
|
292
|
+
def _add_archive(self, archive: Action):
|
293
|
+
_data = archive.__dict__.copy()
|
294
|
+
|
295
|
+
if type(archive) == Election:
|
296
|
+
_data['type'] = "election"
|
297
|
+
elif type(archive) == Promotion:
|
298
|
+
_data['type'] = "promotion"
|
299
|
+
elif type(archive) == Demotion:
|
300
|
+
_data['type'] = "demotion"
|
301
|
+
else:
|
302
|
+
_data['type'] = "unknown"
|
303
|
+
|
304
|
+
del _data['id']
|
305
|
+
|
306
|
+
self.archives.put(key = archive.id, data = _data)
|
307
|
+
|
308
|
+
def _get_archive(self, id: str) -> Action | Election | Promotion | Demotion:
|
309
|
+
_data = self.archives.get(id)
|
310
|
+
|
311
|
+
if _data is None:
|
312
|
+
return None
|
313
|
+
|
314
|
+
if _data['type'] == "election":
|
315
|
+
archive = Election(_data['author'], _data['target'], _data['position'])
|
316
|
+
|
317
|
+
archive.positive_votes = _data['positive_votes']
|
318
|
+
archive.total_votes = _data['total_votes']
|
319
|
+
elif _data['type'] == "promotion":
|
320
|
+
archive = Promotion(_data['author'], _data['target'], _data['position'])
|
321
|
+
elif _data['type'] == "demotion":
|
322
|
+
archive = Demotion(_data['author'], _data['target'])
|
323
|
+
|
324
|
+
archive.reason = _data['reason']
|
325
|
+
else:
|
326
|
+
archive = Action(_data['author'], _data['target'])
|
327
|
+
|
328
|
+
archive.id = id
|
329
|
+
archive.action = _data['action']
|
330
|
+
archive.date = _data['date']
|
331
|
+
|
332
|
+
return archive
|
333
|
+
|
334
|
+
def _fetch_archives(self, **query) -> list[ Action | Election | Promotion | Demotion ]:
|
335
|
+
_res = self.archives.fetch(query).items
|
336
|
+
|
337
|
+
return [ self._get_archive(archive['key']) for archive in _res ]
|
338
|
+
|
339
|
+
class BankInstance:
|
340
|
+
def __init__(self, token: str) -> None:
|
341
|
+
self.db = deta.Deta(token)
|
342
|
+
self.archives = self.db.Base('archives')
|
343
|
+
self.accounts = self.db.Base('accounts')
|
344
|
+
self.registry = self.db.Base('banks')
|
345
|
+
|
346
|
+
def get_account(self, id: str) -> BankAccount:
|
347
|
+
id = id.upper()
|
348
|
+
_data = self.accounts.get(id)
|
349
|
+
|
350
|
+
if _data is None:
|
351
|
+
return None
|
352
|
+
|
353
|
+
acc = BankAccount(id)
|
354
|
+
acc.amount = _data['amount']
|
355
|
+
acc.locked = _data['locked']
|
356
|
+
acc.owner = _data['owner_id']
|
357
|
+
acc.bank = _data['bank']
|
358
|
+
|
359
|
+
return acc
|
360
|
+
|
361
|
+
def save_account(self, acc: BankAccount):
|
362
|
+
_data = {
|
363
|
+
'amount': acc.amount,
|
364
|
+
'locked': acc.locked,
|
365
|
+
'owner_id': acc.owner,
|
366
|
+
'bank': acc.bank
|
367
|
+
}
|
368
|
+
|
369
|
+
self.accounts.put(_data, acc.id.upper())
|
370
|
+
|
371
|
+
def lock_account(self, acc: BankAccount):
|
372
|
+
acc.locked = True
|
373
|
+
|
374
|
+
self.save_account(acc)
|
375
|
+
|
376
|
+
def _add_archive(self, _archive: Action):
|
377
|
+
_data = _archive.__dict__.copy()
|
378
|
+
|
379
|
+
if type(_archive) == Transaction:
|
380
|
+
_data['type'] = "transaction"
|
381
|
+
else:
|
382
|
+
_data['type'] = "unknown"
|
383
|
+
|
384
|
+
del _data['id']
|
385
|
+
|
386
|
+
self.archives.put(key = _archive.id, data = _data)
|
387
|
+
|
388
|
+
def _get_archive(self, id: str) -> Action | Transaction:
|
389
|
+
_data = self.archives.get(id)
|
390
|
+
|
391
|
+
if _data is None:
|
392
|
+
return None
|
393
|
+
|
394
|
+
if _data['type'] == "transaction":
|
395
|
+
archive = Transaction(_data['author'], _data['target'], _data['amount'])
|
396
|
+
|
397
|
+
archive.reason = _data['reason']
|
398
|
+
archive.currency = _data['currency']
|
399
|
+
else:
|
400
|
+
archive = Action(_data['author'], _data['target'])
|
401
|
+
|
402
|
+
archive.id = id
|
403
|
+
archive.action = _data['action']
|
404
|
+
archive.date = _data['date']
|
405
|
+
|
406
|
+
return archive
|
73
407
|
|
74
|
-
def
|
75
|
-
|
408
|
+
def _fetch_archives(self, **query) -> list[ Action | Transaction ]:
|
409
|
+
_res = self.archives.fetch(query).items
|
76
410
|
|
77
|
-
return [ self.
|
411
|
+
return [ self._get_archive(archive['key']) for archive in _res ]
|
Binary file
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
class Action:
|
4
|
+
def __init__(self, author: str = '11625D9061021010', target: str = '0') -> None:
|
5
|
+
self.id: str = hex(round(time.time()))[2:].upper()
|
6
|
+
self.date: int = int(self.id, 16)
|
7
|
+
self.action: str = ""
|
8
|
+
self.author: str = author
|
9
|
+
self.target: str = target
|
10
|
+
|
11
|
+
|
12
|
+
# Entities
|
13
|
+
|
14
|
+
class Sanction(Action):
|
15
|
+
def __init__(self, author: str, target: str) -> None:
|
16
|
+
super().__init__(author, target)
|
17
|
+
|
18
|
+
self.details: str = ""
|
19
|
+
self.major: bool = False # Sanction majeure ou non
|
20
|
+
self.duration: int = 0 # Durée en secondes, 0 = définitif
|
21
|
+
|
22
|
+
class AdminAction(Action):
|
23
|
+
def __init__(self, author: str, target: str) -> None:
|
24
|
+
super().__init__(author, target)
|
25
|
+
|
26
|
+
self.details: str = ""
|
27
|
+
self.new_state: str | int | bool = None
|
28
|
+
|
29
|
+
|
30
|
+
# Community
|
31
|
+
|
32
|
+
class Election(Action):
|
33
|
+
def __init__(self, author: str, target: str, position: str) -> None:
|
34
|
+
super().__init__(author, target)
|
35
|
+
|
36
|
+
self.position: str = position
|
37
|
+
self.positive_votes: int = 0
|
38
|
+
self.total_votes: int = 0
|
39
|
+
|
40
|
+
class Promotion(Action):
|
41
|
+
def __init__(self, author: str, target: str, position: str) -> None:
|
42
|
+
super().__init__(author, target)
|
43
|
+
|
44
|
+
self.position: str = position
|
45
|
+
|
46
|
+
class Demotion(Action):
|
47
|
+
def __init__(self, author: str, target: str) -> None:
|
48
|
+
super().__init__(author, target)
|
49
|
+
|
50
|
+
self.reason: str = None
|
51
|
+
|
52
|
+
# Bank
|
53
|
+
|
54
|
+
class Transaction(Action):
|
55
|
+
def __init__(self, author: str, target: str, amount: int) -> None:
|
56
|
+
super().__init__(author, target)
|
57
|
+
|
58
|
+
self.amount: int = amount
|
59
|
+
self.currency: str = 'HC'
|
60
|
+
self.reason: str = None
|
nsarchive/cls/bank.py
ADDED
nsarchive/cls/entities.py
CHANGED
@@ -1,23 +1,18 @@
|
|
1
|
+
import io
|
1
2
|
import time
|
2
3
|
|
3
4
|
from .exceptions import *
|
4
5
|
|
6
|
+
from ..utils import assets
|
7
|
+
|
5
8
|
class Entity:
|
6
|
-
def __init__(self, id: str):
|
7
|
-
self.id: str = id # ID hexadécimal de l'entité
|
8
|
-
self.name: str =
|
9
|
+
def __init__(self, id: str) -> None:
|
10
|
+
self.id: str = id # ID hexadécimal de l'entité (ou nom dans le cas de l'entreprise)
|
11
|
+
self.name: str = "Entité Inconnue"
|
9
12
|
self.registerDate: int = 0
|
10
|
-
self.legalPosition:
|
11
|
-
self.xp: int = 0
|
12
|
-
|
13
|
-
def get_level(self) -> None:
|
14
|
-
i = 0
|
15
|
-
while self.xp > int(round(25 * (i * 2.5) ** 2, -2)):
|
16
|
-
i += 1
|
17
|
-
|
18
|
-
return i
|
13
|
+
self.legalPosition: str = 'Membre'
|
19
14
|
|
20
|
-
def
|
15
|
+
def set_name(self, new_name: str) -> None:
|
21
16
|
if len(new_name) > 32:
|
22
17
|
raise NameTooLongError(f"Name length mustn't exceed 32 characters.")
|
23
18
|
|
@@ -25,36 +20,80 @@ class Entity:
|
|
25
20
|
|
26
21
|
def set_position(self, position: str) -> None:
|
27
22
|
self.legalPosition = position
|
28
|
-
|
29
|
-
def add_xp(self, amount: int) -> None:
|
30
|
-
boost = 0 if 0 in self.boosts.values() else max(list(self.boosts.values()) + [ 1 ])
|
31
23
|
|
32
|
-
self.xp += amount * boost
|
33
|
-
|
34
24
|
class User(Entity):
|
35
|
-
def __init__(self, id: str):
|
25
|
+
def __init__(self, id: str) -> None:
|
36
26
|
super().__init__(id)
|
37
27
|
|
28
|
+
self.xp: int = 0
|
38
29
|
self.boosts: dict[str, int] = {}
|
30
|
+
|
31
|
+
def get_level(self) -> None:
|
32
|
+
i = 0
|
33
|
+
while self.xp > int(round(25 * (i * 2.5) ** 2, -2)):
|
34
|
+
i += 1
|
35
|
+
|
36
|
+
return i
|
39
37
|
|
38
|
+
def add_xp(self, amount: int) -> None:
|
39
|
+
boost = 0 if 0 in self.boosts.values() else max(list(self.boosts.values()) + [ 1 ])
|
40
|
+
|
41
|
+
self.xp += amount * boost
|
42
|
+
|
40
43
|
def edit_boost(self, name: str, multiplier: int = -1) -> None:
|
41
44
|
if multiplier >= 0:
|
42
45
|
self.boosts[name] = multiplier
|
43
46
|
else:
|
44
47
|
del self.boosts[name]
|
45
48
|
|
49
|
+
class MemberPermissions:
|
50
|
+
def __init__(self) -> None:
|
51
|
+
self.manage_organization = False # Renommer ou changer le logo
|
52
|
+
self.manage_members = False # Virer quelqu'un d'une entreprise, l'y inviter, changer ses rôles
|
53
|
+
self.manage_roles = False # Promouvoir ou rétrograder les membres
|
54
|
+
|
55
|
+
def edit(self, **permissions: bool) -> None:
|
56
|
+
for perm in permissions.values():
|
57
|
+
self.__setattr__(*perm)
|
58
|
+
|
59
|
+
class GroupMember(User):
|
60
|
+
def __init__(self, id: str) -> None:
|
61
|
+
super().__init__(id)
|
62
|
+
|
63
|
+
self.permissions: MemberPermissions = MemberPermissions()
|
64
|
+
|
65
|
+
class FunctionalUser:
|
66
|
+
def __init__(self, id: str) -> None:
|
67
|
+
self.id: str = id
|
68
|
+
|
69
|
+
self.mandates: int = {
|
70
|
+
'PRE_REP': 0, # Président de la République
|
71
|
+
'MIN': 0, # Différents ministres
|
72
|
+
'PRE_AS': 0, # Président de l'Assemblée Nationale
|
73
|
+
'JUDGE': 0, # Juge
|
74
|
+
'REPR': 0 # Député
|
75
|
+
}
|
76
|
+
|
77
|
+
self.contributions: dict = {
|
78
|
+
'project': 0,
|
79
|
+
'approved_project': 0,
|
80
|
+
'admin_action': 0,
|
81
|
+
'law_vote': 0
|
82
|
+
}
|
83
|
+
|
46
84
|
class Organization(Entity):
|
47
|
-
def __init__(self, id: str):
|
85
|
+
def __init__(self, id: str) -> None:
|
48
86
|
super().__init__(id)
|
49
87
|
|
50
88
|
self.owner: Entity
|
51
89
|
self.certifications: dict = {}
|
52
|
-
self.members: list = []
|
53
|
-
|
90
|
+
self.members: list[GroupMember] = []
|
91
|
+
self.avatar: bytes = assets.open('default_avatar.png')
|
92
|
+
|
54
93
|
def add_certification(self, certif: str) -> None:
|
55
94
|
self.certifications[certif] = round(time.time())
|
56
95
|
|
57
|
-
def add_member(self, member:
|
96
|
+
def add_member(self, member: GroupMember) -> None:
|
58
97
|
self.members.append(member)
|
59
98
|
|
60
99
|
def remove_member(self, member: User) -> None:
|
@@ -62,4 +101,12 @@ class Organization(Entity):
|
|
62
101
|
self.members.remove(member)
|
63
102
|
|
64
103
|
def set_owner(self, member: User) -> None:
|
65
|
-
self.owner = member
|
104
|
+
self.owner = member
|
105
|
+
|
106
|
+
def get_member_id(self) -> list[str]:
|
107
|
+
return [ member.id for member in self.members ]
|
108
|
+
|
109
|
+
class Elector(User):
|
110
|
+
def __init__(self, id: str) -> None:
|
111
|
+
super().__init__(id)
|
112
|
+
self.votes: list[str] = []
|
nsarchive/cls/exceptions.py
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
from .entities import *
|
2
|
+
|
3
|
+
# Votes
|
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: str = '0'
|
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'))
|
17
|
+
|
18
|
+
|
19
|
+
# Institutions (defs)
|
20
|
+
|
21
|
+
class Administration:
|
22
|
+
def __init__(self) -> None:
|
23
|
+
self.president: FunctionalUser
|
24
|
+
self.members: list[FunctionalUser]
|
25
|
+
|
26
|
+
class Government:
|
27
|
+
def __init__(self, president: FunctionalUser) -> None:
|
28
|
+
self.president: FunctionalUser = president
|
29
|
+
self.prime_minister: FunctionalUser
|
30
|
+
|
31
|
+
self.inner_minister: FunctionalUser
|
32
|
+
self.economy_minister: FunctionalUser
|
33
|
+
self.justice_minister: FunctionalUser
|
34
|
+
self.press_minister: FunctionalUser
|
35
|
+
self.outer_minister: FunctionalUser
|
36
|
+
|
37
|
+
class Assembly:
|
38
|
+
def __init__(self) -> None:
|
39
|
+
self.president: FunctionalUser
|
40
|
+
self.members: list[FunctionalUser]
|
41
|
+
|
42
|
+
class Court:
|
43
|
+
def __init__(self) -> None:
|
44
|
+
self.president: FunctionalUser
|
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[FunctionalUser]
|
47
|
+
|
48
|
+
class PoliceForces:
|
49
|
+
def __init__(self) -> None:
|
50
|
+
self.president: FunctionalUser
|
51
|
+
self.members: list[FunctionalUser]
|
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
|
@@ -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()
|
@@ -0,0 +1,175 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: nsarchive
|
3
|
+
Version: 0.1b0
|
4
|
+
Summary:
|
5
|
+
License: GPL-3.0
|
6
|
+
Author: happex
|
7
|
+
Author-email: 110610727+okayhappex@users.noreply.github.com
|
8
|
+
Requires-Python: >=3.10,<4.0
|
9
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
14
|
+
Description-Content-Type: text/markdown
|
15
|
+
|
16
|
+
# nsarchive
|
17
|
+
|
18
|
+
`nsarchive` est un module Python pour la gestion des entités (utilisateurs et organisations) à l'aide de la base de données Deta. Ce module permet de créer, récupérer, sauvegarder et gérer des entités et leurs attributs spécifiques.
|
19
|
+
|
20
|
+
## Pré-requis
|
21
|
+
|
22
|
+
Listes des choses à avoir afin de pouvoir utiliser le module correctement:
|
23
|
+
- [Python 3.10](https://www.python.org/downloads/) ou supérieur
|
24
|
+
- Un token [Deta](https://deta.space), donné par un administrateur ou pour votre collection personnelle
|
25
|
+
- Un bon capuccino, pour commencer la programmation en bons termes
|
26
|
+
|
27
|
+
> **Note:** Il vous faudra un token différent pour accéder aux différentes parties de la base de données. Vos tokens n'expireront pas à moins que l'ordre en aura été donné
|
28
|
+
|
29
|
+
## Installation
|
30
|
+
|
31
|
+
Vous pouvez installer ce module via pip :
|
32
|
+
|
33
|
+
```sh
|
34
|
+
pip install nsarchive
|
35
|
+
```
|
36
|
+
|
37
|
+
## Utilisation
|
38
|
+
|
39
|
+
### Importation et Initialisation
|
40
|
+
|
41
|
+
Pour utiliser `nsarchive`, commencez par importer le module et initialiser une instance d'`EntityInstance` avec votre token Deta.
|
42
|
+
|
43
|
+
```python
|
44
|
+
from nsarchive import EntityInstance
|
45
|
+
|
46
|
+
# Remplacez 'your_deta_token' par votre véritable token Deta
|
47
|
+
entity_instance = EntityInstance(token = 'your_deta_token')
|
48
|
+
```
|
49
|
+
|
50
|
+
### Récupérer une Entité
|
51
|
+
|
52
|
+
Vous pouvez récupérer une entité (Utilisateur ou Organisation) à l'aide de son ID.
|
53
|
+
|
54
|
+
```python
|
55
|
+
entity = entity_instance.get_entity(id = 'entity_id')
|
56
|
+
print(entity.name)
|
57
|
+
```
|
58
|
+
|
59
|
+
**ATTENTION: Les entités sont identifiées sous une forme hexadécimale. Pour les avoir, vous devez convertir leur ID Discord en hexadécimale puis enlever le préfixe `0x`.**
|
60
|
+
|
61
|
+
Pour les organisations, l'ID Discord correspondra à la formule suivante: `ID fondateur // 100000`.
|
62
|
+
|
63
|
+
N'oubliez pas de toujours utiliser un `str` dans les ID pour interagir avec la base de données.
|
64
|
+
|
65
|
+
### Sauvegarder une Entité
|
66
|
+
|
67
|
+
Après avoir modifié une entité, vous pouvez la sauvegarder dans la base de données.
|
68
|
+
|
69
|
+
```python
|
70
|
+
entity.rename("Nouveau Nom")
|
71
|
+
entity_instance.save_entity(entity)
|
72
|
+
```
|
73
|
+
|
74
|
+
### Rechercher des Entités
|
75
|
+
|
76
|
+
Vous pouvez rechercher des entités avec des critères spécifiques.
|
77
|
+
|
78
|
+
```python
|
79
|
+
entities = entity_instance.fetch_entity(query = {'name': 'Alice'})
|
80
|
+
for entity in entities:
|
81
|
+
print(entity['name'])
|
82
|
+
```
|
83
|
+
|
84
|
+
### Gérer les Organisations
|
85
|
+
|
86
|
+
Les organisations peuvent avoir des membres et des certifications. Voici comment ajouter un membre ou une certification.
|
87
|
+
|
88
|
+
```python
|
89
|
+
organization = entity_instance.get_entity(id = 'org_id')
|
90
|
+
user = entity_instance.get_entity(id = 'user_id')
|
91
|
+
|
92
|
+
# Ajouter un membre
|
93
|
+
organization.add_member(user)
|
94
|
+
entity_instance.save_entity(organization)
|
95
|
+
|
96
|
+
# Ajouter une certification
|
97
|
+
organization.add_certification('Certification Example')
|
98
|
+
entity_instance.save_entity(organization)
|
99
|
+
```
|
100
|
+
|
101
|
+
Les certifications pourront être utilisées pour vérifier l'officialité d'une organisation, mais également pour déterminer si l'on peut accorder (ou non) des permissions à ses membres.
|
102
|
+
|
103
|
+
### Exemples de Classes
|
104
|
+
|
105
|
+
#### `Entity`
|
106
|
+
|
107
|
+
Classe parente des classes `User` et `Organization`, elle est utilisée lorsque le module ne peut pas déterminer l'appartenance d'une identité à l'une de ces deux classes ou à l'autre.
|
108
|
+
|
109
|
+
```python
|
110
|
+
from nsarchive.cls.entities import Entity
|
111
|
+
|
112
|
+
entity = Entity(id='entity_id')
|
113
|
+
entity.rename('New Name')
|
114
|
+
entity.add_xp(100)
|
115
|
+
print(entity.get_level())
|
116
|
+
```
|
117
|
+
|
118
|
+
#### `User`
|
119
|
+
|
120
|
+
```python
|
121
|
+
from nsarchive.cls.entities import User
|
122
|
+
|
123
|
+
user = User(id = 'user_id')
|
124
|
+
user.edit_boost(name = 'admin', multiplier = 5) # Négliger le paramètre <multiplier> ou le fixer à un nombre négatif reviendrait à supprimer le boost.
|
125
|
+
print(user.boosts)
|
126
|
+
```
|
127
|
+
|
128
|
+
> **Note:** Lorsqu'on ajoute de l'expérience à un utilisateur via la méthode `add_xp`, le nombre de points ajoutés est automatiquement multiplié par le bonus le plus important dont l'utilisateur bénéficie.
|
129
|
+
|
130
|
+
#### `Organization`
|
131
|
+
|
132
|
+
```python
|
133
|
+
from nsarchive.cls.entities import Organization
|
134
|
+
|
135
|
+
organization = Organization(id = 'org_id')
|
136
|
+
organization.set_owner(user)
|
137
|
+
organization.add_member(user)
|
138
|
+
print(organization.members)
|
139
|
+
```
|
140
|
+
|
141
|
+
> **Note:** Les attributs `owner` et `members` sont indépendants. L'owner peut être n'importe quelle personne faisant ou non partie des `members`.
|
142
|
+
|
143
|
+
## Gestion des Exceptions
|
144
|
+
|
145
|
+
`nsarchive` fournit des exceptions spécifiques pour gérer les erreurs courantes.
|
146
|
+
|
147
|
+
#### `NameTooLongError`
|
148
|
+
|
149
|
+
Lancé lorsque le nom d'une entité dépasse la longueur maximale autorisée (32 caractères).
|
150
|
+
|
151
|
+
```python
|
152
|
+
from nsarchive.cls.exceptions import NameTooLongError
|
153
|
+
|
154
|
+
try:
|
155
|
+
entity.rename('Ce nom est long, voire même très long, je dirais même extrêmement long')
|
156
|
+
except NameTooLongError as e:
|
157
|
+
print(e)
|
158
|
+
```
|
159
|
+
|
160
|
+
#### `EntityTypeError`
|
161
|
+
|
162
|
+
Lancé lorsque le type d'entité est incorrect. Vous ne devriez normalement pas la rencontrer en utilisant le module, mais elle pourrait vous être utile.
|
163
|
+
|
164
|
+
```python
|
165
|
+
from nsarchive.cls.exceptions import EntityTypeError
|
166
|
+
|
167
|
+
try:
|
168
|
+
# Code qui peut lancer une EntityTypeError
|
169
|
+
except EntityTypeError as e:
|
170
|
+
print(e)
|
171
|
+
```
|
172
|
+
|
173
|
+
## License
|
174
|
+
|
175
|
+
Ce projet est sous licence GNU GPL-3.0 - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
nsarchive/__init__.py,sha256=Y-I47MuPc8FIHIhvt8RZ-t5TXAi7APD0XlfEjqevfjk,15273
|
2
|
+
nsarchive/assets/default_avatar.png,sha256=n-4vG_WPke8LvbY3ZU6oA-H-OtRoIu7woKnRq9DCIlI,51764
|
3
|
+
nsarchive/cls/archives.py,sha256=5C66pXuXAANRXNDqNTvIepRtUrXIWOL7ymmYiBHsHAY,1720
|
4
|
+
nsarchive/cls/bank.py,sha256=OactEpRn8PGv7BwnBUbMpzgHqrvv4yx526AMzh9uBO8,220
|
5
|
+
nsarchive/cls/entities.py,sha256=u5u46HzHJp2H_DngLALLgedHaLXlJpjhmxU_Ggozp3Q,3474
|
6
|
+
nsarchive/cls/exceptions.py,sha256=UZ7G7AFUN5OkKAGpNl1OT7jauF1jC7WW8wWXVFt5sMs,539
|
7
|
+
nsarchive/cls/republic.py,sha256=aY79B5PZF5IErwzEjn9ito6T8gXA4trm6LmIeYu6XLM,1821
|
8
|
+
nsarchive/utils/assets.py,sha256=hd0STSpa0yT-OJlUyI_wCYXJqcBiUMQds2pZTXNNg9c,382
|
9
|
+
nsarchive-0.1b0.dist-info/LICENSE,sha256=aFLFZg6LEJFpTlNQ8su3__jw4GfV-xWBmC1cePkKZVw,35802
|
10
|
+
nsarchive-0.1b0.dist-info/METADATA,sha256=rvpiq-iES71BGQ2r4pUmSPeItUkt0KW6u-XqZExWNXk,5559
|
11
|
+
nsarchive-0.1b0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
12
|
+
nsarchive-0.1b0.dist-info/RECORD,,
|
nsarchive/cls/votes.py
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: nsarchive
|
3
|
-
Version: 0.1a0
|
4
|
-
Summary:
|
5
|
-
License: GPL-3.0
|
6
|
-
Author: happex
|
7
|
-
Author-email: 110610727+okayhappex@users.noreply.github.com
|
8
|
-
Requires-Python: >=3.10,<4.0
|
9
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
14
|
-
Description-Content-Type: text/markdown
|
15
|
-
|
16
|
-
# 1ns-archive
|
17
|
-
|
nsarchive-0.1a0.dist-info/RECORD
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
nsarchive/__init__.py,sha256=cWlY3WvOeAmzwU0TC6VH0V2NfZeL4dbi_7ocneQ5els,2767
|
2
|
-
nsarchive/cls/entities.py,sha256=IrQSciTyb1fS-AumcGxyD35ONfvNa49CwfTQNDrFEkA,1895
|
3
|
-
nsarchive/cls/exceptions.py,sha256=TrH9PvHhVZi7wap9ZfBLGRWJY3OBCYgWAMnco5uadYY,420
|
4
|
-
nsarchive/cls/votes.py,sha256=p5QnvQQTaKkZDjfZa2qDgGrpCmu4vQV8-9drPayZ0oE,221
|
5
|
-
nsarchive-0.1a0.dist-info/LICENSE,sha256=aFLFZg6LEJFpTlNQ8su3__jw4GfV-xWBmC1cePkKZVw,35802
|
6
|
-
nsarchive-0.1a0.dist-info/METADATA,sha256=Kn6vtRhpgpk091l-IlmMpfUGVf8bbnfig0eA63c93cw,518
|
7
|
-
nsarchive-0.1a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
8
|
-
nsarchive-0.1a0.dist-info/RECORD,,
|
File without changes
|
File without changes
|