From 818caf0b5d1fc4f0cb2889ca5bd9e2d0d7fd8ac8 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 14:33:29 +0100 Subject: [PATCH] API: refined status code handling when adding or updating a project member When a user is added to a project that is already a member of, a status code 201 is now returned to signal an idempotent operation. If something fails then instead of returning error code 404 different more specific error codes are returned. Status code 400 (Bad request) is returned when a required attribute, e.g. `access_level` is not given or 422 if there is a semantic error, e.g. should the `access_level` have an unsupported value. Specs are added to check these status codes. --- lib/api/projects.rb | 35 +++++++++++++++++------- spec/requests/api/projects_spec.rb | 43 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 47ab4e1aab0..e6df6b4ee88 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -89,15 +89,26 @@ module Gitlab # POST /projects/:id/members post ":id/members" do authorize! :admin_project, user_project - users_project = user_project.users_projects.new( - user_id: params[:user_id], - project_access: params[:access_level] - ) - if users_project.save - @member = users_project.user + error!("User id not given", 400) if !params.has_key? :user_id + error!("Access level not given", 400) if !params.has_key? :access_level + + # either the user is already a team member or a new one + team_member = user_project.team_member_by_id(params[:user_id]) + if team_member.nil? + team_member = user_project.users_projects.new( + user_id: params[:user_id], + project_access: params[:access_level] + ) + end + + if team_member.save + @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else + if team_member.errors[:project_access].any? + error!(team_member.errors[:project_access], 422) + end not_found! end end @@ -112,12 +123,18 @@ module Gitlab # PUT /projects/:id/members/:user_id put ":id/members/:user_id" do authorize! :admin_project, user_project - users_project = user_project.users_projects.find_by_user_id params[:user_id] - if users_project.update_attributes(project_access: params[:access_level]) - @member = users_project.user + team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + error!("Access level not given", 400) if !params.has_key? :access_level + error!("User can not be found", 404) if team_member.nil? + + if team_member.update_attributes(project_access: params[:access_level]) + @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else + if team_member.errors[:project_access].any? + error!(team_member.errors[:project_access], 422) + end not_found! end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 2682629e7db..91632407c6f 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -177,6 +177,34 @@ describe Gitlab::API do json_response['email'].should == user2.email json_response['access_level'].should == UsersProject::DEVELOPER end + + it "should return a 201 status if user is already project member" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + expect { + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + }.not_to change { UsersProject.count }.by(1) + + response.status.should == 201 + json_response['email'].should == user2.email + json_response['access_level'].should == UsersProject::DEVELOPER + end + + it "should return a 400 error when user id is not given" do + post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER + response.status.should == 400 + end + + it "should return a 400 error when access level is not given" do + post api("/projects/#{project.id}/members", user), user_id: user2.id + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234 + response.status.should == 422 + end end describe "PUT /projects/:id/members/:user_id" do @@ -186,6 +214,21 @@ describe Gitlab::API do json_response['email'].should == user3.email json_response['access_level'].should == UsersProject::MASTER end + + it "should return a 404 error if user_id is not found" do + put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER + response.status.should == 404 + end + + it "should return a 400 error when access level is not given" do + put api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123 + response.status.should == 422 + end end describe "DELETE /projects/:id/members/:user_id" do