Skip to content

Commit

Permalink
Add fields to capture registration options for users.
Browse files Browse the repository at this point in the history
  • Loading branch information
GUI committed Dec 2, 2023
1 parent 411c79a commit 6c23a71
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 1 deletion.
5 changes: 4 additions & 1 deletion db/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,9 @@ CREATE TABLE api_umbrella.api_users (
registration_recaptcha_v3_action character varying(255),
registration_recaptcha_v3_error_codes character varying(50)[],
registration_recaptcha_v2_hostname character varying(255),
registration_recaptcha_v3_hostname character varying(255)
registration_recaptcha_v3_hostname character varying(255),
registration_options jsonb,
registration_input_options jsonb
);


Expand Down Expand Up @@ -2821,3 +2823,4 @@ INSERT INTO api_umbrella.lapis_migrations (name) VALUES ('1699559696');
INSERT INTO api_umbrella.lapis_migrations (name) VALUES ('1699650325');
INSERT INTO api_umbrella.lapis_migrations (name) VALUES ('1700281762');
INSERT INTO api_umbrella.lapis_migrations (name) VALUES ('1700346585');
INSERT INTO api_umbrella.lapis_migrations (name) VALUES ('1701483732');
6 changes: 6 additions & 0 deletions src/api-umbrella/web-app/actions/v1/users.lua
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ function _M.create(self)
user_params["registration_source"] = "api"
end
user_params["registration_key_creator_api_user_id"] = request_headers["x-api-user-id"]
if not is_empty(options) then
user_params["registration_options"] = options
end
if not is_empty(self.params["options"]) then
user_params["registration_input_options"] = self.params["options"]
end

-- If email verification is enabled, then create the record and mark its
-- email_verified field as true. Since the API key won't be part of the API
Expand Down
25 changes: 25 additions & 0 deletions src/api-umbrella/web-app/models/api_user.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local hmac = require "api-umbrella.utils.hmac"
local is_array = require "api-umbrella.utils.is_array"
local is_hash = require "api-umbrella.utils.is_hash"
local json_array_fields = require "api-umbrella.web-app.utils.json_array_fields"
local json_encode = require "api-umbrella.utils.json_encode"
local json_null_default = require "api-umbrella.web-app.utils.json_null_default"
local lyaml = require "lyaml"
local model_ext = require "api-umbrella.web-app.utils.model_ext"
Expand Down Expand Up @@ -381,6 +382,22 @@ ApiUser = model_ext.new_class("api_users", {
model_ext.add_error(errors, "metadata_yaml_string", t("Metadata"), data["_metadata_yaml_string_parse_error"])
end

if data["registration_options"] and not is_hash(data["registration_options"]) and data["registration_options"] ~= db_null then
model_ext.add_error(errors, "registration_options", t("Registration options"), t("unexpected type (must be a hash)"))
end

if data["registration_options"] and is_hash(data["registration_options"]) and data["registration_options"] ~= db_null and string.len(json_encode(data["registration_options"])) > 4000 then
model_ext.add_error(errors, "registration_options", t("Registration options"), t("is too long"))
end

if data["registration_input_options"] and not is_hash(data["registration_input_options"]) and data["registration_input_options"] ~= db_null then
model_ext.add_error(errors, "registration_input_options", t("Registration input options"), t("unexpected type (must be a hash)"))
end

if data["registration_input_options"] and is_hash(data["registration_input_options"]) and data["registration_input_options"] ~= db_null and string.len(json_encode(data["registration_input_options"])) > 4000 then
model_ext.add_error(errors, "registration_input_options", t("Registration input options"), t("is too long"))
end

return errors
end,

Expand All @@ -396,6 +413,14 @@ ApiUser = model_ext.new_class("api_users", {
if is_array(values["registration_recaptcha_v3_error_codes"]) and values["registration_recaptcha_v3_error_codes"] ~= db_null then
values["registration_recaptcha_v3_error_codes"] = db_raw(pg_encode_array(values["registration_recaptcha_v3_error_codes"]))
end

if is_hash(values["registration_options"]) and values["registration_options"] ~= db_null then
values["registration_options"] = db_raw(pg_encode_json(values["registration_options"]))
end

if is_hash(values["registration_input_options"]) and values["registration_input_options"] ~= db_null then
values["registration_input_options"] = db_raw(pg_encode_json(values["registration_input_options"]))
end
end,

after_save = function(self, values)
Expand Down
9 changes: 9 additions & 0 deletions src/migrations.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1495,4 +1495,13 @@ return {
db.query("COMMIT")
end,

[1701483732] = function()
db.query("BEGIN")

db.query("ALTER TABLE api_users ADD COLUMN registration_options jsonb")
db.query("ALTER TABLE api_users ADD COLUMN registration_input_options jsonb")

db.query(grants_sql)
db.query("COMMIT")
end,
}
123 changes: 123 additions & 0 deletions test/apis/v1/users/test_create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,129 @@ def test_accepts_empty_origin_for_admins
assert_response_code(201, response)
end

def test_registration_options_not_set
response = Typhoeus.post("https://127.0.0.1:9081/api-umbrella/v1/users.json", http_options.deep_merge(non_admin_key_creator_api_key).deep_merge({
:headers => { "Content-Type" => "application/json" },
:body => MultiJson.dump({
:user => FactoryBot.attributes_for(:api_user),
}),
}))
assert_response_code(201, response)

data = MultiJson.load(response.body)
user = ApiUser.find(data["user"]["id"])
assert_equal({
"contact_url" => "https://localhost/contact/",
"site_name" => "API Umbrella",
}, user.registration_options)
assert_nil(user.registration_input_options)
end

def test_registration_options_empty
response = Typhoeus.post("https://127.0.0.1:9081/api-umbrella/v1/users.json", http_options.deep_merge(non_admin_key_creator_api_key).deep_merge({
:headers => { "Content-Type" => "application/json" },
:body => MultiJson.dump({
:user => FactoryBot.attributes_for(:api_user),
:options => {},
}),
}))
assert_response_code(201, response)

data = MultiJson.load(response.body)
user = ApiUser.find(data["user"]["id"])
assert_equal({
"contact_url" => "https://localhost/contact/",
"site_name" => "API Umbrella",
}, user.registration_options)
assert_nil(user.registration_input_options)
end

def test_registration_options_set
response = Typhoeus.post("https://127.0.0.1:9081/api-umbrella/v1/users.json", http_options.deep_merge(non_admin_key_creator_api_key).deep_merge({
:headers => { "Content-Type" => "application/json" },
:body => MultiJson.dump({
:user => FactoryBot.attributes_for(:api_user),
:options => {
:foo => "bar",
:send_welcome_email => true,
:contact_url => "example@#{unique_test_hostname}",
:email_from_address => "example@127.0.0.1",
},
}),
}))
assert_response_code(201, response)

data = MultiJson.load(response.body)
user = ApiUser.find(data["user"]["id"])
assert_equal({
"foo" => "bar",
"send_welcome_email" => true,
"contact_url" => "https://localhost/contact/",
"email_from_address" => "example@127.0.0.1",
"site_name" => "API Umbrella",
}, user.registration_options)
assert_equal({
"foo" => "bar",
"send_welcome_email" => true,
"contact_url" => "example@#{unique_test_hostname}",
"email_from_address" => "example@127.0.0.1",
}, user.registration_input_options)
end

def test_registration_options_below_length_limit
response = Typhoeus.post("https://127.0.0.1:9081/api-umbrella/v1/users.json", http_options.deep_merge(non_admin_key_creator_api_key).deep_merge({
:headers => { "Content-Type" => "application/json" },
:body => MultiJson.dump({
:user => FactoryBot.attributes_for(:api_user),
:options => {
:foo => "a" * 3900,
},
}),
}))
assert_response_code(201, response)

data = MultiJson.load(response.body)
user = ApiUser.find(data["user"]["id"])
assert_equal({
"foo" => "a" * 3900,
"contact_url" => "https://localhost/contact/",
"site_name" => "API Umbrella",
}, user.registration_options)
assert_equal({
"foo" => "a" * 3900,
}, user.registration_input_options)
end

def test_registration_options_too_long
response = Typhoeus.post("https://127.0.0.1:9081/api-umbrella/v1/users.json", http_options.deep_merge(non_admin_key_creator_api_key).deep_merge({
:headers => { "Content-Type" => "application/json" },
:body => MultiJson.dump({
:user => FactoryBot.attributes_for(:api_user),
:options => {
:foo => "a" * 4000,
},
}),
}))
assert_response_code(422, response)
data = MultiJson.load(response.body)
assert_equal({
"errors" => [
{
"code" => "INVALID_INPUT",
"field" => "registration_options",
"message" => "is too long",
"full_message" => "Registration options: is too long",
},
{
"code" => "INVALID_INPUT",
"field" => "registration_input_options",
"message" => "is too long",
"full_message" => "Registration input options: is too long",
},
],
}, data)
end

private

def non_admin_key_creator_api_key
Expand Down

0 comments on commit 6c23a71

Please sign in to comment.