comparison mod_http_admin_api/mod_http_admin_api.lua @ 6329:5571c75a4fed

mod_http_admin_api: Unify error reporting around util.error
author Matthew Wild <mwild1@gmail.com>
date Wed, 01 Oct 2025 11:25:57 +0100
parents 4b52d579bc70
children 4e63151010bf
comparison
equal deleted inserted replaced
6328:187b957dc528 6329:5571c75a4fed
30 local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; 30 local xmlns_pubsub = "http://jabber.org/protocol/pubsub";
31 local xmlns_nick = "http://jabber.org/protocol/nick"; 31 local xmlns_nick = "http://jabber.org/protocol/nick";
32 32
33 local deleted_users = module:open_store("accounts_cleanup"); 33 local deleted_users = module:open_store("accounts_cleanup");
34 34
35 local errors = require "util.error".init(module.name, "https://prosody.im/protocol/errors", {
36 ["feature-not-implemented"] = { "cancel", "feature-not-implemented", "Feature not implemented" };
37 ["unknown-invite-type"] = { "cancel", "bad-request", "Unknown invitation type" };
38 ["invite-creation-failed"] = { "cancel", "internal-server-error", "Failed to create invitation" };
39 ["invalid-json"] = { "modify", "bad-request", "Invalid JSON submitted" };
40 ["user-not-found"] = { "cancel", "item-not-found", "User not found", "user-not-found" };
41
42 -- From mod_groups_internal
43 ["group-name-required"] = { "modify", "bad-request", "Group name required", "group-name-required" };
44 ["group-not-found"] = { "cancel", "item-not-found", "Group not found", "group-not-found" };
45
46 -- Generic
47 ["conflict"] = { "cancel", "conflict", "Resource already exists" };
48 ["internal-server-error"] = { "wait", "internal-server-error", "Internal server error" };
49 ["service-unavailable"] = { "cancel", "service-unavailable", "Unable to perform the requested action" };
50 ["bad-request"] = { "cancel", "bad-request", "Invalid request" };
51 });
52
35 local function check_credentials(request) 53 local function check_credentials(request)
36 local auth_type, auth_data = string.match(request.headers.authorization or "", "^(%S+)%s(.+)$"); 54 local auth_type, auth_data = string.match(request.headers.authorization or "", "^(%S+)%s(.+)$");
37 if not (auth_type and auth_data) then 55 if not (auth_type and auth_data) then
38 return false; 56 return false;
39 end 57 end
67 routes[route] = function (event, ...) 85 routes[route] = function (event, ...)
68 local permit, code = check_request_auth(event); 86 local permit, code = check_request_auth(event);
69 if not permit then 87 if not permit then
70 return code; 88 return code;
71 end 89 end
72 return handler(event, ...); 90 return errors.coerce(handler(event, ...));
73 end; 91 end;
74 end 92 end
75 return routes; 93 return routes;
76 end 94 end
77 95
164 groups = options.groups; 182 groups = options.groups;
165 roles = options.roles; 183 roles = options.roles;
166 note = options.note; 184 note = options.note;
167 }, options.ttl); 185 }, options.ttl);
168 else 186 else
169 return 400; 187 return nil, "unknown-invite-type";
170 end 188 end
171 if not invite then 189 if not invite then
172 return 500; 190 return nil, "invite-creation-failed";
173 end 191 end
174 event.response.headers["Content-Type"] = json_content_type; 192 event.response.headers["Content-Type"] = json_content_type;
175 return json.encode(token_info_to_invite_info(invite)); 193 return json.encode(token_info_to_invite_info(invite));
176 end 194 end
177 195
453 471
454 function patch_user(event, username) 472 function patch_user(event, username)
455 if not username then return; end 473 if not username then return; end
456 474
457 local current_user = get_user_info(username); 475 local current_user = get_user_info(username);
458 if not current_user then return 404; end 476 if not current_user then return nil, "user-not-found"; end
459 477
460 local request = event.request; 478 local request = event.request;
461 if request.headers.content_type ~= json_content_type 479 if request.headers.content_type ~= json_content_type
462 or (not request.body or #request.body == 0) then 480 or (not request.body or #request.body == 0) then
463 return 400; 481 return nil, "invalid-json";
464 end 482 end
465 local new_user = json.decode(event.request.body); 483 local new_user = json.decode(event.request.body);
466 if not new_user then 484 if not new_user then
467 return 400; 485 return nil, "invalid-json";
468 end 486 end
469 487
470 local updated_attributes = set.new(array.collect(it.keys(new_user))); 488 local updated_attributes = set.new(array.collect(it.keys(new_user)));
471 if not (updated_attributes - writable_user_attributes):empty() then 489 if not (updated_attributes - writable_user_attributes):empty() then
472 module:log("warn", "Unable to service PATCH user request, unsupported attributes: %s", (updated_attributes - writable_user_attributes)); 490 module:log("warn", "Unable to service PATCH user request, unsupported attributes: %s", (updated_attributes - writable_user_attributes));
473 return 400; 491 return 400;
474 end 492 end
475 493
476 if new_user.enabled ~= nil and new_user.enabled ~= current_user.enabled then 494 if new_user.enabled ~= nil and new_user.enabled ~= current_user.enabled then
477 if not user_attribute_writers.enabled(username, new_user.enabled) then 495 local ok, err = user_attribute_writers.enabled(username, new_user.enabled);
478 return 500; 496 if not ok then
497 return nil, err;
479 end 498 end
480 end 499 end
481 500
482 return 200; 501 return 200;
483 end 502 end
512 }); 531 });
513 end 532 end
514 533
515 if new_user.role then 534 if new_user.role then
516 if not usermanager.set_user_role then 535 if not usermanager.set_user_role then
517 return 500, "feature-not-implemented"; 536 return nil, "feature-not-implemented";
518 end 537 end
519 if not usermanager.set_user_role(username, module.host, new_user.role) then 538 local role, role_err = usermanager.set_user_role(username, module.host, new_user.role);
520 module:log("error", "failed to set role %s for %s", new_user.role, username); 539 if not role then
521 return 500; 540 module:log("error", "failed to set role %s for %s: ", new_user.role, username, role_err);
541 return nil, role_err;
522 end 542 end
523 end 543 end
524 544
525 if new_user.roles then -- COMPAT w/0.12 545 if new_user.roles then -- COMPAT w/0.12
526 if not usermanager.set_user_roles then 546 if not usermanager.set_user_roles then
527 return 500, "feature-not-implemented" 547 return nil, "feature-not-implemented";
528 end 548 end
529 549
530 local backend_roles = {}; 550 local backend_roles = {};
531 for _, role in ipairs(new_user.roles) do 551 for _, role in ipairs(new_user.roles) do
532 backend_roles[role] = true; 552 backend_roles[role] = true;
533 end 553 end
534 local user_jid = username.."@"..module.host; 554 local user_jid = username.."@"..module.host;
535 if not usermanager.set_user_roles(username, module.host, backend_roles) then 555 local role, role_err = usermanager.set_user_roles(username, module.host, backend_roles);
536 module:log("error", "failed to set roles %q for %s", backend_roles, user_jid) 556 if not role then
537 return 500 557 module:log("error", "failed to set roles %q for %s: %s", backend_roles, user_jid, role_err)
558 return nil, role_err;
538 end 559 end
539 end 560 end
540 561
541 if new_user.enabled ~= nil then 562 if new_user.enabled ~= nil then
542 if not user_attribute_writers.enabled(username, new_user.enabled) then 563 local ok, err = user_attribute_writers.enabled(username, new_user.enabled);
543 return 500; 564 if not ok then
565 return nil, err;
544 end 566 end
545 end 567 end
546 568
547 return 200; 569 return 200;
548 end 570 end
549 571
550 function delete_user(event, username) --luacheck: ignore 212/event 572 function delete_user(event, username) --luacheck: ignore 212/event
551 if not usermanager.delete_user(username, module.host) then 573 local ok, err = usermanager.delete_user(username, module.host);
552 return 404; 574 if not ok then
575 return nil, err;
553 end 576 end
554 return 200; 577 return 200;
555 end 578 end
556 579
557 function list_groups(event) 580 function list_groups(event)
595 local group = json.decode(event.request.body); 618 local group = json.decode(event.request.body);
596 if not group then 619 if not group then
597 return 400; 620 return 400;
598 end 621 end
599 622
600 if not group.name then
601 module:log("warn", "Group missing name property");
602 return 400;
603 end
604
605 local create_muc = group.create_muc and true or false; 623 local create_muc = group.create_muc and true or false;
606 624
607 local group_id = mod_groups.create( 625 local group_id, err = mod_groups.create(
608 { 626 {
609 name = group.name; 627 name = group.name;
610 }, 628 },
611 create_muc 629 create_muc
612 ); 630 );
613 if not group_id then 631 if not group_id then
614 return 500; 632 return nil, err;
615 end 633 end
616 634
617 event.response.headers["Content-Type"] = json_content_type; 635 event.response.headers["Content-Type"] = json_content_type;
618 636
619 local info = mod_groups.get_info(group_id); 637 local info = mod_groups.get_info(group_id);
628 function update_group(event, group) --luacheck: ignore 212/event 646 function update_group(event, group) --luacheck: ignore 212/event
629 -- Add member 647 -- Add member
630 do 648 do
631 local group_id, member_name = group:match("^([^/]+)/members/([^/]+)$"); 649 local group_id, member_name = group:match("^([^/]+)/members/([^/]+)$");
632 if group_id and member_name then 650 if group_id and member_name then
633 if not mod_groups.add_member(group_id, member_name) then 651 local ok, err = mod_groups.add_member(group_id, member_name);
634 return 500; 652 if not ok then
653 return nil, err;
635 end 654 end
636 return 204; 655 return 204;
637 end 656 end
638 end 657 end
639 658
640 local group_id = group:match("^([^/]+)$") 659 local group_id = group:match("^([^/]+)$")
641 if not group_id then return 404; end 660 if not group_id then return nil, "group-not-found"; end
642 661
643 local request = event.request; 662 local request = event.request;
644 if request.headers.content_type ~= json_content_type or (not request.body or #request.body == 0) then 663 if request.headers.content_type ~= json_content_type or (not request.body or #request.body == 0) then
645 return 400; 664 return nil, "invalid-json";
646 end 665 end
647 666
648 local update = json.decode(event.request.body); 667 local update = json.decode(event.request.body);
649 if not update then 668 if not update then
650 return 400; 669 return nil, "invalid-json";
651 end 670 end
652 671
653 local group_info = mod_groups.get_info(group_id); 672 local group_info = mod_groups.get_info(group_id);
654 if not group_info then 673 if not group_info then
655 return 404; 674 return nil, "group-not-found";
656 end 675 end
657 676
658 if update.name then 677 if update.name then
659 group_info["name"] = update.name; 678 group_info["name"] = update.name;
660 end 679 end
661 if not mod_groups.set_info(group_id, group_info) then 680 local ok, err = mod_groups.set_info(group_id, group_info);
662 return 500; 681 if not ok then
682 return nil, err;
663 end 683 end
664 return 204; 684 return 204;
665 end 685 end
666 686
667 function extend_group(event, subpath) 687 function extend_group(event, subpath)