Maintenance: Enhance attachment preview capabilities
This commit is contained in:
parent
72f39d0d9d
commit
ed1782fafc
8 changed files with 322 additions and 158 deletions
|
@ -10,8 +10,8 @@ class ApplicationController < ActionController::Base
|
||||||
include ApplicationController::RendersModels
|
include ApplicationController::RendersModels
|
||||||
include ApplicationController::HasUser
|
include ApplicationController::HasUser
|
||||||
include ApplicationController::HasResponseExtentions
|
include ApplicationController::HasResponseExtentions
|
||||||
|
include ApplicationController::HasDownload
|
||||||
include ApplicationController::PreventsCsrf
|
include ApplicationController::PreventsCsrf
|
||||||
include ApplicationController::HasSecureContentSecurityPolicyForDownloads
|
|
||||||
include ApplicationController::LogsHttpAccess
|
include ApplicationController::LogsHttpAccess
|
||||||
include ApplicationController::Authorizes
|
include ApplicationController::Authorizes
|
||||||
end
|
end
|
||||||
|
|
44
app/controllers/application_controller/has_download.rb
Normal file
44
app/controllers/application_controller/has_download.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
module ApplicationController::HasDownload
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
around_action do |_controller, block|
|
||||||
|
|
||||||
|
subscriber = proc do
|
||||||
|
policy = ActionDispatch::ContentSecurityPolicy.new
|
||||||
|
policy.default_src :none
|
||||||
|
|
||||||
|
# The 'plugin_types' rule is deprecated and should be changed in the future.
|
||||||
|
policy.plugin_types 'application/pdf'
|
||||||
|
|
||||||
|
request.content_security_policy = policy
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveSupport::Notifications.subscribed(subscriber, 'send_file.action_controller') do
|
||||||
|
ActiveSupport::Notifications.subscribed(subscriber, 'send_data.action_controller') do
|
||||||
|
block.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def file_id
|
||||||
|
@file_id ||= params[:id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def download_file
|
||||||
|
@download_file ||= ::ApplicationController::HasDownload::DownloadFile.new(file_id, disposition: sanitized_disposition)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sanitized_disposition
|
||||||
|
disposition = params.fetch(:disposition, 'inline')
|
||||||
|
valid_disposition = %w[inline attachment]
|
||||||
|
return disposition if valid_disposition.include?(disposition)
|
||||||
|
|
||||||
|
raise Exceptions::Forbidden, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class ApplicationController::HasDownload::DownloadFile < SimpleDelegator
|
||||||
|
attr_reader :requested_disposition
|
||||||
|
|
||||||
|
def initialize(id, disposition: 'inline')
|
||||||
|
@requested_disposition = disposition
|
||||||
|
|
||||||
|
super(Store.find(id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def disposition
|
||||||
|
return 'attachment' if forcibly_download_as_binary? || !allowed_inline?
|
||||||
|
|
||||||
|
requested_disposition
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_type
|
||||||
|
return ActiveStorage.binary_content_type if forcibly_download_as_binary?
|
||||||
|
|
||||||
|
file_content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def content(view_type)
|
||||||
|
return __getobj__.content if view_type.blank? || !preferences[:resizable]
|
||||||
|
|
||||||
|
return content_inline if content_inline? && view_type == 'inline'
|
||||||
|
return content_preview if content_preview? && view_type == 'preview'
|
||||||
|
|
||||||
|
__getobj__.content
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def allowed_inline?
|
||||||
|
ActiveStorage.content_types_allowed_inline.include?(content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def forcibly_download_as_binary?
|
||||||
|
ActiveStorage.content_types_to_serve_as_binary.include?(file_content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def file_content_type
|
||||||
|
@file_content_type ||= preferences['Content-Type'] || preferences['Mime-Type'] || ActiveStorage.binary_content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_inline?
|
||||||
|
preferences[:content_inline] == true
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_preview?
|
||||||
|
preferences[:content_preview] == true
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,25 +0,0 @@
|
||||||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
|
||||||
|
|
||||||
module ApplicationController::HasSecureContentSecurityPolicyForDownloads
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
|
|
||||||
around_action do |_controller, block|
|
|
||||||
|
|
||||||
subscriber = proc do
|
|
||||||
policy = ActionDispatch::ContentSecurityPolicy.new
|
|
||||||
policy.default_src :none
|
|
||||||
policy.plugin_types 'application/pdf'
|
|
||||||
|
|
||||||
request.content_security_policy = policy
|
|
||||||
end
|
|
||||||
|
|
||||||
ActiveSupport::Notifications.subscribed(subscriber, 'send_file.action_controller') do
|
|
||||||
ActiveSupport::Notifications.subscribed(subscriber, 'send_data.action_controller') do
|
|
||||||
block.call
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -6,14 +6,13 @@ class AttachmentsController < ApplicationController
|
||||||
prepend_before_action :authentication_check_only, only: %i[show destroy]
|
prepend_before_action :authentication_check_only, only: %i[show destroy]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
content = @file.content_preview if params[:preview] && @file.preferences[:content_preview]
|
view_type = params[:preview] ? 'preview' : nil
|
||||||
content ||= @file.content
|
|
||||||
|
|
||||||
send_data(
|
send_data(
|
||||||
content,
|
download_file.content(view_type),
|
||||||
filename: @file.filename,
|
filename: download_file.filename,
|
||||||
type: @file.preferences['Content-Type'] || @file.preferences['Mime-Type'] || 'application/octet-stream',
|
type: download_file.content_type,
|
||||||
disposition: sanitized_disposition
|
disposition: download_file.disposition
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ class AttachmentsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
Store.remove_item(@file.id)
|
Store.remove_item(download_file.id)
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -72,18 +71,8 @@ class AttachmentsController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def sanitized_disposition
|
|
||||||
disposition = params.fetch(:disposition, 'inline')
|
|
||||||
valid_disposition = %w[inline attachment]
|
|
||||||
return disposition if valid_disposition.include?(disposition)
|
|
||||||
|
|
||||||
raise Exceptions::Forbidden, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
|
|
||||||
end
|
|
||||||
|
|
||||||
def authorize!
|
def authorize!
|
||||||
@file = Store.find(params[:id])
|
record = download_file&.store_object&.name&.safe_constantize&.find(download_file.o_id)
|
||||||
|
|
||||||
record = @file&.store_object&.name&.safe_constantize&.find(@file.o_id)
|
|
||||||
authorize(record) if record
|
authorize(record) if record
|
||||||
rescue Pundit::NotAuthorizedError
|
rescue Pundit::NotAuthorizedError
|
||||||
raise ActiveRecord::RecordNotFound
|
raise ActiveRecord::RecordNotFound
|
||||||
|
|
|
@ -175,29 +175,11 @@ class TicketArticlesController < ApplicationController
|
||||||
end
|
end
|
||||||
raise Exceptions::Forbidden, 'Requested file id is not linked with article_id.' if !access
|
raise Exceptions::Forbidden, 'Requested file id is not linked with article_id.' if !access
|
||||||
|
|
||||||
# find file
|
|
||||||
file = Store.find(params[:id])
|
|
||||||
|
|
||||||
disposition = sanitized_disposition
|
|
||||||
|
|
||||||
content = nil
|
|
||||||
if params[:view].present? && file.preferences[:resizable] == true
|
|
||||||
if file.preferences[:content_inline] == true && params[:view] == 'inline'
|
|
||||||
content = file.content_inline
|
|
||||||
elsif file.preferences[:content_preview] == true && params[:view] == 'preview'
|
|
||||||
content = file.content_preview
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if content.blank?
|
|
||||||
content = file.content
|
|
||||||
end
|
|
||||||
|
|
||||||
send_data(
|
send_data(
|
||||||
content,
|
download_file.content(params[:view]),
|
||||||
filename: file.filename,
|
filename: download_file.filename,
|
||||||
type: file.preferences['Content-Type'] || file.preferences['Mime-Type'] || 'application/octet-stream',
|
type: download_file.content_type,
|
||||||
disposition: disposition
|
disposition: download_file.disposition
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -278,14 +260,4 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def sanitized_disposition
|
|
||||||
disposition = params.fetch(:disposition, 'inline')
|
|
||||||
valid_disposition = %w[inline attachment]
|
|
||||||
return disposition if valid_disposition.include?(disposition)
|
|
||||||
|
|
||||||
raise Exceptions::Forbidden, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ApplicationController::HasDownload::DownloadFile do
|
||||||
|
subject(:download_file) { described_class.new(stored_file.id, disposition: 'inline') }
|
||||||
|
|
||||||
|
let(:file_content_type) { 'application/pdf' }
|
||||||
|
let(:file_data) { 'A example file.' }
|
||||||
|
let(:file_name) { 'example.pdf' }
|
||||||
|
|
||||||
|
let(:stored_file) do
|
||||||
|
Store.add(
|
||||||
|
object: 'Ticket',
|
||||||
|
o_id: 1,
|
||||||
|
data: file_data,
|
||||||
|
filename: file_name,
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => file_content_type,
|
||||||
|
},
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#disposition' do
|
||||||
|
context "with given object dispostion 'inline'" do
|
||||||
|
context 'with allowed inline content type (from ActiveStorage.content_types_allowed_inline)' do
|
||||||
|
it 'disposition is inline' do
|
||||||
|
expect(download_file.disposition).to eq('inline')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with binary content type (ActiveStorage.content_types_to_serve_as_binary)' do
|
||||||
|
let(:file_content_type) { 'image/svg+xml' }
|
||||||
|
|
||||||
|
it 'disposition forced to attachment' do
|
||||||
|
expect(download_file.disposition).to eq('attachment')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with given object dispostion 'attachment'" do
|
||||||
|
subject(:download_file) { described_class.new(stored_file.id, disposition: 'attachment') }
|
||||||
|
|
||||||
|
it 'disposition is attachment' do
|
||||||
|
expect(download_file.disposition).to eq('attachment')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#content_type' do
|
||||||
|
context 'with none binary content type' do
|
||||||
|
it 'check content type' do
|
||||||
|
expect(download_file.content_type).to eq('application/pdf')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with forced active storage binary content type' do
|
||||||
|
let(:file_content_type) { 'image/svg+xml' }
|
||||||
|
|
||||||
|
it 'check content type' do
|
||||||
|
expect(download_file.content_type).to eq('application/octet-stream')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#content' do
|
||||||
|
context 'with not resizable file' do
|
||||||
|
it 'check that normal content will be returned' do
|
||||||
|
expect(download_file.content('preview')).to eq('A example file.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with image content type' do
|
||||||
|
let(:file_content_type) { 'image/jpg' }
|
||||||
|
let(:file_data) { File.binread(Rails.root.join('test/data/upload/upload2.jpg')) }
|
||||||
|
let(:file_name) { 'image.jpg' }
|
||||||
|
|
||||||
|
it 'check that inline content will be returned' do
|
||||||
|
expect(download_file.content('inline')).to not_eq(file_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'check that preview content will be returned' do
|
||||||
|
expect(download_file.content('preview')).to not_eq(file_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe 'Ticket Article Attachments', type: :request do
|
RSpec.describe 'Ticket Article Attachments', type: :request, authenticated_as: -> { agent } do
|
||||||
|
|
||||||
let(:group) { create(:group) }
|
let(:group) { create(:group) }
|
||||||
|
|
||||||
|
@ -11,107 +11,149 @@ RSpec.describe 'Ticket Article Attachments', type: :request do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'request handling' do
|
describe 'request handling' do
|
||||||
|
context 'with attachment urls' do
|
||||||
|
let(:ticket1) { create(:ticket, group: group) }
|
||||||
|
let(:article1) { create(:ticket_article, ticket: ticket1) }
|
||||||
|
let(:ticket2) { create(:ticket, group: group) }
|
||||||
|
let(:article2) { create(:ticket_article, ticket: ticket2) }
|
||||||
|
|
||||||
it 'does test attachment urls' do
|
let(:store_file_content_type) { 'text/plain' }
|
||||||
ticket1 = create(:ticket, group: group)
|
let!(:store_file) do
|
||||||
article1 = create(:ticket_article, ticket_id: ticket1.id)
|
Store.add(
|
||||||
|
object: 'Ticket::Article',
|
||||||
|
o_id: article1.id,
|
||||||
|
data: 'some content',
|
||||||
|
filename: 'some_file.txt',
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => store_file_content_type,
|
||||||
|
},
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
store1 = Store.add(
|
context 'with one article attachment' do
|
||||||
object: 'Ticket::Article',
|
it 'does test different attachment urls' do
|
||||||
o_id: article1.id,
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}", params: {}
|
||||||
data: 'some content',
|
expect(response).to have_http_status(:ok)
|
||||||
filename: 'some_file.txt',
|
expect('some content').to eq(response.body)
|
||||||
preferences: {
|
|
||||||
'Content-Type' => 'text/plain',
|
|
||||||
},
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article2 = create(:ticket_article, ticket_id: ticket1.id)
|
|
||||||
|
|
||||||
authenticated_as(agent)
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article2.id}/#{store_file.id}", params: {}
|
||||||
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store1.id}", params: {}
|
expect(response).to have_http_status(:forbidden)
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response.body).to match(%r{403: Forbidden})
|
||||||
expect('some content').to eq(@response.body)
|
end
|
||||||
|
end
|
||||||
|
|
||||||
authenticated_as(agent)
|
context 'with attachment from merged ticket' do
|
||||||
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article2.id}/#{store1.id}", params: {}
|
before do
|
||||||
expect(response).to have_http_status(:forbidden)
|
ticket1.merge_to(
|
||||||
expect(@response.body).to match(%r{403: Forbidden})
|
ticket_id: ticket2.id,
|
||||||
|
user_id: 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
ticket2 = create(:ticket, group: group)
|
it 'does test attachment url after ticket merge' do
|
||||||
ticket1.merge_to(
|
get "/api/v1/ticket_attachment/#{ticket2.id}/#{article1.id}/#{store_file.id}", params: {}
|
||||||
ticket_id: ticket2.id,
|
expect(response).to have_http_status(:ok)
|
||||||
user_id: 1,
|
expect('some content').to eq(response.body)
|
||||||
)
|
|
||||||
|
|
||||||
authenticated_as(agent)
|
get "/api/v1/ticket_attachment/#{ticket2.id}/#{article2.id}/#{store_file.id}", params: {}
|
||||||
get "/api/v1/ticket_attachment/#{ticket2.id}/#{article1.id}/#{store1.id}", params: {}
|
expect(response).to have_http_status(:forbidden)
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response.body).to match(%r{403: Forbidden})
|
||||||
expect('some content').to eq(@response.body)
|
|
||||||
|
|
||||||
authenticated_as(agent)
|
# allow access via merged ticket id also
|
||||||
get "/api/v1/ticket_attachment/#{ticket2.id}/#{article2.id}/#{store1.id}", params: {}
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}", params: {}
|
||||||
expect(response).to have_http_status(:forbidden)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(@response.body).to match(%r{403: Forbidden})
|
expect('some content').to eq(response.body)
|
||||||
|
|
||||||
# allow access via merged ticket id also
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article2.id}/#{store_file.id}", params: {}
|
||||||
authenticated_as(agent)
|
expect(response).to have_http_status(:forbidden)
|
||||||
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store1.id}", params: {}
|
expect(response.body).to match(%r{403: Forbidden})
|
||||||
expect(response).to have_http_status(:ok)
|
end
|
||||||
expect('some content').to eq(@response.body)
|
end
|
||||||
|
|
||||||
authenticated_as(agent)
|
context 'with different file content types' do
|
||||||
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article2.id}/#{store1.id}", params: {}
|
context 'without allowed inline file content type' do
|
||||||
expect(response).to have_http_status(:forbidden)
|
it 'disposition can not be inline' do
|
||||||
expect(@response.body).to match(%r{403: Forbidden})
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}?disposition=inline", params: {}
|
||||||
|
expect(response.headers['Content-Disposition']).to include('attachment')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'content-type is correct' do
|
||||||
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}?disposition=inline", params: {}
|
||||||
|
expect(response.headers['Content-Type']).to include('text/plain')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with binary file content type' do
|
||||||
|
let(:store_file_content_type) { 'image/svg+xml' }
|
||||||
|
|
||||||
|
it 'disposition can not be inline' do
|
||||||
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}?disposition=inline", params: {}
|
||||||
|
expect(response.headers['Content-Disposition']).to include('attachment')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'content-type was forced to active storage binary content type' do
|
||||||
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}?disposition=inline", params: {}
|
||||||
|
expect(response.headers['Content-Type']).to include('application/octet-stream')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with allowed inline file content type' do
|
||||||
|
let(:store_file_content_type) { 'application/pdf' }
|
||||||
|
|
||||||
|
it 'disposition is inline' do
|
||||||
|
get "/api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store_file.id}?disposition=inline", params: {}
|
||||||
|
expect(response.headers['Content-Disposition']).to include('inline')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does test attachments for split' do
|
context 'when attachment actions are used' do
|
||||||
email_file_path = Rails.root.join('test/data/mail/mail024.box')
|
it 'does test attachments for split' do
|
||||||
email_raw_string = File.read(email_file_path)
|
email_file_path = Rails.root.join('test/data/mail/mail024.box')
|
||||||
ticket_p, article_p, _user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
email_raw_string = File.read(email_file_path)
|
||||||
|
ticket_p, article_p, _user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||||
|
|
||||||
authenticated_as(agent)
|
get '/api/v1/ticket_split', params: { form_id: '1234-2', ticket_id: ticket_p.id, article_id: article_p.id }, as: :json
|
||||||
get '/api/v1/ticket_split', params: { form_id: '1234-2', ticket_id: ticket_p.id, article_id: article_p.id }, as: :json
|
expect(response).to have_http_status(:ok)
|
||||||
expect(response).to have_http_status(:ok)
|
expect(json_response['assets']).to be_truthy
|
||||||
expect(json_response['assets']).to be_truthy
|
expect(json_response['attachments']).to be_a_kind_of(Array)
|
||||||
expect(json_response['attachments']).to be_a_kind_of(Array)
|
expect(json_response['attachments'].count).to eq(1)
|
||||||
expect(json_response['attachments'].count).to eq(1)
|
expect(json_response['attachments'][0]['filename']).to eq('rulesets-report.csv')
|
||||||
expect(json_response['attachments'][0]['filename']).to eq('rulesets-report.csv')
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does test attachments for forward' do
|
it 'does test attachments for forward' do
|
||||||
email_file_path = Rails.root.join('test/data/mail/mail008.box')
|
email_file_path = Rails.root.join('test/data/mail/mail008.box')
|
||||||
email_raw_string = File.read(email_file_path)
|
email_raw_string = File.read(email_file_path)
|
||||||
_ticket_p, article_p, _user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
_ticket_p, article_p, _user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||||
|
|
||||||
authenticated_as(agent)
|
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: {}, as: :json
|
||||||
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: {}, as: :json
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
expect(response).to have_http_status(:unprocessable_entity)
|
expect(json_response).to be_a_kind_of(Hash)
|
||||||
expect(json_response).to be_a_kind_of(Hash)
|
expect(json_response['error']).to eq('Need form_id to attach attachments to new form.')
|
||||||
expect(json_response['error']).to eq('Need form_id to attach attachments to new form.')
|
|
||||||
|
|
||||||
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: { form_id: '1234-1' }, as: :json
|
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: { form_id: '1234-1' }, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response['attachments']).to be_a_kind_of(Array)
|
expect(json_response['attachments']).to be_a_kind_of(Array)
|
||||||
expect(json_response['attachments']).to be_blank
|
expect(json_response['attachments']).to be_blank
|
||||||
|
|
||||||
email_file_path = Rails.root.join('test/data/mail/mail024.box')
|
email_file_path = Rails.root.join('test/data/mail/mail024.box')
|
||||||
email_raw_string = File.read(email_file_path)
|
email_raw_string = File.read(email_file_path)
|
||||||
_ticket_p, article_p, _user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
_ticket_p, article_p, _user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||||
|
|
||||||
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: { form_id: '1234-2' }, as: :json
|
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: { form_id: '1234-2' }, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response['attachments']).to be_a_kind_of(Array)
|
expect(json_response['attachments']).to be_a_kind_of(Array)
|
||||||
expect(json_response['attachments'].count).to eq(1)
|
expect(json_response['attachments'].count).to eq(1)
|
||||||
expect(json_response['attachments'][0]['filename']).to eq('rulesets-report.csv')
|
expect(json_response['attachments'][0]['filename']).to eq('rulesets-report.csv')
|
||||||
|
|
||||||
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: { form_id: '1234-2' }, as: :json
|
post "/api/v1/ticket_attachment_upload_clone_by_article/#{article_p.id}", params: { form_id: '1234-2' }, as: :json
|
||||||
expect(response).to have_http_status(:ok)
|
expect(response).to have_http_status(:ok)
|
||||||
expect(json_response['attachments']).to be_a_kind_of(Array)
|
expect(json_response['attachments']).to be_a_kind_of(Array)
|
||||||
expect(json_response['attachments']).to be_blank
|
expect(json_response['attachments']).to be_blank
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue