From f0fac55c2b9b1da44f2d2c7b6854f61415a63c28 Mon Sep 17 00:00:00 2001 From: Felix Krause Date: Fri, 6 Jul 2018 11:24:03 -0400 Subject: [PATCH 1/3] Add new API endpoint to register user --- app/features-json/repos_json_controller.rb | 2 +- app/features-json/user_json_controller.rb | 58 +++++++++++++++++++ .../models/github_provider_credential.rb | 1 + launch.rb | 2 + spec/features-json/user_json_spec.rb | 35 +++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 app/features-json/user_json_controller.rb create mode 100644 spec/features-json/user_json_spec.rb diff --git a/app/features-json/repos_json_controller.rb b/app/features-json/repos_json_controller.rb index c5a326ff..2a8ce704 100644 --- a/app/features-json/repos_json_controller.rb +++ b/app/features-json/repos_json_controller.rb @@ -24,7 +24,7 @@ class RepositoryJSONController < APIController github_client = Octokit::Client.new(access_token: params[:token]) begin - # Note: This fails if the user.email scope is missing from token + # Note: This fails if the user.email scope is missing from token email = github_client.emails.find(&:primary).email rescue Octokit::NotFound json_error!( diff --git a/app/features-json/user_json_controller.rb b/app/features-json/user_json_controller.rb new file mode 100644 index 00000000..05ada61f --- /dev/null +++ b/app/features-json/user_json_controller.rb @@ -0,0 +1,58 @@ +require_relative "../services/user_service" +require_relative "api_controller" +require_relative "json_params" + +module FastlaneCI + # Controller responsible for handling users + class UserJSONController < APIController + disable(:authentication) + + HOME = "/api/user" + + post HOME.to_s do + email = params[:email] + + if email.nil? + # User didn't provide a custom email address + # fetch it based on the API token instead + github_client = Octokit::Client.new(access_token: params[:github_token]) + + begin + # Note: This fails if the user.email scope is missing from token + email = github_client.emails.find(&:primary).email + rescue Octokit::NotFound + json_error!( + error_message: "Provided API token needs user email scope", + error_key: "User.Token.MissingEmailScope", + error_code: 400 + ) + rescue Octokit::Unauthorized + json_error!( + error_message: "Provided API token is invalid", + error_key: "User.Token.Invalid", + error_code: 403 + ) + end + end + + user = Services.user_service.create_user!( + email: email, + password: params[:password] + ) + + if user + Services.user_service.create_provider_credential!( + user_id: user.id, + email: user.email, + api_token: params[:github_token] + ) + return json({ status: :success }) + else + json_error!( + error_message: "Error creating new user", + error_key: "User.Error" + ) + end + end + end +end diff --git a/app/shared/models/github_provider_credential.rb b/app/shared/models/github_provider_credential.rb index bcbc894c..c0b0c1f5 100644 --- a/app/shared/models/github_provider_credential.rb +++ b/app/shared/models/github_provider_credential.rb @@ -18,6 +18,7 @@ class GitHubProviderCredential < ProviderCredential # @return [String] attr_reader :provider_name + # TODO: Document what this value is used for # @return [String] attr_reader :full_name diff --git a/launch.rb b/launch.rb index 6a9295f7..cb946c1e 100644 --- a/launch.rb +++ b/launch.rb @@ -149,6 +149,7 @@ def self.register_available_controllers require_relative "app/features-json/project_json_controller" require_relative "app/features-json/repos_json_controller" require_relative "app/features-json/login_json_controller" + require_relative "app/features-json/user_json_controller" require_relative "app/features-json/build_json_controller" require_relative "app/features-json/artifact_json_controller" require_relative "app/features-json/setup_json_controller" @@ -161,6 +162,7 @@ def self.register_available_controllers FastlaneCI::FastlaneApp.use(FastlaneCI::ArtifactJSONController) FastlaneCI::FastlaneApp.use(FastlaneCI::SetupJSONController) FastlaneCI::FastlaneApp.use(FastlaneCI::SettingJSONController) + FastlaneCI::FastlaneApp.use(FastlaneCI::UserJSONController) end def self.start_github_workers diff --git a/spec/features-json/user_json_spec.rb b/spec/features-json/user_json_spec.rb new file mode 100644 index 00000000..f3b647e8 --- /dev/null +++ b/spec/features-json/user_json_spec.rb @@ -0,0 +1,35 @@ +require "spec_helper" +require "app/features-json/user_json_controller" +require "app/services/user_service" + +describe FastlaneCI::UserJSONController do + def app + described_class + end + let(:json) { JSON.parse(last_response.body) } + + before do + allow(FastlaneCI.dot_keys).to receive(:encryption_key).and_return("test") + end + + describe "/api/user" do + it "creates a new user and attach the provider credentials" do + email = "email@email.com" + allow(FastlaneCI::Services.user_service.user_data_source).to receive(:user_exist?).with({ email: email }).and_return(false) + + post "/api/user", { github_token: "github_token", password: "password", email: email }.to_json, { "CONTENT_TYPE" => "application/json" } + expect(last_response).to be_ok + expect(json["status"]).to eq("success") + end + + it "returns an error if the user already exists" do + email = "email@email.com" + allow(FastlaneCI::Services.user_service.user_data_source).to receive(:user_exist?).with({ email: email }).and_return(true) + + post "/api/user", { github_token: "github_token", password: "password", email: email }.to_json, { "CONTENT_TYPE" => "application/json" } + expect(last_response.status).to eq(400) + expect(json["key"]).to eq("User.Error") + expect(json["message"]).to eq("Error creating new user") + end + end +end From d6f58924a08d737b49d27f656bd33fe2f3e044d6 Mon Sep 17 00:00:00 2001 From: Felix Krause Date: Fri, 6 Jul 2018 13:54:26 -0400 Subject: [PATCH 2/3] Don't allow custom email for register API endpoint --- app/features-json/user_json_controller.rb | 39 ++++++++++------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/app/features-json/user_json_controller.rb b/app/features-json/user_json_controller.rb index 05ada61f..fa78dbf2 100644 --- a/app/features-json/user_json_controller.rb +++ b/app/features-json/user_json_controller.rb @@ -10,29 +10,24 @@ class UserJSONController < APIController HOME = "/api/user" post HOME.to_s do - email = params[:email] + # fetch email based on the API token instead + github_client = Octokit::Client.new(access_token: params[:github_token]) - if email.nil? - # User didn't provide a custom email address - # fetch it based on the API token instead - github_client = Octokit::Client.new(access_token: params[:github_token]) - - begin - # Note: This fails if the user.email scope is missing from token - email = github_client.emails.find(&:primary).email - rescue Octokit::NotFound - json_error!( - error_message: "Provided API token needs user email scope", - error_key: "User.Token.MissingEmailScope", - error_code: 400 - ) - rescue Octokit::Unauthorized - json_error!( - error_message: "Provided API token is invalid", - error_key: "User.Token.Invalid", - error_code: 403 - ) - end + begin + # Note: This fails if the user.email scope is missing from token + email = github_client.emails.find(&:primary).email + rescue Octokit::NotFound + json_error!( + error_message: "Provided API token needs user email scope", + error_key: "User.Token.MissingEmailScope", + error_code: 400 + ) + rescue Octokit::Unauthorized + json_error!( + error_message: "Provided API token is invalid", + error_key: "User.Token.Invalid", + error_code: 403 + ) end user = Services.user_service.create_user!( From 0a97364f868a94b8d0000c7a0377c1b31eee92f9 Mon Sep 17 00:00:00 2001 From: Felix Krause Date: Mon, 9 Jul 2018 15:20:03 -0400 Subject: [PATCH 3/3] Update tests to stub github client --- spec/features-json/user_json_spec.rb | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/spec/features-json/user_json_spec.rb b/spec/features-json/user_json_spec.rb index f3b647e8..ba0c5a13 100644 --- a/spec/features-json/user_json_spec.rb +++ b/spec/features-json/user_json_spec.rb @@ -13,20 +13,30 @@ def app end describe "/api/user" do + let(:fake_email) { "email@email.com" } + before do + github_client = "github_client" + expect(Octokit::Client).to receive(:new).and_return(github_client) + + email_entry = "email_entry" + expect(email_entry).to receive(:primary).and_return(true) + expect(email_entry).to receive(:email).and_return(fake_email) + + expect(github_client).to receive(:emails).and_return([email_entry]) + end + it "creates a new user and attach the provider credentials" do - email = "email@email.com" - allow(FastlaneCI::Services.user_service.user_data_source).to receive(:user_exist?).with({ email: email }).and_return(false) + allow(FastlaneCI::Services.user_service.user_data_source).to receive(:user_exist?).with({ email: fake_email }).and_return(false) - post "/api/user", { github_token: "github_token", password: "password", email: email }.to_json, { "CONTENT_TYPE" => "application/json" } + post "/api/user", { github_token: "github_token", password: "password" }.to_json, { "CONTENT_TYPE" => "application/json" } expect(last_response).to be_ok expect(json["status"]).to eq("success") end it "returns an error if the user already exists" do - email = "email@email.com" - allow(FastlaneCI::Services.user_service.user_data_source).to receive(:user_exist?).with({ email: email }).and_return(true) + allow(FastlaneCI::Services.user_service.user_data_source).to receive(:user_exist?).with({ email: fake_email }).and_return(true) - post "/api/user", { github_token: "github_token", password: "password", email: email }.to_json, { "CONTENT_TYPE" => "application/json" } + post "/api/user", { github_token: "github_token", password: "password" }.to_json, { "CONTENT_TYPE" => "application/json" } expect(last_response.status).to eq(400) expect(json["key"]).to eq("User.Error") expect(json["message"]).to eq("Error creating new user")