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.
- package/cjs/aoconnect.js +2 -2
- package/cjs/index.js +6 -0
- package/{test/lua/aos.wasm → cjs/lua/aos2_0_1.wasm} +0 -0
- package/cjs/utils.js +1 -16
- package/esm/aoconnect.js +2 -2
- package/esm/index.js +2 -1
- package/esm/utils.js +0 -18
- package/package.json +1 -1
- package/test/aoconnect.js +2 -2
- package/test/index.js +2 -1
- package/test/package.json +1 -1
- package/test/utils.js +0 -18
- package/esm/lua/aos-sqlite.wasm +0 -0
- package/esm/lua/aos.wasm +0 -0
- package/esm/lua/aos2.lua +0 -33
- package/esm/lua/atomic-asset.lua +0 -238
- package/esm/lua/atomic-note-library.lua +0 -2274
- package/esm/lua/atomic-note.lua +0 -11
- package/esm/lua/collection-registry.lua +0 -202
- package/esm/lua/collection.lua +0 -173
- package/esm/lua/notebook.lua +0 -173
- package/esm/lua/profile.lua +0 -858
- package/esm/lua/profile000.lua +0 -666
- package/esm/lua/proxy.lua +0 -24
- package/esm/lua/registry.lua +0 -858
- package/esm/lua/registry000.lua +0 -636
- package/test/lua/aos-sqlite.wasm +0 -0
- package/test/lua/aos2.lua +0 -33
- package/test/lua/atomic-asset.lua +0 -238
- package/test/lua/atomic-note-library.lua +0 -2274
- package/test/lua/atomic-note.lua +0 -11
- package/test/lua/collection-registry.lua +0 -202
- package/test/lua/collection.lua +0 -173
- package/test/lua/notebook.lua +0 -173
- package/test/lua/profile.lua +0 -858
- package/test/lua/profile000.lua +0 -666
- package/test/lua/proxy.lua +0 -24
- package/test/lua/registry.lua +0 -858
- package/test/lua/registry000.lua +0 -636
package/test/lua/profile.lua
DELETED
|
@@ -1,858 +0,0 @@
|
|
|
1
|
-
local json = require('json')
|
|
2
|
-
local sqlite3 = require('lsqlite3')
|
|
3
|
-
|
|
4
|
-
Db = Db or sqlite3.open_memory()
|
|
5
|
-
ao.addAssignable("AssignableRule", { Action = '_' })
|
|
6
|
-
local HandlerRoles = {
|
|
7
|
-
['Update-Profile'] = {'Owner', 'Admin'},
|
|
8
|
-
['Add-Uploaded-Asset'] = {'Owner', 'Admin', 'Contributor'},
|
|
9
|
-
['Add-Collection'] = {'Owner', 'Admin', 'Contributor'},
|
|
10
|
-
['Update-Collection-Sort'] = {'Owner', 'Admin'},
|
|
11
|
-
['Transfer'] = {'Owner', 'Admin'},
|
|
12
|
-
['Debit-Notice'] = {'Owner', 'Admin'},
|
|
13
|
-
['Credit-Notice'] = {'Owner', 'Admin'},
|
|
14
|
-
['Action-Response'] = {'Owner', 'Admin'},
|
|
15
|
-
['Run-Action'] = {'Owner', 'Admin'},
|
|
16
|
-
['Proxy-Action'] = {'Owner', 'Admin'},
|
|
17
|
-
['Update-Role'] = {'Owner', 'Admin'}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
local function decode_message_data(data)
|
|
21
|
-
local status, decoded_data = pcall(json.decode, data)
|
|
22
|
-
if not status or type(decoded_data) ~= 'table' then
|
|
23
|
-
return false, nil
|
|
24
|
-
end
|
|
25
|
-
return true, decoded_data
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
local function is_authorized(profile_id, user_id, roles)
|
|
29
|
-
if not profile_id then
|
|
30
|
-
return false
|
|
31
|
-
end
|
|
32
|
-
local query = [[
|
|
33
|
-
SELECT role
|
|
34
|
-
FROM ao_profile_authorization
|
|
35
|
-
WHERE profile_id = ? AND delegate_address = ?
|
|
36
|
-
LIMIT 1
|
|
37
|
-
]]
|
|
38
|
-
local stmt = Db:prepare(query)
|
|
39
|
-
stmt:bind_values(profile_id, user_id)
|
|
40
|
-
local authorized = false
|
|
41
|
-
for row in stmt:nrows() do
|
|
42
|
-
for _, role in ipairs(roles) do
|
|
43
|
-
if row.role == role then
|
|
44
|
-
authorized = true
|
|
45
|
-
break
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
stmt:finalize()
|
|
50
|
-
return authorized
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
local function process_profile_action(msg)
|
|
54
|
-
|
|
55
|
-
local reply_to = msg.From
|
|
56
|
-
local decode_check, data = decode_message_data(msg.Data)
|
|
57
|
-
if not decode_check then
|
|
58
|
-
ao.send({
|
|
59
|
-
Target = reply_to,
|
|
60
|
-
Action = 'ERROR',
|
|
61
|
-
Tags = {
|
|
62
|
-
Status = 'DECODE_FAILED',
|
|
63
|
-
Message = "Failed to decode data"
|
|
64
|
-
},
|
|
65
|
-
Data = { Code = "DECODE_FAILED" }
|
|
66
|
-
})
|
|
67
|
-
return
|
|
68
|
-
end
|
|
69
|
-
local tags = msg.Tags or {}
|
|
70
|
-
-- see if new version of update
|
|
71
|
-
-- handle legacy authorized_address tag
|
|
72
|
-
local legacy_authorized_address = tags.AuthorizedAddress or decode_check and data.AuthorizedAddress or nil
|
|
73
|
-
-- new api: profile_id is msg id on spawn or msg.Target in update
|
|
74
|
-
local target = msg.Target and msg.Target ~= "" and msg.Target or nil
|
|
75
|
-
local profile_id = legacy_authorized_address and msg.From or target or msg.Id -- create = msg.Id spawn
|
|
76
|
-
local user_id = legacy_authorized_address or msg.From -- (assigned) -- AuthorizedAddress
|
|
77
|
-
|
|
78
|
-
-- new api: after spawn, updates assigned will need to include ProfileProcess tag or data
|
|
79
|
-
|
|
80
|
-
-- update and new api if msg.Tags.Type == "Message" and msg.Target ~= ao.id (Self)
|
|
81
|
-
|
|
82
|
-
local is_update = msg.Tags.Type == "Message" and msg.Target ~= ao.id or false -- and action == "Create-Profile" or action == "Update-Profile"
|
|
83
|
-
-- handle legacy "every update is create action" bug by checking roles first
|
|
84
|
-
if not is_update then
|
|
85
|
-
local check = Db:prepare('SELECT 1 FROM ao_profile_authorization WHERE delegate_address = ? AND profile_id = ? LIMIT 1')
|
|
86
|
-
check:bind_values(user_id, profile_id)
|
|
87
|
-
if check:step() ~= sqlite3.ROW then
|
|
88
|
-
is_update = false
|
|
89
|
-
local insert_auth = Db:prepare(
|
|
90
|
-
'INSERT INTO ao_profile_authorization (profile_id, delegate_address, role) VALUES (?, ?, ?)')
|
|
91
|
-
insert_auth:bind_values(profile_id, user_id, 'Owner')
|
|
92
|
-
insert_auth:step()
|
|
93
|
-
insert_auth:finalize()
|
|
94
|
-
else
|
|
95
|
-
is_update = true
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
if is_update and not is_authorized(profile_id, user_id, HandlerRoles['Update-Profile']) then
|
|
100
|
-
ao.send({
|
|
101
|
-
Target = reply_to,
|
|
102
|
-
Action = 'Authorization-Error',
|
|
103
|
-
Tags = {
|
|
104
|
-
Status = 'Error',
|
|
105
|
-
Message = 'Unauthorized to access this handler'
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
return
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
local columns = {}
|
|
112
|
-
local placeholders = {}
|
|
113
|
-
local params = {}
|
|
114
|
-
local metadataValues = {
|
|
115
|
-
id = profile_id,
|
|
116
|
-
username = msg.Tags.UserName or decode_check and data.UserName or nil,
|
|
117
|
-
profile_image = msg.Tags.ProfileImage or decode_check and data.ProfileImage or nil,
|
|
118
|
-
cover_image = msg.Tags.CoverImage or decode_check and data.CoverImage or nil,
|
|
119
|
-
description = msg.Tags.Description or decode_check and data.Description or nil,
|
|
120
|
-
display_name = msg.Tags.DisplayName or decode_check and data.DisplayName or nil,
|
|
121
|
-
date_updated = msg.Timestamp,
|
|
122
|
-
date_created = not is_update and msg.Timestamp or nil
|
|
123
|
-
}
|
|
124
|
-
local function generateInsertQuery()
|
|
125
|
-
for key, val in pairs(metadataValues) do
|
|
126
|
-
if val ~= nil then
|
|
127
|
-
-- Include the field if provided
|
|
128
|
-
table.insert(columns, key)
|
|
129
|
-
if val == "" then
|
|
130
|
-
-- If the field is an empty string, insert NULL
|
|
131
|
-
table.insert(placeholders, "NULL")
|
|
132
|
-
else
|
|
133
|
-
-- Otherwise, prepare to bind the actual value
|
|
134
|
-
table.insert(placeholders, "?")
|
|
135
|
-
table.insert(params, val)
|
|
136
|
-
end
|
|
137
|
-
else
|
|
138
|
-
-- If field is nil and not mandatory, insert NULL
|
|
139
|
-
if key ~= "id" then
|
|
140
|
-
table.insert(columns, key)
|
|
141
|
-
table.insert(placeholders, "NULL")
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
local sql = "INSERT INTO ao_profile_metadata (" .. table.concat(columns, ", ") .. ")"
|
|
147
|
-
sql = sql .. " VALUES (" .. table.concat(placeholders, ", ") .. ")"
|
|
148
|
-
|
|
149
|
-
return sql
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
local function generateUpdateQuery()
|
|
153
|
-
-- first create setclauses for everything but id
|
|
154
|
-
for key, val in pairs(metadataValues) do
|
|
155
|
-
if val ~= nil and val ~= 'id' then
|
|
156
|
-
-- Include the field if provided
|
|
157
|
-
table.insert(columns, key)
|
|
158
|
-
if val == "" then
|
|
159
|
-
-- If the field is an empty string, insert NULL
|
|
160
|
-
table.insert(placeholders, "NULL")
|
|
161
|
-
else
|
|
162
|
-
-- Otherwise, prepare to bind the actual value
|
|
163
|
-
table.insert(placeholders, "?")
|
|
164
|
-
table.insert(params, val)
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
-- now build querystring
|
|
169
|
-
local sql = "UPDATE ao_profile_metadata SET "
|
|
170
|
-
for i, _ in ipairs(columns) do
|
|
171
|
-
sql = sql .. columns[i] .. " = " .. placeholders[i]
|
|
172
|
-
if i ~= #columns then
|
|
173
|
-
sql = sql .. ","
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
sql = sql .. " WHERE id = ?"
|
|
177
|
-
return sql
|
|
178
|
-
end
|
|
179
|
-
-- A spawn create will have data including UserName
|
|
180
|
-
-- A legacy create will only
|
|
181
|
-
-- new api: profile assigns the spawn tx to the registry, which contains the data
|
|
182
|
-
-- legacy api: profile send()s new message to registry with the data and authorized_address (user_id) of admin
|
|
183
|
-
if is_update or (not is_update and (msg.Tags.UserName or decode_check and data.UserName)) then
|
|
184
|
-
local sql = not is_update and generateInsertQuery() or generateUpdateQuery()
|
|
185
|
-
local stmt = Db:prepare(sql)
|
|
186
|
-
|
|
187
|
-
if not stmt then
|
|
188
|
-
ao.send({
|
|
189
|
-
Target = reply_to,
|
|
190
|
-
Action = 'DB_CODE',
|
|
191
|
-
Tags = {
|
|
192
|
-
Status = 'DB_PREPARE_FAILED',
|
|
193
|
-
Message = "DB PREPARED QUERY FAILED"
|
|
194
|
-
},
|
|
195
|
-
Data = { Code = "Failed to prepare insert statement",
|
|
196
|
-
SQL = sql,
|
|
197
|
-
ERROR = Db:errmsg()
|
|
198
|
-
}
|
|
199
|
-
})
|
|
200
|
-
print("Failed to prepare insert statement")
|
|
201
|
-
return json.encode({ Code = 'DB_PREPARE_FAILED' })
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
if not is_update then
|
|
205
|
-
-- bind values for INSERT statement
|
|
206
|
-
stmt:bind_values(table.unpack(params))
|
|
207
|
-
else
|
|
208
|
-
-- bind values for UPDATE statement (id is last)
|
|
209
|
-
table.insert(params, profile_id)
|
|
210
|
-
stmt:bind_values(table.unpack(params))
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
local step_status = stmt:step()
|
|
214
|
-
if step_status ~= sqlite3.OK and step_status ~= sqlite3.DONE and step_status ~= sqlite3.ROW then
|
|
215
|
-
stmt:finalize()
|
|
216
|
-
print("Error: " .. Db:errmsg())
|
|
217
|
-
print("SQL" .. sql)
|
|
218
|
-
ao.send({
|
|
219
|
-
Target = reply_to,
|
|
220
|
-
Action = 'DB_STEP_CODE',
|
|
221
|
-
Tags = {
|
|
222
|
-
Status = 'ERROR',
|
|
223
|
-
Message = 'sqlite step error'
|
|
224
|
-
},
|
|
225
|
-
Data = { DB_STEP_MSG = step_status, IS_UPDATE = tostring(is_update) }
|
|
226
|
-
})
|
|
227
|
-
return json.encode({ Code = step_status })
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
ao.send({
|
|
232
|
-
Target = reply_to,
|
|
233
|
-
Action = 'Success',
|
|
234
|
-
Tags = {
|
|
235
|
-
Status = 'Success',
|
|
236
|
-
Message = is_update and 'Record Updated' or 'Record Inserted'
|
|
237
|
-
},
|
|
238
|
-
Data = json.encode(metadataValues)
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
-- Handlers.add('migrate-database', ... , Db:exec [[ ALTER TABLE _ ADD new_field type ]]
|
|
245
|
-
|
|
246
|
-
Handlers.add('Prepare-Database', Handlers.utils.hasMatchingTag('Action', 'Prepare-Database'),
|
|
247
|
-
function(msg)
|
|
248
|
-
if msg.From ~= Owner and msg.From ~= ao.id then
|
|
249
|
-
ao.send({
|
|
250
|
-
Target = msg.From,
|
|
251
|
-
Action = 'Authorization-Error',
|
|
252
|
-
Tags = {
|
|
253
|
-
Status = 'Error',
|
|
254
|
-
Message = 'Unauthorized to access this handler'
|
|
255
|
-
}
|
|
256
|
-
})
|
|
257
|
-
return
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
--todo create tables for: languages, following, followed, topic-tags, locations, external_links, external_wallets
|
|
261
|
-
|
|
262
|
-
Db:exec [[
|
|
263
|
-
CREATE TABLE IF NOT EXISTS ao_profile_metadata (
|
|
264
|
-
id TEXT PRIMARY KEY NOT NULL,
|
|
265
|
-
username TEXT,
|
|
266
|
-
display_name TEXT,
|
|
267
|
-
description TEXT,
|
|
268
|
-
profile_image TEXT,
|
|
269
|
-
cover_image TEXT,
|
|
270
|
-
date_created INTEGER NOT NULL,
|
|
271
|
-
date_updated INTEGER NOT NULL
|
|
272
|
-
);
|
|
273
|
-
]]
|
|
274
|
-
|
|
275
|
-
Db:exec [[
|
|
276
|
-
CREATE TABLE IF NOT EXISTS ao_profile_authorization (
|
|
277
|
-
profile_id TEXT NOT NULL,
|
|
278
|
-
delegate_address TEXT NOT NULL,
|
|
279
|
-
role TEXT NOT NULL,
|
|
280
|
-
PRIMARY KEY (profile_id, delegate_address),
|
|
281
|
-
FOREIGN KEY (profile_id) REFERENCES ao_profile_metadata (id) ON DELETE CASCADE
|
|
282
|
-
);
|
|
283
|
-
]]
|
|
284
|
-
|
|
285
|
-
ao.send({
|
|
286
|
-
Target = Owner,
|
|
287
|
-
Action = 'DB-Init-Success',
|
|
288
|
-
Tags = {
|
|
289
|
-
Status = 'Success',
|
|
290
|
-
Message = 'Created DB'
|
|
291
|
-
}
|
|
292
|
-
})
|
|
293
|
-
end)
|
|
294
|
-
|
|
295
|
-
-- Data - { ProfileIds [] }
|
|
296
|
-
Handlers.add('Get-Metadata-By-ProfileIds', Handlers.utils.hasMatchingTag('Action', 'Get-Metadata-By-ProfileIds'),
|
|
297
|
-
function(msg)
|
|
298
|
-
|
|
299
|
-
local decode_check, data = decode_message_data(msg.Data)
|
|
300
|
-
|
|
301
|
-
if decode_check and data then
|
|
302
|
-
if not data.ProfileIds then
|
|
303
|
-
ao.send({
|
|
304
|
-
Target = msg.From,
|
|
305
|
-
Action = 'Input-Error',
|
|
306
|
-
Tags = {
|
|
307
|
-
Status = 'Error',
|
|
308
|
-
Message = 'Invalid arguments, required { ProfileIds }'
|
|
309
|
-
},
|
|
310
|
-
Data = msg.Data
|
|
311
|
-
})
|
|
312
|
-
return
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
local metadata = {}
|
|
316
|
-
if #data.ProfileIds > 0 then
|
|
317
|
-
local placeholders = {}
|
|
318
|
-
|
|
319
|
-
for _, _ in ipairs(data.ProfileIds) do
|
|
320
|
-
table.insert(placeholders, "?")
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
if #placeholders > 0 then
|
|
324
|
-
local stmt = Db:prepare([[
|
|
325
|
-
SELECT *
|
|
326
|
-
FROM ao_profile_metadata
|
|
327
|
-
WHERE id IN (]] .. table.concat(placeholders, ',') .. [[)
|
|
328
|
-
]])
|
|
329
|
-
|
|
330
|
-
if not stmt then
|
|
331
|
-
ao.send({
|
|
332
|
-
Target = msg.From,
|
|
333
|
-
Action = 'DB_CODE',
|
|
334
|
-
Tags = {
|
|
335
|
-
Status = 'DB_PREPARE_FAILED',
|
|
336
|
-
Message = "DB PREPARED QUERY FAILED"
|
|
337
|
-
},
|
|
338
|
-
Data = { Code = "Failed to prepare insert statement" }
|
|
339
|
-
})
|
|
340
|
-
print("Failed to prepare insert statement")
|
|
341
|
-
return json.encode({ Code = 'DB_PREPARE_FAILED' })
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
stmt:bind_values(table.unpack(data.ProfileIds))
|
|
345
|
-
|
|
346
|
-
local foundRows = false
|
|
347
|
-
for row in stmt:nrows() do
|
|
348
|
-
foundRows = true
|
|
349
|
-
table.insert(metadata, { ProfileId = row.id,
|
|
350
|
-
Username = row.username,
|
|
351
|
-
ProfileImage = row.profile_image,
|
|
352
|
-
CoverImage = row.cover_image,
|
|
353
|
-
Description = row.description,
|
|
354
|
-
DisplayName = row.display_name
|
|
355
|
-
})
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
if not foundRows then
|
|
359
|
-
print('No rows found matching the criteria.')
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
ao.send({
|
|
363
|
-
Target = msg.From,
|
|
364
|
-
Action = 'Get-Metadata-Success',
|
|
365
|
-
Tags = {
|
|
366
|
-
Status = 'Success',
|
|
367
|
-
Message = 'Metadata retrieved',
|
|
368
|
-
},
|
|
369
|
-
Data = json.encode(metadata)
|
|
370
|
-
})
|
|
371
|
-
else
|
|
372
|
-
print('Profile ID list is empty after validation.')
|
|
373
|
-
end
|
|
374
|
-
else
|
|
375
|
-
ao.send({
|
|
376
|
-
Target = msg.From,
|
|
377
|
-
Action = 'Input-Error',
|
|
378
|
-
Tags = {
|
|
379
|
-
Status = 'Error',
|
|
380
|
-
Message = 'No ProfileIds provided or the list is empty.'
|
|
381
|
-
}
|
|
382
|
-
})
|
|
383
|
-
print('No ProfileIds provided or the list is empty.')
|
|
384
|
-
return
|
|
385
|
-
|
|
386
|
-
end
|
|
387
|
-
else
|
|
388
|
-
ao.send({
|
|
389
|
-
Target = msg.From,
|
|
390
|
-
Action = 'Input-Error',
|
|
391
|
-
Tags = {
|
|
392
|
-
Status = 'Error',
|
|
393
|
-
Message = string.format(
|
|
394
|
-
'Failed to parse data, received: %s. %s.', msg.Data,
|
|
395
|
-
'Data must be an object - { ProfileIds }')
|
|
396
|
-
}
|
|
397
|
-
})
|
|
398
|
-
end
|
|
399
|
-
end)
|
|
400
|
-
|
|
401
|
-
-- Data - { Address }
|
|
402
|
-
Handlers.add('Get-Profiles-By-Delegate', Handlers.utils.hasMatchingTag('Action', 'Get-Profiles-By-Delegate'),
|
|
403
|
-
function(msg)
|
|
404
|
-
local decode_check, data = decode_message_data(msg.Data)
|
|
405
|
-
|
|
406
|
-
if decode_check and data then
|
|
407
|
-
if not data.Address then
|
|
408
|
-
ao.send({
|
|
409
|
-
Target = msg.From,
|
|
410
|
-
Action = 'Input-Error',
|
|
411
|
-
Tags = {
|
|
412
|
-
Status = 'Error',
|
|
413
|
-
Message = 'Invalid arguments, required { Address }'
|
|
414
|
-
}
|
|
415
|
-
})
|
|
416
|
-
return
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
local associated_profiles = {}
|
|
420
|
-
|
|
421
|
-
local authorization_lookup = Db:prepare([[
|
|
422
|
-
SELECT profile_id, delegate_address, role
|
|
423
|
-
FROM ao_profile_authorization
|
|
424
|
-
WHERE delegate_address = ?
|
|
425
|
-
]])
|
|
426
|
-
|
|
427
|
-
authorization_lookup:bind_values(data.Address)
|
|
428
|
-
|
|
429
|
-
for row in authorization_lookup:nrows() do
|
|
430
|
-
table.insert(associated_profiles, {
|
|
431
|
-
ProfileId = row.profile_id,
|
|
432
|
-
CallerAddress = row.delegate_address,
|
|
433
|
-
Role = row.role
|
|
434
|
-
})
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
authorization_lookup:finalize()
|
|
438
|
-
|
|
439
|
-
if #associated_profiles > 0 then
|
|
440
|
-
ao.send({
|
|
441
|
-
Target = msg.From,
|
|
442
|
-
Action = 'Profile-Success',
|
|
443
|
-
Tags = {
|
|
444
|
-
Status = 'Success',
|
|
445
|
-
Message = 'Associated profiles fetched'
|
|
446
|
-
},
|
|
447
|
-
Data = json.encode(associated_profiles)
|
|
448
|
-
})
|
|
449
|
-
else
|
|
450
|
-
ao.send({
|
|
451
|
-
Target = msg.From,
|
|
452
|
-
Action = 'Profile-Error',
|
|
453
|
-
Tags = {
|
|
454
|
-
Status = 'Error',
|
|
455
|
-
Message = 'This wallet address is not associated with a profile'
|
|
456
|
-
}
|
|
457
|
-
})
|
|
458
|
-
end
|
|
459
|
-
else
|
|
460
|
-
ao.send({
|
|
461
|
-
Target = msg.From,
|
|
462
|
-
Action = 'Input-Error',
|
|
463
|
-
Tags = {
|
|
464
|
-
Status = 'Error',
|
|
465
|
-
Message = string.format(
|
|
466
|
-
'Failed to parse data, received: %s. %s.', msg.Data,
|
|
467
|
-
'Data must be an object - { Address }')
|
|
468
|
-
}
|
|
469
|
-
})
|
|
470
|
-
end
|
|
471
|
-
end)
|
|
472
|
-
|
|
473
|
-
-- Data - { Addresses }
|
|
474
|
-
Handlers.add('Read-Profiles', Handlers.utils.hasMatchingTag('Action', 'Read-Profiles'),
|
|
475
|
-
function(msg)
|
|
476
|
-
local json = require 'json'
|
|
477
|
-
|
|
478
|
-
local function decode_message_data(data)
|
|
479
|
-
local status, decoded_data = pcall(json.decode, data)
|
|
480
|
-
if not status or type(decoded_data) ~= 'table' then
|
|
481
|
-
return false, nil
|
|
482
|
-
end
|
|
483
|
-
return true, decoded_data
|
|
484
|
-
end
|
|
485
|
-
|
|
486
|
-
local decode_check, data = decode_message_data(msg.Data)
|
|
487
|
-
|
|
488
|
-
if decode_check and data then
|
|
489
|
-
if not data.Addresses or type(data.Addresses) ~= 'table' then
|
|
490
|
-
ao.send({
|
|
491
|
-
Target = msg.From,
|
|
492
|
-
Action = 'Input-Error',
|
|
493
|
-
Tags = {
|
|
494
|
-
Status = 'Error',
|
|
495
|
-
Message = 'Invalid arguments, required { Addresses }'
|
|
496
|
-
}
|
|
497
|
-
})
|
|
498
|
-
return
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
local associated_profiles = {}
|
|
502
|
-
|
|
503
|
-
-- Create placeholders
|
|
504
|
-
local placeholders = {}
|
|
505
|
-
for i = 1, #data.Addresses do
|
|
506
|
-
table.insert(placeholders, '?')
|
|
507
|
-
end
|
|
508
|
-
local placeholders_str = table.concat(placeholders, ', ')
|
|
509
|
-
|
|
510
|
-
-- Prepare the SQL query
|
|
511
|
-
local sql_query = [[
|
|
512
|
-
SELECT profile_id, delegate_address
|
|
513
|
-
FROM ao_profile_authorization
|
|
514
|
-
WHERE delegate_address IN (]] .. placeholders_str .. [[)
|
|
515
|
-
]]
|
|
516
|
-
|
|
517
|
-
local authorization_lookup = Db:prepare(sql_query)
|
|
518
|
-
|
|
519
|
-
-- Bind values
|
|
520
|
-
for i, address in ipairs(data.Addresses) do
|
|
521
|
-
authorization_lookup:bind(i, address)
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
-- Execute query and gather results
|
|
525
|
-
for row in authorization_lookup:nrows() do
|
|
526
|
-
table.insert(associated_profiles, {
|
|
527
|
-
ProfileId = row.profile_id,
|
|
528
|
-
CallerAddress = row.delegate_address
|
|
529
|
-
})
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
authorization_lookup:finalize()
|
|
533
|
-
|
|
534
|
-
if #associated_profiles > 0 then
|
|
535
|
-
ao.send({
|
|
536
|
-
Target = msg.From,
|
|
537
|
-
Action = 'Profile-Success',
|
|
538
|
-
Tags = {
|
|
539
|
-
Status = 'Success',
|
|
540
|
-
Message = 'Associated profiles fetched'
|
|
541
|
-
},
|
|
542
|
-
Data = json.encode(associated_profiles)
|
|
543
|
-
})
|
|
544
|
-
else
|
|
545
|
-
ao.send({
|
|
546
|
-
Target = msg.From,
|
|
547
|
-
Action = 'Profile-Error',
|
|
548
|
-
Tags = {
|
|
549
|
-
Status = 'Error',
|
|
550
|
-
Message = 'No profiles associated with the provided addresses'
|
|
551
|
-
}
|
|
552
|
-
})
|
|
553
|
-
end
|
|
554
|
-
else
|
|
555
|
-
ao.send({
|
|
556
|
-
Target = msg.From,
|
|
557
|
-
Action = 'Input-Error',
|
|
558
|
-
Tags = {
|
|
559
|
-
Status = 'Error',
|
|
560
|
-
Message = string.format(
|
|
561
|
-
'Failed to parse data, received: %s. %s.', msg.Data,
|
|
562
|
-
'Data must be an object - { Addresses }')
|
|
563
|
-
}
|
|
564
|
-
})
|
|
565
|
-
end
|
|
566
|
-
end)
|
|
567
|
-
|
|
568
|
-
-- Create-Profile Handler (Original spawned profile message)
|
|
569
|
-
Handlers.add('Create-Profile', Handlers.utils.hasMatchingTag('Action', 'Create-Profile'),
|
|
570
|
-
process_profile_action)
|
|
571
|
-
|
|
572
|
-
-- Update-Profile Handler
|
|
573
|
-
Handlers.add('Update-Profile', Handlers.utils.hasMatchingTag('Action', 'Update-Profile'),
|
|
574
|
-
process_profile_action)
|
|
575
|
-
|
|
576
|
-
-- Data - { Id, Op, Role? }
|
|
577
|
-
Handlers.add('Update-Role', Handlers.utils.hasMatchingTag('Action', 'Update-Role'),
|
|
578
|
-
function(msg)
|
|
579
|
-
local decode_check, data = decode_message_data(msg.Data)
|
|
580
|
-
local profile_id = msg.Target
|
|
581
|
-
local user_id = msg.From
|
|
582
|
-
if decode_check and data then
|
|
583
|
-
if not data.Id or not data.Op then
|
|
584
|
-
ao.send({
|
|
585
|
-
Target = profile_id,
|
|
586
|
-
Action = 'Input-Error',
|
|
587
|
-
Tags = {
|
|
588
|
-
Status = 'Error',
|
|
589
|
-
Message = 'Invalid arguments, required { Id, Op, Role }'
|
|
590
|
-
}
|
|
591
|
-
})
|
|
592
|
-
return
|
|
593
|
-
end
|
|
594
|
-
end
|
|
595
|
-
|
|
596
|
-
if not is_authorized(profile_id, user_id, HandlerRoles['Update-Role']) then
|
|
597
|
-
ao.send({
|
|
598
|
-
Target = profile_id,
|
|
599
|
-
Action = 'Authorization-Error',
|
|
600
|
-
Tags = {
|
|
601
|
-
Status = 'Error',
|
|
602
|
-
Message = 'Unauthorized to access this handler'
|
|
603
|
-
}
|
|
604
|
-
})
|
|
605
|
-
return
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
local Id = data.Id or msg.Tags.Id
|
|
611
|
-
local Role = data.Role or msg.Tags.Role
|
|
612
|
-
local Op = data.Op or msg.Tags.Op
|
|
613
|
-
|
|
614
|
-
if not Id or not Op then
|
|
615
|
-
ao.send({
|
|
616
|
-
Target = profile_id,
|
|
617
|
-
Action = 'Input-Error',
|
|
618
|
-
Tags = {
|
|
619
|
-
Status = 'Error',
|
|
620
|
-
Message =
|
|
621
|
-
'Invalid arguments, required { Id, Op } in data or tags'
|
|
622
|
-
}
|
|
623
|
-
})
|
|
624
|
-
return
|
|
625
|
-
end
|
|
626
|
-
-- handle add, update, or remove Ops
|
|
627
|
-
local stmt
|
|
628
|
-
if data.Op == 'Add' then
|
|
629
|
-
stmt = Db:prepare(
|
|
630
|
-
'INSERT INTO ao_profile_authorization (profile_id, delegate_address, role) VALUES (?, ?, ?)')
|
|
631
|
-
stmt:bind_values(profile_id, Id, Role)
|
|
632
|
-
|
|
633
|
-
elseif data.Op == 'Update' then
|
|
634
|
-
stmt = Db:prepare(
|
|
635
|
-
'UPDATE ao_profile_authorization SET role = ? WHERE profile_id = ? AND delegate_address = ?')
|
|
636
|
-
stmt:bind_values(Role, profile_id, Id)
|
|
637
|
-
|
|
638
|
-
elseif data.Op == 'Delete' then
|
|
639
|
-
stmt = Db:prepare(
|
|
640
|
-
'DELETE FROM ao_profile_authorization WHERE profile_id = ? AND delegate_address = ?')
|
|
641
|
-
stmt:bind_values(profile_id, Id)
|
|
642
|
-
end
|
|
643
|
-
|
|
644
|
-
local step_status = stmt:step()
|
|
645
|
-
stmt:finalize()
|
|
646
|
-
if step_status ~= sqlite3.OK and step_status ~= sqlite3.DONE and step_status ~= sqlite3.ROW then
|
|
647
|
-
print("Error: " .. Db:errmsg())
|
|
648
|
-
ao.send({
|
|
649
|
-
Target = profile_id,
|
|
650
|
-
Action = 'DB_STEP_CODE',
|
|
651
|
-
Tags = {
|
|
652
|
-
Status = 'ERROR',
|
|
653
|
-
Message = 'sqlite step error'
|
|
654
|
-
},
|
|
655
|
-
Data = { DB_STEP_MSG = step_status }
|
|
656
|
-
})
|
|
657
|
-
return json.encode({ Code = step_status })
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
ao.send({
|
|
661
|
-
Target = profile_id,
|
|
662
|
-
Action = 'Success',
|
|
663
|
-
Tags = {
|
|
664
|
-
Status = 'Success',
|
|
665
|
-
Message = 'Auth Record Success'
|
|
666
|
-
},
|
|
667
|
-
Data = json.encode({ ProfileId = profile_id, DelegateAddress = Id, Role = Role })
|
|
668
|
-
})
|
|
669
|
-
end
|
|
670
|
-
)
|
|
671
|
-
|
|
672
|
-
Handlers.add('Count-Profiles', Handlers.utils.hasMatchingTag('Action', 'Count-Profiles'),
|
|
673
|
-
function(msg)
|
|
674
|
-
local count_sql = [[
|
|
675
|
-
SELECT COUNT(*)
|
|
676
|
-
FROM ao_profile_metadata
|
|
677
|
-
]]
|
|
678
|
-
local stmt = Db:prepare(count_sql)
|
|
679
|
-
local result = stmt:step()
|
|
680
|
-
local count = 0
|
|
681
|
-
|
|
682
|
-
if result == sqlite3.ROW then
|
|
683
|
-
count = stmt:get_value(0)
|
|
684
|
-
else
|
|
685
|
-
count = -1
|
|
686
|
-
end
|
|
687
|
-
|
|
688
|
-
ao.send({
|
|
689
|
-
Target = msg.From,
|
|
690
|
-
Action = 'Count-Profiles-Success',
|
|
691
|
-
Tags = {
|
|
692
|
-
Status = 'Success',
|
|
693
|
-
Message = 'Profiles Counted',
|
|
694
|
-
},
|
|
695
|
-
Data = json.encode({ Count = count })
|
|
696
|
-
})
|
|
697
|
-
return json.encode({ Count = count })
|
|
698
|
-
end)
|
|
699
|
-
|
|
700
|
-
Handlers.add('Read-Metadata', Handlers.utils.hasMatchingTag('Action', 'Read-Metadata'),
|
|
701
|
-
function(msg)
|
|
702
|
-
local metadata = {}
|
|
703
|
-
local status, err = pcall(function()
|
|
704
|
-
for row in Db:nrows('SELECT id, username, profile_image, cover_image, description, display_name, date_updated, date_created FROM ao_profile_metadata') do
|
|
705
|
-
table.insert(metadata, {
|
|
706
|
-
id = row.id,
|
|
707
|
-
Username = row.username,
|
|
708
|
-
ProfileImage = row.profile_image,
|
|
709
|
-
CoverImage = row.cover_image,
|
|
710
|
-
Description = row.description,
|
|
711
|
-
DisplayName = row.display_name,
|
|
712
|
-
DateCreated = row.date_created,
|
|
713
|
-
DateUpdated = row.date_updated
|
|
714
|
-
})
|
|
715
|
-
end
|
|
716
|
-
end)
|
|
717
|
-
if err or not status then
|
|
718
|
-
print("Error: ", err)
|
|
719
|
-
return
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
if foundRows == false then
|
|
723
|
-
print('No rows found matching the criteria.')
|
|
724
|
-
end
|
|
725
|
-
ao.send({
|
|
726
|
-
Target = msg.From,
|
|
727
|
-
Action = 'Read-Metadata-Success',
|
|
728
|
-
Tags = {
|
|
729
|
-
Status = 'Success',
|
|
730
|
-
Message = 'Metadata retrieved',
|
|
731
|
-
},
|
|
732
|
-
Data = json.encode(metadata)
|
|
733
|
-
})
|
|
734
|
-
|
|
735
|
-
return json.encode(metadata)
|
|
736
|
-
end)
|
|
737
|
-
|
|
738
|
-
Handlers.add('Read-Auth', Handlers.utils.hasMatchingTag('Action', 'Read-Auth'),
|
|
739
|
-
function(msg)
|
|
740
|
-
local metadata = {}
|
|
741
|
-
local string = ''
|
|
742
|
-
local foundRows = false
|
|
743
|
-
local status, err = pcall(function()
|
|
744
|
-
for row in Db:nrows('SELECT profile_id, delegate_address, role FROM ao_profile_authorization') do
|
|
745
|
-
foundRows = true
|
|
746
|
-
table.insert(metadata, {
|
|
747
|
-
ProfileId = row.profile_id,
|
|
748
|
-
CallerAddress = row.delegate_address,
|
|
749
|
-
Role = row.role,
|
|
750
|
-
})
|
|
751
|
-
string = string .. "ProfileId: " .. row.profile_id .. " CallerAddress: " .. row.delegate_address .. " Role: " .. row.role .. "\n"
|
|
752
|
-
end
|
|
753
|
-
end)
|
|
754
|
-
if not status then
|
|
755
|
-
print("Error: ", err)
|
|
756
|
-
return
|
|
757
|
-
end
|
|
758
|
-
ao.send({
|
|
759
|
-
Target = msg.From,
|
|
760
|
-
Action = 'Read-Metadata-Success',
|
|
761
|
-
Tags = {
|
|
762
|
-
Status = 'Success',
|
|
763
|
-
Message = 'Auth Data retrieved',
|
|
764
|
-
},
|
|
765
|
-
Data = json.encode(metadata)
|
|
766
|
-
})
|
|
767
|
-
return json.encode(metadata)
|
|
768
|
-
end)
|
|
769
|
-
|
|
770
|
-
Handlers.add('Read-Profile', Handlers.utils.hasMatchingTag('Action', 'Read-Profile'),
|
|
771
|
-
function(msg)
|
|
772
|
-
local decode_check, data = decode_message_data(msg.Data)
|
|
773
|
-
|
|
774
|
-
if decode_check ~= true then
|
|
775
|
-
ao.send({
|
|
776
|
-
Target = msg.From,
|
|
777
|
-
Action = 'DB_CODE',
|
|
778
|
-
Tags = {
|
|
779
|
-
Status = 'DECODE_FAILED',
|
|
780
|
-
Message = "Failed to decode data"
|
|
781
|
-
},
|
|
782
|
-
Data = { Code = "DECODE_FAILED" }
|
|
783
|
-
})
|
|
784
|
-
return
|
|
785
|
-
end
|
|
786
|
-
|
|
787
|
-
local selectsql = [[
|
|
788
|
-
SELECT *
|
|
789
|
-
FROM ao_profile_metadata
|
|
790
|
-
WHERE id = ?
|
|
791
|
-
]]
|
|
792
|
-
|
|
793
|
-
local row
|
|
794
|
-
local select_stmt = Db:prepare(selectsql)
|
|
795
|
-
local bind = -1
|
|
796
|
-
if select_stmt then
|
|
797
|
-
bind = select_stmt:bind_values(data.ProfileId)
|
|
798
|
-
else
|
|
799
|
-
ao.send({
|
|
800
|
-
Target = msg.From,
|
|
801
|
-
Action = 'DB_CODE',
|
|
802
|
-
Tags = {
|
|
803
|
-
Status = 'DB_PREPARE_FAILED',
|
|
804
|
-
Message = "DB PREPARED QUERY FAILED"
|
|
805
|
-
},
|
|
806
|
-
Data = { Code = "Failed to prepare select statement" }
|
|
807
|
-
})
|
|
808
|
-
print("Failed to prepare select statement")
|
|
809
|
-
return json.encode({ Code = 'DB_PREPARE_FAILED' })
|
|
810
|
-
end
|
|
811
|
-
|
|
812
|
-
local step_status = select_stmt:step()
|
|
813
|
-
if step_status ~= sqlite3.OK and step_status ~= sqlite3.DONE and step_status ~= sqlite3.ROW then
|
|
814
|
-
ao.send({
|
|
815
|
-
Target = msg.From,
|
|
816
|
-
Action = 'DB_STEP_CODE',
|
|
817
|
-
Tags = {
|
|
818
|
-
Status = 'ERROR',
|
|
819
|
-
Message = 'sqlite step error'
|
|
820
|
-
},
|
|
821
|
-
Data = { DB_STEP_MSG = step_status }
|
|
822
|
-
})
|
|
823
|
-
return json.encode({ Code = step_status })
|
|
824
|
-
end
|
|
825
|
-
|
|
826
|
-
if step_status == sqlite3.DONE then
|
|
827
|
-
ao.send({
|
|
828
|
-
Target = msg.From,
|
|
829
|
-
Action = 'Read-Profile-Error',
|
|
830
|
-
Tags = {
|
|
831
|
-
Status = 'Error',
|
|
832
|
-
Message = 'Profile not found'
|
|
833
|
-
}
|
|
834
|
-
})
|
|
835
|
-
return
|
|
836
|
-
end
|
|
837
|
-
|
|
838
|
-
row = select_stmt:get_named_values()
|
|
839
|
-
local metadata = {
|
|
840
|
-
ProfileId = row.id,
|
|
841
|
-
Username = row.username,
|
|
842
|
-
ProfileImage = row.profile_image,
|
|
843
|
-
CoverImage = row.cover_image,
|
|
844
|
-
Description = row.description,
|
|
845
|
-
DisplayName = row.display_name,
|
|
846
|
-
DateCreated = row.date_created,
|
|
847
|
-
DateUpdated = row.date_updated
|
|
848
|
-
}
|
|
849
|
-
ao.send({
|
|
850
|
-
Target = msg.From,
|
|
851
|
-
Action = 'Success',
|
|
852
|
-
Tags = {
|
|
853
|
-
Status = 'Success',
|
|
854
|
-
Message = 'Read success'
|
|
855
|
-
},
|
|
856
|
-
Data = json.encode(metadata)
|
|
857
|
-
})
|
|
858
|
-
end)
|