commit
d199576cf7
Binary file not shown.
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 79 KiB |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,125 @@ |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
# This capsulates permissions a user has for a work package. It caches based |
||||
# on the work package's project and is thus optimized for the context menu. |
||||
# |
||||
# This is no conern but it was placed here so that it will be removed together |
||||
# with the rest of the experimental API. |
||||
|
||||
module Api |
||||
module Experimental |
||||
module Concerns |
||||
class Can |
||||
attr_accessor :user |
||||
|
||||
def initialize(user) |
||||
self.user = user |
||||
end |
||||
|
||||
def actions(wp) |
||||
cache[wp].each_with_object([]) { |(k, v), a| a << k if v } |
||||
end |
||||
|
||||
def allowed?(work_package, action) |
||||
cache[work_package][action] |
||||
end |
||||
|
||||
private |
||||
|
||||
def cache |
||||
@cache ||= Hash.new do |hash, work_package| |
||||
# copy checks for the move_work_packages permission. This makes |
||||
# sense only because the work_packages/moves controller handles |
||||
# copying multiple work packages. |
||||
hash[work_package] = { |
||||
:edit => edit_allowed?(work_package), |
||||
:log_time => log_time_allowed?(work_package), |
||||
:move => move_allowed?(work_package), |
||||
:copy => move_allowed?(work_package), |
||||
:duplicate => copy_allowed?(work_package), # duplicating is another form of copying |
||||
:delete => delete_allowed?(work_package) |
||||
} |
||||
end |
||||
end |
||||
|
||||
def edit_allowed?(work_package) |
||||
@edit_cache ||= Hash.new do |hash, project| |
||||
hash[project] = user.allowed_to?(:edit_work_packages, project) |
||||
end |
||||
|
||||
@edit_cache[work_package.project] || work_package.new_statuses_allowed_to(user).present? |
||||
end |
||||
|
||||
def log_time_allowed?(work_package) |
||||
@log_time_cache ||= Hash.new do |hash, project| |
||||
hash[project] = user.allowed_to?(:log_time, project) |
||||
end |
||||
|
||||
@log_time_cache[work_package.project] |
||||
end |
||||
|
||||
def move_allowed?(work_package) |
||||
@move_cache ||= Hash.new do |hash, project| |
||||
hash[project] = user.allowed_to?(:move_work_packages, project) |
||||
end |
||||
|
||||
@move_cache[work_package.project] |
||||
end |
||||
|
||||
def copy_allowed?(work_package) |
||||
type_active_in_project?(work_package) && add_allowed?(work_package) |
||||
end |
||||
|
||||
def delete_allowed?(work_package) |
||||
@delete_cache ||= Hash.new do |hash, project| |
||||
hash[project] = user.allowed_to?(:delete_work_packages, project) |
||||
end |
||||
|
||||
@delete_cache[work_package.project] |
||||
end |
||||
|
||||
def add_allowed?(work_package) |
||||
@add_cache ||= Hash.new do |hash, project| |
||||
hash[project] = user.allowed_to?(:add_work_packages, project) |
||||
end |
||||
|
||||
@add_cache[work_package.project] |
||||
end |
||||
|
||||
def type_active_in_project?(work_package) |
||||
@type_active_cache ||= Hash.new do |hash, project| |
||||
hash[project] = project.types.pluck(:id) |
||||
end |
||||
|
||||
@type_active_cache[work_package.project].include?(work_package.type_id) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,38 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
|
||||
class ChangeAttachmentJournalsDescriptionLength < ActiveRecord::Migration |
||||
def change |
||||
change_column :attachment_journals, |
||||
:description, |
||||
:text |
||||
end |
||||
end |
||||
|
@ -0,0 +1,52 @@ |
||||
module API |
||||
module V3 |
||||
module Queries |
||||
class QueriesAPI < Grape::API |
||||
|
||||
resources :queries do |
||||
|
||||
params do |
||||
requires :id, desc: 'Query id' |
||||
end |
||||
namespace ':id' do |
||||
|
||||
before do |
||||
@query = Query.find(params[:id]) |
||||
model = QueryModel.new(query: @query) |
||||
@representer = QueryRepresenter.new(model) |
||||
end |
||||
|
||||
helpers do |
||||
def allowed_to_manage_stars? |
||||
(@query.is_public? && current_user.allowed_to?(:manage_public_queries, @query.project)) || |
||||
(!@query.is_public? && (current_user.admin? || |
||||
(current_user.allowed_to?(:save_queries, @query.project) && @query.user_id == current_user.id))) |
||||
end |
||||
end |
||||
|
||||
patch :star do |
||||
authorize(:queries, :star, project: @query.project, allow: allowed_to_manage_stars?) |
||||
normalized_query_name = @query.name.parameterize.underscore |
||||
query_menu_item = MenuItems::QueryMenuItem.find_or_initialize_by_name_and_navigatable_id( |
||||
normalized_query_name, @query.id, title: @query.name |
||||
) |
||||
query_menu_item.save! |
||||
@representer.to_json |
||||
end |
||||
|
||||
patch :unstar do |
||||
authorize(:queries, :unstar, project: @query.project, allow: allowed_to_manage_stars?) |
||||
query_menu_item = @query.query_menu_item |
||||
return @representer.to_json if @query.query_menu_item.nil? |
||||
query_menu_item.destroy |
||||
@query.reload |
||||
@representer.to_json |
||||
end |
||||
end |
||||
|
||||
end |
||||
|
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,54 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'reform' |
||||
require 'reform/form/coercion' |
||||
|
||||
module API |
||||
module V3 |
||||
module Queries |
||||
class QueryModel < Reform::Form |
||||
include Composition |
||||
include Coercion |
||||
|
||||
model :query |
||||
|
||||
property :name, on: :query, type: String |
||||
property :project_id, on: :query, type: Integer |
||||
property :user_id, on: :query, type: Integer |
||||
property :filters, on: :query, type: String |
||||
property :is_public, on: :query, type: String |
||||
property :column_names, on: :query, type: String |
||||
property :sort_criteria, on: :query, type: String |
||||
property :group_by, on: :query, type: String |
||||
property :display_sums, on: :query, type: String |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,76 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'roar/decorator' |
||||
require 'roar/representer/json/hal' |
||||
|
||||
module API |
||||
module V3 |
||||
module Queries |
||||
class QueryRepresenter < Roar::Decorator |
||||
include Roar::Representer::JSON::HAL |
||||
include Roar::Representer::Feature::Hypermedia |
||||
include Rails.application.routes.url_helpers |
||||
|
||||
self.as_strategy = API::Utilities::CamelCasingStrategy.new |
||||
|
||||
property :_type, exec_context: :decorator |
||||
|
||||
link :self do |
||||
{ href: "http://localhost:3000/api/v3/queries/#{represented.query.id}", title: "#{represented.name}" } |
||||
end |
||||
|
||||
property :id, getter: -> (*) { query.id }, render_nil: true |
||||
property :name, render_nil: true |
||||
property :project_id, getter: -> (*) { query.project.id } |
||||
property :project_name, getter: -> (*) { query.project.try(:name) } |
||||
property :user_id, getter: -> (*) { query.user.try(:id) }, render_nil: true |
||||
property :user_name, getter: -> (*) { query.user.try(:name) }, render_nil: true |
||||
property :user_login, getter: -> (*) { query.user.try(:login) }, render_nil: true |
||||
property :user_mail, getter: -> (*) { query.user.try(:mail) }, render_nil: true |
||||
property :filters, render_nil: true |
||||
property :is_public, getter: -> (*) { query.is_public.to_s }, render_nil: true |
||||
property :column_names, render_nil: true |
||||
property :sort_criteria, render_nil: true |
||||
property :group_by, render_nil: true |
||||
property :display_sums, getter: -> (*) { query.display_sums.to_s }, render_nil: true |
||||
property :is_starred, getter: -> (*) { is_starred.to_s }, exec_context: :decorator |
||||
|
||||
def _type |
||||
"Query" |
||||
end |
||||
|
||||
def is_starred |
||||
return true if !represented.query.query_menu_item.nil? |
||||
false |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,377 @@ |
||||
require 'spec_helper' |
||||
require 'rack/test' |
||||
|
||||
describe 'API v3 Query resource' do |
||||
include Rack::Test::Methods |
||||
|
||||
let(:project) { FactoryGirl.create(:project, :identifier => 'test_project', :is_public => false) } |
||||
let(:current_user) { FactoryGirl.create(:user) } |
||||
let(:manage_public_queries_role) { FactoryGirl.create(:role, permissions: [:manage_public_queries]) } |
||||
let(:save_queries_role) { FactoryGirl.create(:role, permissions: [:save_queries]) } |
||||
let(:role_without_query_permissions) { FactoryGirl.create(:role, permissions: [:view_work_packages]) } |
||||
let(:unauthorize_user) { FactoryGirl.create(:user) } |
||||
|
||||
describe '#star' do |
||||
let(:star_path) { "/api/v3/queries/#{query.id}/star" } |
||||
let(:filters) do |
||||
query.filters.map{ |f| {f.field.to_s => { "operator" => f.operator, "values" => f.values }}} |
||||
end |
||||
let(:expected_response) do |
||||
{ |
||||
"_type" => 'Query', |
||||
"_links" => { |
||||
"self" => { |
||||
"href" => "http://localhost:3000/api/v3/queries/#{query.id}", |
||||
"title" => query.name |
||||
} |
||||
}, |
||||
"id" => query.id, |
||||
"name" => query.name, |
||||
"projectId" => query.project_id, |
||||
"projectName" => query.project.name, |
||||
"userId" => query.user_id, |
||||
"userName" => query.user.try(:name), |
||||
"userLogin" => query.user.try(:login), |
||||
"userMail" => query.user.try(:mail), |
||||
"filters" => filters, |
||||
"isPublic" => query.is_public.to_s, |
||||
"columnNames" => query.column_names, |
||||
"sortCriteria" => query.sort_criteria, |
||||
"groupBy" => query.group_by, |
||||
"displaySums" => query.display_sums.to_s, |
||||
"isStarred" => "true" |
||||
} |
||||
end |
||||
|
||||
describe 'public queries' do |
||||
let(:query) { FactoryGirl.create(:public_query, project: project) } |
||||
|
||||
context 'user with permission to manage public queries' do |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [manage_public_queries_role.id] |
||||
member.save! |
||||
end |
||||
|
||||
context 'when starring an unstarred query' do |
||||
before(:each) { patch star_path } |
||||
|
||||
it 'should respond with 200' do |
||||
last_response.status.should eq(200) |
||||
end |
||||
|
||||
it 'should return the query in HAL+JSON format' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response.should eq(expected_response) |
||||
end |
||||
|
||||
it 'should return the query with "isStarred" property set to true' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response['isStarred'].should eq('true') |
||||
end |
||||
end |
||||
|
||||
context 'when starring already starred query' do |
||||
before(:each) { patch star_path } |
||||
|
||||
it 'should respond with 200' do |
||||
last_response.status.should eq(200) |
||||
end |
||||
|
||||
it 'should return the query in HAL+JSON format' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response.should eq(expected_response) |
||||
end |
||||
|
||||
it 'should return the query with "isStarred" property set to true' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response['isStarred'].should eq('true') |
||||
end |
||||
end |
||||
|
||||
context 'when trying to star nonexistent query' do |
||||
let(:star_path) { "/api/v3/queries/999/star" } |
||||
before(:each) { patch star_path } |
||||
|
||||
it 'should respond with 404' do |
||||
last_response.status.should eq(404) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_found', 'messages' => ['Couldn\'t find Query with id=999']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'user without permission to manage public queries' do |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [role_without_query_permissions.id] |
||||
member.save! |
||||
patch star_path |
||||
end |
||||
|
||||
it 'should respond with 403' do |
||||
last_response.status.should eq(403) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'private queries' do |
||||
context 'user with permission to save queries' do |
||||
let(:query) { FactoryGirl.create(:private_query, project: project, user: current_user) } |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [save_queries_role.id] |
||||
member.save! |
||||
patch star_path |
||||
end |
||||
|
||||
context 'starring his own query' do |
||||
|
||||
it 'should respond with 200' do |
||||
last_response.status.should eq(200) |
||||
end |
||||
|
||||
it 'should return the query in HAL+JSON format' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response.should eq(expected_response) |
||||
end |
||||
|
||||
it 'should return the query with "isStarred" property set to true' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response['isStarred'].should eq('true') |
||||
end |
||||
end |
||||
|
||||
context 'trying to star somebody else\'s query' do |
||||
let(:another_user) { FactoryGirl.create(:user) } |
||||
let(:query) { FactoryGirl.create(:private_query, project: project, user: another_user) } |
||||
|
||||
it 'should respond with 403' do |
||||
last_response.status.should eq(403) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'user without permission to save queries' do |
||||
let(:query) { FactoryGirl.create(:private_query, project: project, user: current_user) } |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [role_without_query_permissions.id] |
||||
member.save! |
||||
patch star_path |
||||
end |
||||
|
||||
it 'should respond with 403' do |
||||
last_response.status.should eq(403) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}]) |
||||
end |
||||
end |
||||
|
||||
end |
||||
end |
||||
|
||||
describe '#unstar' do |
||||
let(:unstar_path) { "/api/v3/queries/#{query.id}/unstar" } |
||||
let(:filters) do |
||||
query.filters.map{ |f| {f.field.to_s => { "operator" => f.operator, "values" => f.values }}} |
||||
end |
||||
let(:expected_response) do |
||||
{ |
||||
"_type" => 'Query', |
||||
"_links" => { |
||||
"self" => { |
||||
"href" => "http://localhost:3000/api/v3/queries/#{query.id}", |
||||
"title" => query.name |
||||
} |
||||
}, |
||||
"id" => query.id, |
||||
"name" => query.name, |
||||
"projectId" => query.project_id, |
||||
"projectName" => query.project.name, |
||||
"userId" => query.user_id, |
||||
"userName" => query.user.try(:name), |
||||
"userLogin" => query.user.try(:login), |
||||
"userMail" => query.user.try(:mail), |
||||
"filters" => filters, |
||||
"isPublic" => query.is_public.to_s, |
||||
"columnNames" => query.column_names, |
||||
"sortCriteria" => query.sort_criteria, |
||||
"groupBy" => query.group_by, |
||||
"displaySums" => query.display_sums.to_s, |
||||
"isStarred" => "true" |
||||
} |
||||
end |
||||
|
||||
describe 'public queries' do |
||||
let(:query) { FactoryGirl.create(:public_query, project: project) } |
||||
|
||||
context 'user with permission to manage public queries' do |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [manage_public_queries_role.id] |
||||
member.save! |
||||
end |
||||
|
||||
context 'when unstarring a starred query' do |
||||
before(:each) do |
||||
FactoryGirl.create(:query_menu_item, query: query) |
||||
patch unstar_path |
||||
end |
||||
|
||||
it 'should respond with 200' do |
||||
last_response.status.should eq(200) |
||||
end |
||||
|
||||
it 'should return the query in HAL+JSON format' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response.should eq(expected_response.tap{ |r| r["isStarred"] = "false" }) |
||||
end |
||||
|
||||
it 'should return the query with "isStarred" property set to false' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response['isStarred'].should eq('false') |
||||
end |
||||
end |
||||
|
||||
context 'when unstarring an unstarred query' do |
||||
before(:each) { patch unstar_path } |
||||
|
||||
it 'should respond with 200' do |
||||
last_response.status.should eq(200) |
||||
end |
||||
|
||||
it 'should return the query in HAL+JSON format' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response.should eq(expected_response.tap{ |r| r["isStarred"] = "false" }) |
||||
end |
||||
|
||||
it 'should return the query with "isStarred" property set to true' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response['isStarred'].should eq('false') |
||||
end |
||||
|
||||
end |
||||
|
||||
context 'when trying to unstar nonexistent query' do |
||||
let(:unstar_path) { "/api/v3/queries/999/unstar" } |
||||
before(:each) { patch unstar_path } |
||||
|
||||
it 'should respond with 404' do |
||||
last_response.status.should eq(404) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_found', 'messages' => ['Couldn\'t find Query with id=999']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'user without permission to manage public queries' do |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [role_without_query_permissions.id] |
||||
member.save! |
||||
patch unstar_path |
||||
end |
||||
|
||||
it 'should respond with 403' do |
||||
last_response.status.should eq(403) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'private queries' do |
||||
context 'user with permission to save queries' do |
||||
let(:query) { FactoryGirl.create(:private_query, project: project, user: current_user) } |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [save_queries_role.id] |
||||
member.save! |
||||
patch unstar_path |
||||
end |
||||
|
||||
context 'unstarring his own query' do |
||||
|
||||
it 'should respond with 200' do |
||||
last_response.status.should eq(200) |
||||
end |
||||
|
||||
it 'should return the query in HAL+JSON format' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response.should eq(expected_response.tap{ |r| r["isStarred"] = "false" }) |
||||
end |
||||
|
||||
it 'should return the query with "isStarred" property set to true' do |
||||
parsed_response = JSON.parse(last_response.body) |
||||
parsed_response['isStarred'].should eq('false') |
||||
end |
||||
end |
||||
|
||||
context 'trying to unstar somebody else\'s query' do |
||||
let(:another_user) { FactoryGirl.create(:user) } |
||||
let(:query) { FactoryGirl.create(:private_query, project: project, user: another_user) } |
||||
|
||||
it 'should respond with 403' do |
||||
last_response.status.should eq(403) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'user without permission to save queries' do |
||||
let(:query) { FactoryGirl.create(:private_query, project: project, user: current_user) } |
||||
before(:each) do |
||||
allow(User).to receive(:current).and_return current_user |
||||
member = FactoryGirl.build(:member, user: current_user, project: project) |
||||
member.role_ids = [role_without_query_permissions.id] |
||||
member.save! |
||||
patch unstar_path |
||||
end |
||||
|
||||
it 'should respond with 403' do |
||||
last_response.status.should eq(403) |
||||
end |
||||
|
||||
it 'should respond with explanatory error message' do |
||||
parsed_errors = JSON.parse(last_response.body)['errors'] |
||||
parsed_errors.should eq([{ 'key' => 'not_authorized', 'messages' => ['You are not authorize to access this resource']}]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
end |
||||
end |
Loading…
Reference in new issue