Commit 3845276c authored by Aishwarya Subramanian's avatar Aishwarya Subramanian Committed by Jarka Košanová

Added user job title to users table

Schema changes for new column
Controller changes and specs
Added relevant specs
Added changelog entry
Added few api documentation changes
parent 2b5d9cb7
......@@ -117,6 +117,7 @@ class ProfilesController < Profiles::ApplicationController
:private_profile,
:include_private_contributions,
:timezone,
:job_title,
status: [:emoji, :message]
)
end
......
......@@ -162,6 +162,7 @@ class User < ApplicationRecord
has_one :status, class_name: 'UserStatus'
has_one :user_preference
has_one :user_detail
#
# Validations
......@@ -259,8 +260,10 @@ class User < ApplicationRecord
delegate :sourcegraph_enabled, :sourcegraph_enabled=, to: :user_preference
delegate :setup_for_company, :setup_for_company=, to: :user_preference
delegate :render_whitespace_in_code, :render_whitespace_in_code=, to: :user_preference
delegate :job_title, :job_title=, to: :user_detail, allow_nil: true
accepts_nested_attributes_for :user_preference, update_only: true
accepts_nested_attributes_for :user_detail, update_only: true
state_machine :state, initial: :active do
event :block do
......@@ -1619,6 +1622,10 @@ class User < ApplicationRecord
super.presence || build_user_preference
end
def user_detail
super.presence || build_user_detail
end
def todos_limited_to(ids)
todos.where(id: ids)
end
......
# frozen_string_literal: true
class UserDetail < ApplicationRecord
belongs_to :user
validates :job_title, presence: true, length: { maximum: 200 }
end
---
title: Add support for user Job Title
merge_request: 25483
author:
type: added
......@@ -20,6 +20,8 @@ en:
token: "Grafana HTTP API Token"
grafana_url: "Grafana API URL"
grafana_enabled: "Grafana integration enabled"
user/user_detail:
job_title: 'Job title'
views:
pagination:
previous: "Prev"
......
# frozen_string_literal: true
class CreateUserDetails < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
with_lock_retries do
create_table :user_details, id: false do |t|
t.references :user, index: false, foreign_key: { on_delete: :cascade }, null: false, primary_key: true
t.string :job_title, limit: 200, default: "", null: false
end
end
add_index :user_details, :user_id, unique: true
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_02_26_162723) do
ActiveRecord::Schema.define(version: 2020_02_27_165129) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
......@@ -4170,6 +4170,11 @@ ActiveRecord::Schema.define(version: 2020_02_26_162723) do
t.index ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true
end
create_table "user_details", primary_key: "user_id", force: :cascade do |t|
t.string "job_title", limit: 200, default: "", null: false
t.index ["user_id"], name: "index_user_details_on_user_id", unique: true
end
create_table "user_interacted_projects", id: false, force: :cascade do |t|
t.integer "user_id", null: false
t.integer "project_id", null: false
......@@ -5028,6 +5033,7 @@ ActiveRecord::Schema.define(version: 2020_02_26_162723) do
add_foreign_key "u2f_registrations", "users"
add_foreign_key "user_callouts", "users", on_delete: :cascade
add_foreign_key "user_custom_attributes", "users", on_delete: :cascade
add_foreign_key "user_details", "users", on_delete: :cascade
add_foreign_key "user_interacted_projects", "projects", name: "fk_722ceba4f7", on_delete: :cascade
add_foreign_key "user_interacted_projects", "users", name: "fk_0894651f08", on_delete: :cascade
add_foreign_key "user_preferences", "users", on_delete: :cascade
......
......@@ -95,6 +95,7 @@ GET /users
"twitter": "",
"website_url": "",
"organization": "",
"job_title": "",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
"theme_id": 1,
......@@ -132,6 +133,7 @@ GET /users
"twitter": "",
"website_url": "",
"organization": "",
"job_title": "",
"last_sign_in_at": null,
"confirmed_at": "2012-05-30T16:53:06.148Z",
"theme_id": 1,
......@@ -247,7 +249,8 @@ Parameters:
"linkedin": "",
"twitter": "",
"website_url": "",
"organization": ""
"organization": "",
"job_title": "Operations Specialist"
}
```
......@@ -282,6 +285,7 @@ Example Responses:
"twitter": "",
"website_url": "",
"organization": "",
"job_title": "Operations Specialist",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
"theme_id": 1,
......@@ -545,6 +549,7 @@ GET /user
"twitter": "",
"website_url": "",
"organization": "",
"job_title": "",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
"theme_id": 1,
......
......@@ -4,7 +4,7 @@ module API
module Entities
class User < UserBasic
expose :created_at, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) }
expose :bio, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization
expose :bio, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization, :job_title
end
end
end
......@@ -89,6 +89,16 @@ describe ProfilesController, :request_store do
expect(user.reload.status.message).to eq('Working hard!')
expect(response).to have_gitlab_http_status(:found)
end
it 'allows updating user specified job title' do
title = 'Marketing Executive'
sign_in(user)
put :update, params: { user: { job_title: title } }
expect(user.reload.job_title).to eq(title)
expect(response).to have_gitlab_http_status(:found)
end
end
describe 'PUT update_username' do
......
# frozen_string_literal: true
FactoryBot.define do
factory :user_detail do
user
job_title { 'VP of Sales' }
end
end
# frozen_string_literal: true
require 'spec_helper'
describe UserDetail do
it { is_expected.to belong_to(:user) }
describe 'validations' do
describe 'job_title' do
it { is_expected.to validate_presence_of(:job_title) }
it { is_expected.to validate_length_of(:job_title).is_at_most(200) }
end
end
end
......@@ -29,6 +29,7 @@ describe User, :do_not_mock_admin_mode do
it { is_expected.to have_one(:namespace) }
it { is_expected.to have_one(:status) }
it { is_expected.to have_one(:max_access_level_membership) }
it { is_expected.to have_one(:user_detail) }
it { is_expected.to have_many(:snippets).dependent(:destroy) }
it { is_expected.to have_many(:members) }
it { is_expected.to have_many(:project_members) }
......@@ -4318,4 +4319,19 @@ describe User, :do_not_mock_admin_mode do
expect(user.hook_attrs).to eq(user_attributes)
end
end
describe 'user detail' do
context 'when user is initialized' do
let(:user) { build(:user) }
it { expect(user.user_detail).to be_present }
it { expect(user.user_detail).not_to be_persisted }
end
context 'when user detail exists' do
let(:user) { create(:user, job_title: 'Engineer') }
it { expect(user.user_detail).to be_persisted }
end
end
end
......@@ -330,6 +330,21 @@ describe API::Users, :do_not_mock_admin_mode do
expect(json_response.keys).not_to include 'last_sign_in_ip'
end
context 'when job title is present' do
let(:job_title) { 'Fullstack Engineer' }
before do
create(:user_detail, user: user, job_title: job_title)
end
it 'returns job title of a user' do
get api("/users/#{user.id}", user)
expect(response).to match_response_schema('public_api/v4/user/basic')
expect(json_response['job_title']).to eq(job_title)
end
end
context 'when authenticated as admin' do
it 'includes the `is_admin` field' do
get api("/users/#{user.id}", admin)
......
......@@ -64,6 +64,13 @@ describe Users::UpdateService do
end.not_to change { user.name }
end
it 'updates user detail with provided attributes' do
result = update_user(user, job_title: 'Backend Engineer')
expect(result).to eq(status: :success)
expect(user.job_title).to eq('Backend Engineer')
end
def update_user(user, opts)
described_class.new(user, opts.merge(user: user)).execute
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment