wao 0.1.0 → 0.1.2

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.
@@ -1,666 +0,0 @@
1
- local bint = require('.bint')(256)
2
- local json = require('json')
3
-
4
- -- Profile: {
5
- -- UserName
6
- -- DisplayName
7
- -- Description
8
- -- CoverImage
9
- -- ProfileImage
10
- -- DateCreated
11
- -- DateUpdated
12
- -- }
13
-
14
- CurrentProfileVersion = '0.0.1'
15
-
16
- if not Profile then Profile = {} end
17
-
18
- if not Profile.Version then Profile.Version = CurrentProfileVersion end
19
-
20
- if not FirstRunCompleted then FirstRunCompleted = false end
21
- -- Assets: { Id, Type, Quantity } []
22
-
23
- if not Assets then Assets = {} end
24
-
25
- -- Collections: { Id, Name, Items, SortOrder } []
26
-
27
- if not Collections then Collections = {} end
28
-
29
- if not Roles then Roles = {} end
30
-
31
- REGISTRY = '<REGISTRY>'
32
-
33
- local function check_valid_address(address)
34
- if not address or type(address) ~= 'string' then
35
- return false
36
- end
37
-
38
- return string.match(address, "^[%w%-_]+$") ~= nil and #address == 43
39
- end
40
-
41
- local function check_required_data(data, required_fields)
42
- for _, field in ipairs(required_fields) do
43
- if data[field] ~= nil then
44
- return true
45
- end
46
- end
47
- return false
48
- end
49
-
50
- local function decode_message_data(data)
51
- local status, decoded_data = pcall(json.decode, data)
52
-
53
- if not status or type(decoded_data) ~= 'table' then
54
- return false, nil
55
- end
56
-
57
- return true, decoded_data
58
- end
59
-
60
- local function authorizeRoles(msg)
61
- -- If Roles is blank, the initial call should be from the owner
62
- if msg.From ~= Owner and msg.From ~= ao.id and #Roles == 0 then
63
- return false, {
64
- Target = msg.From,
65
- Action = 'Authorization-Error',
66
- Tags = {
67
- Status = 'Error',
68
- ErrorMessage = 'Initial Roles not set, owner is not authorized for this handler'
69
- }
70
- }
71
- end
72
-
73
- local existingRole = false
74
- for _, role in pairs(Roles) do
75
- if role.AddressOrProfile == msg.From then
76
- existingRole = true
77
- break
78
- end
79
- end
80
-
81
- if not existingRole and msg.From == Owner then
82
- -- If Roles table is empty or owner doesn't exist, authorize the owner
83
- table.insert(Roles, { Role = 'Owner', AddressOrProfile = msg.From })
84
- existingRole = true
85
- end
86
-
87
- if not existingRole then
88
- return false, {
89
- Target = msg.From,
90
- Action = 'Authorization-Error',
91
- Tags = {
92
- Status = 'Error',
93
- ErrorMessage = 'Unauthorized to access this handler'
94
- }
95
- }
96
- end
97
-
98
- return true
99
- end
100
-
101
- local function sort_collections()
102
- table.sort(Collections, function(a, b)
103
- return a.SortOrder < b.SortOrder
104
- end)
105
- end
106
-
107
- Handlers.add('Info', Handlers.utils.hasMatchingTag('Action', 'Info'),
108
- function(msg)
109
- ao.send({
110
- Target = msg.From,
111
- Action = 'Read-Success',
112
- Data = json.encode({
113
- Profile = Profile,
114
- Assets = Assets,
115
- Collections = Collections,
116
- Owner = Owner
117
- })
118
- })
119
- end)
120
-
121
- -- Data - { UserName?, DisplayName?, Description?, CoverImage, ProfileImage }
122
- --[[
123
- This function handles the 'Update-Profile' action. It first checks if the sender of the message is authorized to perform this action.
124
- If the sender is authorized, it then decodes the data from the message. If the data is valid and contains at least one of the required fields,
125
- it updates the profile with the new data and sends a success message to the sender and the registry. If the data is not valid or does not contain
126
- any of the required fields, it sends an error message to the sender.
127
-
128
- Parameters:
129
- msg:
130
- {
131
- data: { },
132
- tags: { }
133
-
134
- Returns:
135
- None. This function sends messages to the sender or the registry but does not return anything.
136
- --]]
137
- Handlers.add('Update-Profile', Handlers.utils.hasMatchingTag('Action', 'Update-Profile'),
138
- function(msg)
139
- local authorizeResult, message = authorizeRoles(msg)
140
- if not authorizeResult then
141
- ao.send(message)
142
- return
143
- end
144
-
145
- local decode_check, data = decode_message_data(msg.Data)
146
-
147
- if decode_check and data then
148
- if not check_required_data(data, { "UserName", "DisplayName", "Description", "CoverImage", "ProfileImage" }) then
149
- ao.send({
150
- Target = msg.From,
151
- Action = 'Input-Error',
152
- Tags = {
153
- Status = 'Error',
154
- EMessage =
155
- 'Invalid arguments, required at least one of { UserName, DisplayName, Description, CoverImage, ProfileImage }'
156
- }
157
- })
158
- return
159
- end
160
-
161
- Profile.UserName = msg.Tags.UserName or data.UserName or Profile.UserName or ''
162
- Profile.DisplayName = msg.Tags.DisplayName or data.DisplayName or Profile.DisplayName or ''
163
- Profile.Description = msg.Tags.Description or data.Description or Profile.Description or ''
164
- Profile.CoverImage = msg.Tags.CoverImage or data.CoverImage or Profile.CoverImage or ''
165
- Profile.ProfileImage = msg.Tags.ProfileImage or data.ProfileImage or Profile.ProfileImage or ''
166
- Profile.DateCreated = Profile.DateCreated or msg.Timestamp
167
- Profile.DateUpdated = msg.Timestamp
168
-
169
- -- if FirstRunCompleted then
170
- -- ao.assign({Processes = { REGISTRY }, Message = msg.Id})
171
- -- else
172
- ao.send({
173
- Target = REGISTRY,
174
- Action = 'Create-Profile',
175
- Data = json.encode({
176
- AuthorizedAddress = msg.From,
177
- UserName = Profile.UserName or nil,
178
- DisplayName = Profile.DisplayName or nil,
179
- Description = Profile.Description or nil,
180
- CoverImage = Profile.CoverImage or nil,
181
- ProfileImage = Profile.ProfileImage or nil,
182
- DateCreated = Profile.DateCreated,
183
- DateUpdated = Profile.DateUpdated
184
- }),
185
- Tags = msg.Tags
186
- })
187
- FirstRunCompleted = true
188
- -- end
189
-
190
- ao.send({
191
- Target = msg.From,
192
- Action = 'Profile-Success',
193
- Tags = {
194
- Status = 'Success',
195
- Message = 'Profile updated'
196
- }
197
- })
198
- else
199
- ao.send({
200
- Target = msg.From,
201
- Action = 'Input-Error',
202
- Tags = {
203
- Status = 'Error',
204
- EMessage = string.format(
205
- 'Failed to parse data, received: %s. %s.', msg.Data,
206
- 'Data must be an object - { UserName, DisplayName, Description, CoverImage, ProfileImage }')
207
- }
208
- })
209
- end
210
- end)
211
-
212
- -- Data - { Target, Recipient, Quantity }
213
- Handlers.add('Transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'),
214
- function(msg)
215
- local authorizeResult, message = authorizeRoles(msg)
216
- if not authorizeResult then
217
- ao.send(message)
218
- return
219
- end
220
-
221
- ao.send({
222
- Target = msg.Tags.Target,
223
- Action = 'Transfer',
224
- Tags = msg.Tags,
225
- Data = msg.Data
226
- })
227
- end)
228
-
229
- -- Data - { Recipient, Quantity }
230
- Handlers.add('Debit-Notice', Handlers.utils.hasMatchingTag('Action', 'Debit-Notice'),
231
- function(msg)
232
- if not msg.Tags.Recipient or not msg.Tags.Quantity then
233
- ao.send({
234
- Target = msg.From,
235
- Action = 'Input-Error',
236
- Tags = {
237
- Status = 'Error',
238
- Message =
239
- 'Invalid arguments, required { Recipient, Quantity }'
240
- }
241
- })
242
- return
243
- end
244
-
245
- if not check_valid_address(msg.Tags.Recipient) then
246
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Recipient must be a valid address' } })
247
- return
248
- end
249
-
250
- local asset_index = -1
251
- for i, asset in ipairs(Assets) do
252
- if asset.Id == msg.From then
253
- asset_index = i
254
- break
255
- end
256
- end
257
-
258
- if asset_index > -1 then
259
- local updated_quantity = tonumber(Assets[asset_index].Quantity) - tonumber(msg.Tags.Quantity)
260
-
261
- if updated_quantity <= 0 then
262
- table.remove(Assets, asset_index)
263
- else
264
- Assets[asset_index].Quantity = tostring(updated_quantity)
265
- end
266
-
267
- ao.send({
268
- Target = Owner,
269
- Action = 'Transfer-Success',
270
- Tags = {
271
- Status = 'Success',
272
- Message = 'Balance transferred'
273
- }
274
- })
275
- else
276
- ao.send({
277
- Target = msg.From,
278
- Action = 'Transfer-Failed',
279
- Tags = {
280
- Status = 'Error',
281
- Message = 'No asset found to debit'
282
- }
283
- })
284
- end
285
- end)
286
-
287
- -- Data - { Sender, Quantity }
288
- Handlers.add('Credit-Notice', Handlers.utils.hasMatchingTag('Action', 'Credit-Notice'),
289
- function(msg)
290
- if not msg.Tags.Sender or not msg.Tags.Quantity then
291
- ao.send({
292
- Target = msg.From,
293
- Action = 'Input-Error',
294
- Tags = {
295
- Status = 'Error',
296
- Message =
297
- 'Invalid arguments, required { Sender, Quantity }'
298
- }
299
- })
300
- return
301
- end
302
-
303
- if not check_valid_address(msg.Tags.Sender) then
304
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Sender must be a valid address' } })
305
- return
306
- end
307
-
308
- local asset_index = -1
309
- for i, asset in ipairs(Assets) do
310
- if asset.Id == msg.From then
311
- asset_index = i
312
- break
313
- end
314
- end
315
-
316
- if asset_index > -1 then
317
- local updated_quantity = tonumber(Assets[asset_index].Quantity) + tonumber(msg.Tags.Quantity)
318
-
319
- Assets[asset_index].Quantity = tostring(updated_quantity)
320
- else
321
- table.insert(Assets, { Id = msg.From, Quantity = msg.Tags.Quantity })
322
-
323
- ao.send({
324
- Target = Owner,
325
- Action = 'Transfer-Success',
326
- Tags = {
327
- Status = 'Success',
328
- Message = 'Balance transferred'
329
- }
330
- })
331
- end
332
-
333
- if msg.Tags.Sender ~= Owner then
334
- local walletTransferTokens = { 'xU9zFkq3X2ZQ6olwNVvr1vUWIjc3kXTWr7xKQD6dh10' }
335
- local runWalletTransfer = false
336
- for _, value in pairs(walletTransferTokens) do
337
- if value == msg.From then
338
- runWalletTransfer = true
339
- break
340
- end
341
- end
342
-
343
- if runWalletTransfer then
344
- ao.send({
345
- Target = msg.From,
346
- Action = 'Transfer',
347
- Tags = {
348
- Recipient = Owner,
349
- Quantity = msg.Tags.Quantity
350
- }
351
- })
352
- end
353
- end
354
- end)
355
-
356
- -- Data - { Id, Quantity }
357
- Handlers.add('Add-Uploaded-Asset', Handlers.utils.hasMatchingTag('Action', 'Add-Uploaded-Asset'),
358
- function(msg)
359
- -- local authorizeResult, message = authorizeRoles(msg)
360
- -- if not authorizeResult then
361
- -- ao.send(message)
362
- -- return
363
- -- end
364
-
365
- local decode_check, data = decode_message_data(msg.Data)
366
-
367
- if decode_check and data then
368
- if not data.Id or not data.Quantity then
369
- ao.send({
370
- Target = msg.From,
371
- Action = 'Input-Error',
372
- Tags = {
373
- Status = 'Error',
374
- Message =
375
- 'Invalid arguments, required { Id, Quantity }'
376
- }
377
- })
378
- return
379
- end
380
-
381
- if not check_valid_address(data.Id) then
382
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Asset Id must be a valid address' } })
383
- return
384
- end
385
-
386
- local exists = false
387
- for _, asset in ipairs(Assets) do
388
- if asset.Id == data.Id then
389
- exists = true
390
- break
391
- end
392
- end
393
-
394
- if not exists then
395
- table.insert(Assets, { Id = data.Id, Type = 'Upload', Quantity = data.Quantity })
396
- ao.send({
397
- Target = msg.From,
398
- Action = 'Add-Uploaded-Asset-Success',
399
- Tags = {
400
- Status = 'Success',
401
- Message = 'Asset added to profile'
402
- }
403
- })
404
- else
405
- ao.send({
406
- Target = msg.From,
407
- Action = 'Validation-Error',
408
- Tags = {
409
- Status = 'Error',
410
- Message = string.format(
411
- 'Asset with Id %s already exists', data.Id)
412
- }
413
- })
414
- end
415
- else
416
- ao.send({
417
- Target = msg.From,
418
- Action = 'Input-Error',
419
- Tags = {
420
- Status = 'Error',
421
- Message = string.format(
422
- 'Failed to parse data, received: %s. %s.', msg.Data,
423
- 'Data must be an object - { Id, Quantity }')
424
- }
425
- })
426
- end
427
- end)
428
-
429
- -- Data - { Id, Name, Items }
430
- Handlers.add('Add-Collection', Handlers.utils.hasMatchingTag('Action', 'Add-Collection'),
431
- function(msg)
432
- -- local authorizeResult, message = authorizeRoles(msg)
433
- -- if not authorizeResult then
434
- -- ao.send(message)
435
- -- return
436
- -- end
437
-
438
- local decode_check, data = decode_message_data(msg.Data)
439
-
440
- if decode_check and data then
441
- if not data.Id or not data.Name then
442
- ao.send({
443
- Target = msg.From,
444
- Action = 'Input-Error',
445
- Tags = {
446
- Status = 'Error',
447
- Message =
448
- 'Invalid arguments, required { Id, Name }'
449
- }
450
- })
451
- return
452
- end
453
-
454
- if not check_valid_address(data.Id) then
455
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Collection Id must be a valid address' } })
456
- return
457
- end
458
-
459
- local exists = false
460
- for _, collection in ipairs(Collections) do
461
- if collection.Id == data.Id then
462
- exists = true
463
- break
464
- end
465
- end
466
-
467
- -- Ensure the highest SortOrder for new items
468
- local highestSortOrder = 0
469
- for _, collection in ipairs(Collections) do
470
- if collection.SortOrder > highestSortOrder then
471
- highestSortOrder = collection.SortOrder
472
- end
473
- end
474
-
475
- if not exists then
476
- table.insert(Collections, { Id = data.Id, Name = data.Name, SortOrder = highestSortOrder + 1 })
477
- sort_collections()
478
- ao.send({
479
- Target = msg.From,
480
- Action = 'Add-Collection-Success',
481
- Tags = {
482
- Status = 'Success',
483
- Message = 'Collection added'
484
- }
485
- })
486
- else
487
- ao.send({
488
- Target = msg.From,
489
- Action = 'Validation-Error',
490
- Tags = {
491
- Status = 'Error',
492
- Message = string.format(
493
- 'Collection with Id %s already exists', data.Id)
494
- }
495
- })
496
- end
497
- else
498
- ao.send({
499
- Target = msg.From,
500
- Action = 'Input-Error',
501
- Tags = {
502
- Status = 'Error',
503
- Message = string.format(
504
- 'Failed to parse data, received: %s. %s.', msg.Data,
505
- 'Data must be an object - { Id, Name, Items }')
506
- }
507
- })
508
- end
509
- end)
510
-
511
- -- Data - { Ids: [Id1, Id2, ..., IdN] }
512
- Handlers.add('Update-Collection-Sort', Handlers.utils.hasMatchingTag('Action', 'Update-Collection-Sort'),
513
- function(msg)
514
- local authorizeResult, message = authorizeRoles(msg)
515
- if not authorizeResult then
516
- ao.send(message)
517
- return
518
- end
519
-
520
- local decode_check, data = decode_message_data(msg.Data)
521
-
522
- if decode_check and data then
523
- if not data.Ids then
524
- ao.send({
525
- Target = msg.From,
526
- Action = 'Input-Error',
527
- Tags = {
528
- Status = 'Error',
529
- Message = 'Invalid arguments, required { Ids }'
530
- }
531
- })
532
- return
533
- end
534
-
535
- -- Validate all IDs exist in the Collections table
536
- local valid_ids = {}
537
- local id_set = {}
538
- for _, id in ipairs(data.Ids) do
539
- for _, collection in ipairs(Collections) do
540
- if collection.Id == id then
541
- table.insert(valid_ids, id)
542
- id_set[id] = true
543
- break
544
- end
545
- end
546
- end
547
-
548
- -- Update SortOrder for valid collections
549
- for i, id in ipairs(valid_ids) do
550
- for _, collection in ipairs(Collections) do
551
- if collection.Id == id then
552
- collection.SortOrder = i
553
- end
554
- end
555
- end
556
-
557
- -- Place any collections not in the valid_ids list at the end, preserving their relative order
558
- local remaining_collections = {}
559
- for _, collection in ipairs(Collections) do
560
- if not id_set[collection.Id] then
561
- table.insert(remaining_collections, collection)
562
- end
563
- end
564
-
565
- -- Sort remaining collections by their current SortOrder
566
- table.sort(remaining_collections, function(a, b)
567
- return a.SortOrder < b.SortOrder
568
- end)
569
-
570
- -- Assign new SortOrder to remaining collections
571
- local new_sort_order = #valid_ids + 1
572
- for _, collection in ipairs(remaining_collections) do
573
- collection.SortOrder = new_sort_order
574
- new_sort_order = new_sort_order + 1
575
- end
576
-
577
- -- Sort collections by SortOrder
578
- sort_collections()
579
-
580
- ao.send({
581
- Target = msg.From,
582
- Action = 'Update-Collection-Sort-Success',
583
- Tags = {
584
- Status = 'Success',
585
- Message = 'Collections sorted'
586
- }
587
- })
588
- else
589
- ao.send({
590
- Target = msg.From,
591
- Action = 'Input-Error',
592
- Tags = {
593
- Status = 'Error',
594
- Message = string.format(
595
- 'Failed to parse data, received: %s. %s.', msg.Data,
596
- 'Data must be an object - { Ids }')
597
- }
598
- })
599
- end
600
- end)
601
-
602
- Handlers.add('Action-Response', Handlers.utils.hasMatchingTag('Action', 'Action-Response'),
603
- function(msg)
604
- if msg.Tags['Status'] and msg.Tags['Message'] then
605
- local response_tags = {
606
- Status = msg.Tags['Status'],
607
- Message = msg.Tags['Message']
608
- }
609
-
610
- if msg.Tags['Handler'] then response_tags.Handler = msg.Tags['Handler'] end
611
-
612
- ao.send({
613
- Target = Owner,
614
- Action = 'Action-Response',
615
- Tags = response_tags
616
- })
617
- end
618
- end)
619
-
620
- Handlers.add('Run-Action', Handlers.utils.hasMatchingTag('Action', 'Run-Action'),
621
- function(msg)
622
- local authorizeResult, message = authorizeRoles(msg)
623
- if not authorizeResult then
624
- ao.send(message)
625
- return
626
- end
627
-
628
- local decode_check, data = decode_message_data(msg.Data)
629
-
630
- if decode_check and data then
631
- if not data.Target or not data.Action or not data.Input then
632
- ao.send({
633
- Target = msg.From,
634
- Action = 'Input-Error',
635
- Tags = {
636
- Status = 'Error',
637
- Message =
638
- 'Invalid arguments, required { Target, Action, Input }'
639
- }
640
- })
641
- return
642
- end
643
-
644
- if not check_valid_address(data.Target) then
645
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Target must be a valid address' } })
646
- return
647
- end
648
-
649
- ao.send({
650
- Target = data.Target,
651
- Action = data.Action,
652
- Data = data.Input
653
- })
654
- else
655
- ao.send({
656
- Target = msg.From,
657
- Action = 'Input-Error',
658
- Tags = {
659
- Status = 'Error',
660
- Message = string.format(
661
- 'Failed to parse data, received: %s. %s.', msg.Data,
662
- 'Data must be an object - { Target, Action, Input }')
663
- }
664
- })
665
- end
666
- end)
@@ -1,24 +0,0 @@
1
- local ao = require("ao")
2
-
3
- Handlers.add(
4
- "allow",
5
- Handlers.utils.hasMatchingTag("Action", "Allow"),
6
- function (msg)
7
- ao.addAssignable({ From = msg.From })
8
- Handlers.utils.reply("allowed!")(msg)
9
- end
10
- )
11
-
12
- Handlers.add(
13
- "assign",
14
- Handlers.utils.hasMatchingTag("Type", "Process"),
15
- function (msg)
16
- assert(msg.From == msg.Owner, 'only process owner can execute!')
17
- assert(msg.Tags["Content-Type"] == "text/markdown" or msg.Tags["Content-Type"] == "text/plain", 'only markdown and text are allowed!')
18
- ao.send({
19
- Target = msg.Id,
20
- Data = msg.Data,
21
- Tags = { Action = "Assigned" }
22
- })
23
- end
24
- )