fix new API endpoints and add test cases

This commit is contained in:
zmagoD 2021-05-23 17:31:02 +02:00
parent 300c1521fd
commit 7e6789200a
12 changed files with 773 additions and 18 deletions

View file

@ -11,6 +11,7 @@ module Api
def index
user_assignments = @experiment.user_assignments
.includes(:user_role)
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
@ -28,17 +29,18 @@ module Api
def create
raise PermissionError.new(Experiment, :manage) unless can_manage_experiment?(@experiment)
user_role = UserRole.find_by_name user_assignment_params[:role]
user_role = UserRole.find_by_name incoming_role_name(user_assignment_params[:role])
experiment_member = ExperimentMember.new(current_user, @experiment, @project)
experiment_member.create(
user_role_id: user_role.id,
user_id: user_assignment_params[:user_id]
)
render jsonapi: experiment_member.user_project, serializer: ExperimentUserAssignmentSerializer, status: :created
render jsonapi: experiment_member.user_assignment.reload, serializer: ExperimentUserAssignmentSerializer, status: :created
end
def update
user_role = UserRole.find_by_name user_assignment_params[:role]
user_role = UserRole.find_by_name incoming_role_name(user_assignment_params[:role])
user = @user_assignment.user
experiment_member = ExperimentMember.new(
current_user,
@ -51,7 +53,7 @@ module Api
return render body: nil, status: :no_content if @user_assignment.user_role == user_role
experiment_member.update(user_role_id: user_role.id, user_id: user.id)
render jsonapi: experiment_member.user_project, serializer: ExperimentUserAssignmentSerializer, status: :ok
render jsonapi: experiment_member.user_assignment.reload, serializer: ExperimentUserAssignmentSerializer, status: :ok
end
def destroy
@ -68,6 +70,8 @@ module Api
private
include Api::V1::UserRoleSanitizer
def load_user_assignment
@user_assignment = @experiment.user_assignments.find(params.require(:id))
end

View file

@ -12,6 +12,7 @@ module Api
def index
user_assignments = @task.user_assignments
.includes(:user_role)
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
@ -29,17 +30,17 @@ module Api
def create
raise PermissionError.new(MyModule, :read) unless can_manage_module?(@task)
user_role = UserRole.find_by_name user_assignment_params[:role]
user_role = UserRole.find_by_name incoming_role_name(user_assignment_params[:role])
my_module_member = MyModuleMember.new(current_user, @task, @experiment, @project)
my_module_member.create(
user_role_id: user_role.id,
user_id: user_assignment_params[:user_id]
)
render jsonapi: my_module_member.user_project, serializer: TaskUserAssignmentSerializer, status: :created
render jsonapi: my_module_member.user_assignment.reload, serializer: TaskUserAssignmentSerializer, status: :created
end
def update
user_role = UserRole.find_by_name user_assignment_params[:role]
user_role = UserRole.find_by_name incoming_role_name(user_assignment_params[:role])
user = @user_assignment.user
my_module_member = MyModuleMember.new(
current_user,
@ -53,7 +54,7 @@ module Api
return render body: nil, status: :no_content if @user_assignment.user_role == user_role
my_module_member.update(user_role_id: user_role.id, user_id: user.id)
render jsonapi: my_module_member.user_project, serializer: TaskUserAssignmentSerializer, status: :ok
render jsonapi: my_module_member.user_assignment.reload, serializer: TaskUserAssignmentSerializer, status: :ok
end
def destroy
@ -71,6 +72,8 @@ module Api
private
include Api::V1::UserRoleSanitizer
def load_user_assignment
@user_assignment = @task.user_assignments.find(params.require(:id))
end

View file

@ -9,7 +9,7 @@ module Api
before_action :load_user_project_for_managing, only: %i(update destroy)
def index
user_projects = @project.user_projects
user_projects = @project.user_projects.includes(:user, project: [user_assignments: :user_role])
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
@ -28,7 +28,7 @@ module Api
raise PermissionError.new(Project, :manage) unless can_manage_project?(@project)
# internally we reuse the same logic as for user project assignment
user_role = UserRole.find_by_name user_project_params[:role]
user_role = UserRole.find_by_name incoming_role_name(user_project_params[:role])
user = @team.users.find(user_project_params[:user_id])
project_member = ProjectMember.new(user, @project, current_user)
@ -36,11 +36,11 @@ module Api
project_member.user_role_id = user_role.id
project_member.create
render jsonapi: project_member.user_project, serializer: UserProjectSerializer, status: :created
render jsonapi: project_member.user_project.reload, serializer: UserProjectSerializer, status: :created
end
def update
user_role = UserRole.find_by_name user_project_params[:role]
user_role = UserRole.find_by_name incoming_role_name(user_project_params[:role])
project_member = ProjectMember.new(@user_project.user, @project, current_user)
if project_member.user_assignment&.user_role == user_role
@ -49,7 +49,7 @@ module Api
project_member.user_role_id = user_role.id
project_member.update
render jsonapi: @user_project, serializer: UserProjectSerializer, status: :ok
render jsonapi: @user_project.reload, serializer: UserProjectSerializer, status: :ok
end
def destroy
@ -60,6 +60,8 @@ module Api
private
include Api::V1::UserRoleSanitizer
def load_user_project
@user_project = @project.user_projects.find(params.require(:id))
end

View file

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Api
module V1
module UserRoleSanitizer
extend ActiveSupport::Concern
def incoming_role_name(role)
case role
when 'owner'
I18n.t('user_roles.predefined.owner')
when 'normal_user'
I18n.t('user_roles.predefined.normal_user')
when 'technician'
I18n.t('user_roles.predefined.technician')
when 'viewer'
I18n.t('user_roles.predefined.viewer')
else
raise IncludeNotSupportedError
end
end
end
end
end

View file

@ -6,4 +6,17 @@ module UserRolesHelper
@user_roles_collection ||= UserRole.all.pluck(:name, :id)
end
end
def legacy_user_role_parser(name)
case name
when I18n.t('user_roles.predefined.owner')
'owner'
when I18n.t('user_roles.predefined.normal_user')
'normal_user'
when I18n.t('user_roles.predefined.technician')
'technician'
when I18n.t('user_roles.predefined.viewer')
'viewer'
end
end
end

View file

@ -3,11 +3,17 @@
module Api
module V1
class ExperimentUserAssignmentSerializer < ActiveModel::Serializer
include UserRolesHelper
type :experiment_user_assignments
attributes :id, :role
belongs_to :user, serializer: UserSerializer
belongs_to :experiment, serializer: ExperimentSerializer
def role
# TODO: sync about the role solution
legacy_user_role_parser(object.user_role.name)
end
end
end
end

View file

@ -3,11 +3,17 @@
module Api
module V1
class TaskUserAssignmentSerializer < ActiveModel::Serializer
include UserRolesHelper
type :task_user_assignments
attributes :id, :role
belongs_to :user, serializer: UserSerializer
belongs_to :task, serializer: TaskSerializer
def role
# TODO: sync about the role solution
legacy_user_role_parser(object.user_role.name)
end
end
end
end

View file

@ -3,10 +3,22 @@
module Api
module V1
class UserProjectSerializer < ActiveModel::Serializer
include UserRolesHelper
type :user_projects
attributes :id, :role
belongs_to :user, serializer: UserSerializer
def role
# TODO: sync about the role solution
user_role = object.project
.user_assignments
.select { |ua| ua.user_id == object.user.id }
.first&.user_role
return unless user_role
legacy_user_role_parser(user_role.name)
end
end
end
end

View file

@ -697,11 +697,15 @@ Rails.application.routes.draw do
get 'activities', to: 'projects#activities'
resources :reports, only: %i(index show), path: 'reports', as: :reports
resources :experiments, only: %i(index show create update) do
resources :experiment_user_assignments, only: %i(index show create update)
resources :user_assignments,
only: %i(index show create update),
controller: :experiment_user_assignments
resources :task_groups, only: %i(index show)
resources :connections, only: %i(index show)
resources :tasks, only: %i(index show create update) do
resources :tasks_user_assignments, only: %i(index show create update)
resources :user_assignments,
only: %i(index show create update),
controller: :task_user_assignments
resources :task_inventory_items, only: %i(index show),
path: 'items',
as: :items

View file

@ -0,0 +1,330 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe "Api::V1::ExperimentUserAssignmentsController", type: :request do
before :all do
@user = create(:user)
@another_user = create(:user)
@team = create(:team, created_by: @user)
@normal_user_role = create :normal_user_role
@owner_role = create :owner_role
create(:user_team, user: @user, team: @team, role: :normal_user)
create(:user_team, user: @another_user, team: @team, role: :normal_user)
@own_project = create(:project, name: Faker::Name.unique.name, created_by: @user, team: @team)
@own_experiment = create :experiment,
name: Faker::Name.unique.name,
project: @own_project,
created_by: @user
@invalid_project = create :project,
name: Faker::Name.unique.name,
created_by: @another_user,
team: @team,
visibility: :hidden
@invalid_experiment = create :experiment,
name: Faker::Name.unique.name,
project: @invalid_project,
created_by: @another_user
create :user_project, user: @user, project: @own_project
create :user_assignment, assignable: @own_project, user: @user, user_role: @owner_role, assigned_by: @user
create :user_assignment, assignable: @own_experiment, user: @user, user_role: @owner_role, assigned_by: @user
create :technician_role
@valid_headers = { 'Authorization': 'Bearer ' + generate_token(@user.id) }
end
describe 'GET experiment_user_assignments, #index' do
it 'Response with correct user assignments' do
hash_body = nil
get api_v1_team_project_experiment_user_assignments_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@own_experiment.user_assignments, each_serializer: Api::V1::ExperimentUserAssignmentSerializer)
.as_json[:data]
)
end
it 'When invalid request, user in not an owner of the experiment' do
hash_body = nil
get api_v1_team_project_experiment_user_assignments_path(
team_id: @team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id),
headers: @valid_headers
expect(response).to have_http_status(403)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)
end
it 'When invalid request, non existing experiment' do
hash_body = nil
get api_v1_team_project_experiment_user_assignments_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 404)
end
end
describe 'GET user_assignment, #show' do
it 'When valid request, user can read user assignment' do
hash_body = nil
get api_v1_team_project_experiment_user_assignment_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
id: @own_experiment.user_assignments.first.id
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@own_experiment.user_assignments.first, serializer: Api::V1::ExperimentUserAssignmentSerializer)
.as_json[:data]
)
end
it 'When invalid request, user in not member of the project' do
hash_body = nil
get api_v1_team_project_experiment_user_assignment_path(
team_id: @team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id,
id: -1
), headers: @valid_headers
expect(response).to have_http_status(403)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)
end
it 'When invalid request, non existing project' do
hash_body = nil
get api_v1_team_project_experiment_user_assignment_path(
team_id: @team.id,
project_id: -1,
experiment_id: -1,
id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 404)
end
end
describe 'POST user_assignment, #create' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
create :user_assignment,
assignable: @own_project,
user: @another_user,
user_role: @owner_role,
assigned_by: @user
end
let(:action) do
post(api_v1_team_project_experiment_user_assignments_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id),
params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'experiment_user_assignments',
attributes: {
user_id: @another_user.id,
role: 'normal_user'
}
}
}
end
it 'creates new user_assignment' do
expect { action }.to change { UserAssignment.count }.by(1)
end
it 'returns status 201' do
action
expect(response).to have_http_status 201
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'experiment_user_assignments',
attributes: hash_including(role: 'normal_user'),
relationships: hash_including(user: hash_including(data: hash_including(id: @another_user.id.to_s)))
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'experiment_user_assignments',
attributes: {}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
context 'when user is not an owner of the project' do
let(:request_body) do
{
data: {
type: 'experiment_user_assignments',
attributes: {
user_id: @another_user.id,
role: 'normal_user'
}
}
}
end
it 'renders 403' do
post(
api_v1_team_project_experiment_user_assignments_path(
team_id: @invalid_project.team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id
),
params: request_body.to_json,
headers: @valid_headers
)
expect(response).to have_http_status(403)
end
end
end
describe 'PATCH user_assignment, #update' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
@user_assignment = create :user_assignment,
assignable: @own_experiment,
user: @another_user,
user_role: @normal_user_role,
assigned_by: @user
end
let(:action) do
patch(
api_v1_team_project_experiment_user_assignment_path(
team_id: @own_project.team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
id: @user_assignment.id
),
params: request_body.to_json,
headers: @valid_headers
)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'experiment_user_assignments',
attributes: {
role: :technician
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'experiment_user_assignments',
attributes: hash_including(role: 'technician')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'experiment_user_assignments',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
context 'when user is not an owner of the project' do
let(:request_body) do
{
data: {
type: 'experiment_user_assignments',
attributes: {
role: :technician
}
}
}
end
it 'renders 403' do
invalid_user_assignment = create :user_assignment,
assignable: @invalid_experiment,
user: @another_user,
user_role: @normal_user_role,
assigned_by: @another_user
patch(
api_v1_team_project_experiment_user_assignment_path(
team_id: @invalid_project.team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id,
id: invalid_user_assignment.id
),
params: request_body.to_json,
headers: @valid_headers
)
expect(response).to have_http_status(403)
end
end
end
end

View file

@ -0,0 +1,343 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe "Api::V1::TaskUserAssignmentsController", type: :request do
before :all do
@user = create(:user)
@another_user = create(:user)
@team = create(:team, created_by: @user)
@normal_user_role = create :normal_user_role
@owner_role = create :owner_role
create(:user_team, user: @user, team: @team, role: :normal_user)
create(:user_team, user: @another_user, team: @team, role: :normal_user)
@own_project = create(:project, name: Faker::Name.unique.name, created_by: @user, team: @team)
@own_experiment = create :experiment,
name: Faker::Name.unique.name,
project: @own_project,
created_by: @user
@own_task = create :my_module, name: Faker::Name.unique.name, experiment: @own_experiment
@invalid_project = create :project,
name: Faker::Name.unique.name,
created_by: @another_user,
team: @team,
visibility: :hidden
@invalid_experiment = create :experiment,
name: Faker::Name.unique.name,
project: @invalid_project,
created_by: @another_user
@invalid_task = create :my_module, name: Faker::Name.unique.name, experiment: @invalid_experiment
create :user_project, user: @user, project: @own_project
create :user_assignment, assignable: @own_project, user: @user, user_role: @owner_role, assigned_by: @user
create :user_assignment, assignable: @own_experiment, user: @user, user_role: @owner_role, assigned_by: @user
create :user_assignment, assignable: @own_task, user: @user, user_role: @owner_role, assigned_by: @user
create :technician_role
@valid_headers = { 'Authorization': 'Bearer ' + generate_token(@user.id) }
end
describe 'GET task_user_assignments, #index' do
it 'Response with correct user assignments' do
hash_body = nil
get api_v1_team_project_experiment_task_user_assignments_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
task_id: @own_task.id
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@own_task.user_assignments, each_serializer: Api::V1::TaskUserAssignmentSerializer)
.as_json[:data]
)
end
it 'When invalid request, user in not an owner of the task' do
hash_body = nil
get api_v1_team_project_experiment_task_user_assignments_path(
team_id: @team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id,
task_id: @invalid_task.id
), headers: @valid_headers
expect(response).to have_http_status(403)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)
end
it 'When invalid request, non existing task' do
hash_body = nil
get api_v1_team_project_experiment_task_user_assignments_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
task_id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 404)
end
end
describe 'GET user_assignment, #show' do
it 'When valid request, user can read user assignment' do
hash_body = nil
get api_v1_team_project_experiment_task_user_assignment_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
task_id: @own_task.id,
id: @own_task.user_assignments.first.id
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@own_task.user_assignments.first, serializer: Api::V1::TaskUserAssignmentSerializer)
.as_json[:data]
)
end
it 'When invalid request, user in not member of the project' do
hash_body = nil
get api_v1_team_project_experiment_task_user_assignment_path(
team_id: @team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id,
task_id: @invalid_task.id,
id: -1
), headers: @valid_headers
expect(response).to have_http_status(403)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)
end
it 'When invalid request, non existing project' do
hash_body = nil
get api_v1_team_project_experiment_task_user_assignment_path(
team_id: @team.id,
project_id: -1,
experiment_id: -1,
task_id: -1,
id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 404)
end
end
describe 'POST user_assignment, #create' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
create :user_assignment,
assignable: @own_project,
user: @another_user,
user_role: @owner_role,
assigned_by: @user
end
let(:action) do
post(api_v1_team_project_experiment_task_user_assignments_path(
team_id: @team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
task_id: @own_task.id),
params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'task_user_assignments',
attributes: {
user_id: @another_user.id,
role: 'normal_user'
}
}
}
end
it 'creates new user_assignment' do
expect { action }.to change { UserAssignment.count }.by(1)
end
it 'returns status 201' do
action
expect(response).to have_http_status 201
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'task_user_assignments',
attributes: hash_including(role: 'normal_user'),
relationships: hash_including(user: hash_including(data: hash_including(id: @another_user.id.to_s)))
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'task_user_assignments',
attributes: {}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
context 'when user is not an owner of the project' do
let(:request_body) do
{
data: {
type: 'task_user_assignments',
attributes: {
user_id: @another_user.id,
role: 'normal_user'
}
}
}
end
it 'renders 403' do
post(
api_v1_team_project_experiment_task_user_assignments_path(
team_id: @invalid_project.team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id,
task_id: @invalid_task.id
),
params: request_body.to_json,
headers: @valid_headers
)
expect(response).to have_http_status(403)
end
end
end
describe 'PATCH user_assignment, #update' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
@user_assignment = create :user_assignment,
assignable: @own_task,
user: @another_user,
user_role: @normal_user_role,
assigned_by: @user
end
let(:action) do
patch(
api_v1_team_project_experiment_task_user_assignment_path(
team_id: @own_project.team.id,
project_id: @own_project.id,
experiment_id: @own_experiment.id,
task_id: @own_task.id,
id: @user_assignment.id
),
params: request_body.to_json,
headers: @valid_headers
)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'task_user_assignments',
attributes: {
role: :technician
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'task_user_assignments',
attributes: hash_including(role: 'technician')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'task_user_assignments',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
context 'when user is not an owner of the project' do
let(:request_body) do
{
data: {
type: 'task_user_assignments',
attributes: {
role: :technician
}
}
}
end
it 'renders 403' do
invalid_user_assignment = create :user_assignment,
assignable: @invalid_task,
user: @another_user,
user_role: @normal_user_role,
assigned_by: @another_user
patch(
api_v1_team_project_experiment_task_user_assignment_path(
team_id: @invalid_project.team.id,
project_id: @invalid_project.id,
experiment_id: @invalid_experiment.id,
task_id: @invalid_task.id,
id: invalid_user_assignment.id
),
params: request_body.to_json,
headers: @valid_headers
)
expect(response).to have_http_status(403)
end
end
end
end

View file

@ -13,6 +13,8 @@ RSpec.describe "Api::V1::UserProjectsController", type: :request do
@invalid_project =
create(:project, name: Faker::Name.unique.name, created_by: @another_user, team: @team, visibility: :hidden)
create(:user_project, role: :owner, user: @user, project: @own_project)
create :user_assignment, assignable: @own_project, user: @user, user_role: create(:owner_role), assigned_by: @user
@normal_user_role = create :normal_user_role
@valid_headers = { 'Authorization': 'Bearer ' + generate_token(@user.id) }
end
@ -177,7 +179,13 @@ RSpec.describe "Api::V1::UserProjectsController", type: :request do
describe 'PATCH user_project, #update' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
@user_project = create(:user_project, role: :normal_user, user: @another_user, project: @own_project)
@user_project = create(:user_project, user: @another_user, project: @own_project)
create :user_assignment,
assignable: @own_project,
user: @another_user,
user_role: @normal_user_role,
assigned_by: @user
create :technician_role
end
let(:action) do