Files
leadchat/spec/controllers/api/v1/accounts/articles_controller_spec.rb
Vinay Keerthi f455e7994e fix: respect status parameter when creating articles via API (#12846)
## Description

The Articles API was ignoring the `status` parameter when creating new
articles. All articles were forced to be drafts due to a hardcoded
`@article.draft!` call in the controller, even when users explicitly
sent `status: 1` (published) in their API request.

This PR removes the hardcoded draft enforcement and allows the status
parameter to be respected while maintaining backward compatibility.

Fixes #12063

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

**Before:**
- API POST with `status: 1` → Created as draft (ignored parameter)
- API POST without status → Created as draft

**After:**
- API POST with `status: 1` → Created as published 
- API POST without status → Created as draft (backward compatible) 
- UI creates articles → Still creates as draft (UI doesn't send status)


**Tests run:**
```bash
bundle exec rspec spec/controllers/api/v1/accounts/articles_controller_spec.rb
# 17 examples, 0 failures
```

Updated tests:
1. Changed 2 existing tests that were verifying the broken behavior
(expecting draft when published was sent)
2. Added new test to verify articles default to draft when status is not
provided
3. All existing tests pass, confirming backward compatibility

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2025-11-13 12:07:24 +05:30

297 lines
13 KiB
Ruby

require 'rails_helper'
RSpec.describe 'Api::V1::Accounts::Articles', type: :request do
let(:account) { create(:account) }
let(:agent) { create(:user, account: account, role: :agent) }
let(:admin) { create(:user, account: account, role: :administrator) }
let!(:portal) { create(:portal, name: 'test_portal', account_id: account.id) }
let!(:category) { create(:category, name: 'category', portal: portal, account_id: account.id, locale: 'en', slug: 'category_slug') }
let!(:article) { create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id) }
describe 'POST /api/v1/accounts/{account.id}/portals/{portal.slug}/articles' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles", params: {}
expect(response).to have_http_status(:unauthorized)
end
end
context 'when it is an authenticated user' do
it 'creates article' do
article_params = {
article: {
category_id: category.id,
description: 'test description',
title: 'MyTitle',
slug: 'my-title',
content: 'This is my content.',
status: :published,
author_id: agent.id,
position: 3
}
}
post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
params: article_params,
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('MyTitle')
expect(json_response['payload']['status']).to eql('published')
expect(json_response['payload']['position']).to be(3)
end
it 'creates article even if category is not provided' do
article_params = {
article: {
category_id: nil,
description: 'test description',
title: 'MyTitle',
slug: 'my-title',
content: 'This is my content.',
status: :published,
author_id: agent.id,
position: 3
}
}
post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
params: article_params,
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('MyTitle')
expect(json_response['payload']['status']).to eql('published')
expect(json_response['payload']['position']).to be(3)
end
it 'creates article as draft when status is not provided' do
article_params = {
article: {
category_id: category.id,
description: 'test description',
title: 'DraftTitle',
slug: 'draft-title',
content: 'This is my draft content.',
author_id: agent.id
}
}
post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
params: article_params,
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('DraftTitle')
expect(json_response['payload']['status']).to eql('draft')
end
it 'associate to the root article' do
root_article = create(:article, category: category, slug: 'root-article', portal: portal, account_id: account.id, author_id: agent.id,
associated_article_id: nil)
parent_article = create(:article, category: category, slug: 'parent-article', portal: portal, account_id: account.id, author_id: agent.id,
associated_article_id: root_article.id)
article_params = {
article: {
category_id: category.id,
description: 'test description',
title: 'MyTitle',
slug: 'MyTitle',
content: 'This is my content.',
status: :published,
author_id: agent.id,
associated_article_id: parent_article.id
}
}
post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
params: article_params,
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('MyTitle')
category = Article.find(json_response['payload']['id'])
expect(category.associated_article_id).to eql(root_article.id)
end
it 'associate to the current parent article' do
parent_article = create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id, associated_article_id: nil)
article_params = {
article: {
category_id: category.id,
description: 'test description',
title: 'MyTitle',
slug: 'MyTitle',
content: 'This is my content.',
status: :published,
author_id: agent.id,
associated_article_id: parent_article.id
}
}
post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
params: article_params,
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql('MyTitle')
category = Article.find(json_response['payload']['id'])
expect(category.associated_article_id).to eql(parent_article.id)
end
end
end
describe 'PUT /api/v1/accounts/{account.id}/portals/{portal.slug}/articles/{article.id}' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
put "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles/#{article.id}", params: {}
expect(response).to have_http_status(:unauthorized)
end
end
context 'when it is an authenticated user' do
it 'updates article' do
article_params = {
article: {
title: 'MyTitle2',
status: 'published',
description: 'test_description',
position: 5
}
}
expect(article.title).not_to eql(article_params[:article][:title])
put "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles/#{article.id}",
params: article_params,
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eql(article_params[:article][:title])
expect(json_response['payload']['status']).to eql(article_params[:article][:status])
expect(json_response['payload']['position']).to eql(article_params[:article][:position])
end
end
end
describe 'DELETE /api/v1/accounts/{account.id}/portals/{portal.slug}/articles/{article.id}' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
delete "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles/#{article.id}", params: {}
expect(response).to have_http_status(:unauthorized)
end
end
context 'when it is an authenticated user' do
it 'deletes category' do
delete "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles/#{article.id}",
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
deleted_article = Article.find_by(id: article.id)
expect(deleted_article).to be_nil
end
end
end
describe 'GET /api/v1/accounts/{account.id}/portals/{portal.slug}/articles' do
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles"
expect(response).to have_http_status(:unauthorized)
end
end
context 'when it is an authenticated user' do
it 'get all articles' do
article2 = create(:article, account_id: account.id, portal: portal, category: category, author_id: agent.id)
expect(article2.id).not_to be_nil
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
headers: admin.create_new_auth_token,
params: {}
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload'].count).to be 2
end
it 'get all articles with uncategorized articles' do
article2 = create(:article, account_id: account.id, portal: portal, category: nil, locale: 'en', author_id: agent.id)
expect(article2.id).not_to be_nil
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
headers: admin.create_new_auth_token,
params: {}
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload'].count).to be 2
expect(json_response['payload'][0]['id']).to eq article2.id
expect(json_response['payload'][0]['category']['id']).to be_nil
end
it 'get all articles with searched params' do
article2 = create(:article, account_id: account.id, portal: portal, category: category, author_id: agent.id)
expect(article2.id).not_to be_nil
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
headers: admin.create_new_auth_token,
params: { category_slug: category.slug }
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload'].count).to be 2
end
it 'get all articles with searched text query' do
article2 = create(:article,
account_id: account.id,
portal: portal,
category: category,
author_id: agent.id,
content: 'this is some test and funny content')
expect(article2.id).not_to be_nil
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles",
headers: admin.create_new_auth_token,
params: { query: 'funny' }
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload'].count).to be 1
expect(json_response['meta']['all_articles_count']).to be 2
expect(json_response['meta']['articles_count']).to be 1
expect(json_response['meta']['mine_articles_count']).to be 0
end
end
describe 'GET /api/v1/accounts/{account.id}/portals/{portal.slug}/articles/{article.id}' do
it 'get article' do
article2 = create(:article, account_id: account.id, portal: portal, category: category, author_id: agent.id)
expect(article2.id).not_to be_nil
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles/#{article2.id}",
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['title']).to eq(article2.title)
expect(json_response['payload']['id']).to eq(article2.id)
end
it 'get associated articles' do
root_article = create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id, associated_article_id: nil)
child_article_1 = create(:article, slug: 'child-1', category: category, portal: portal, account_id: account.id, author_id: agent.id,
associated_article_id: root_article.id)
child_article_2 = create(:article, slug: 'child-2', category: category, portal: portal, account_id: account.id, author_id: agent.id,
associated_article_id: root_article.id)
get "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/articles/#{root_article.id}",
headers: admin.create_new_auth_token
expect(response).to have_http_status(:success)
json_response = response.parsed_body
expect(json_response['payload']['associated_articles'].length).to eq(2)
associated_articles_ids = json_response['payload']['associated_articles'].pluck('id')
expect(associated_articles_ids).to contain_exactly(child_article_1.id, child_article_2.id)
expect(json_response['payload']['id']).to eq(root_article.id)
end
end
end
end