Add JSON response format to entropy endpoints (#2673)

* Add JSON response format to entropy endpoints

Add account settings JSON endpoint returning account info including auto_postpone_period. Add auto_postpone_period to board JSON responses. Add JSON update support to both account and board entropy controllers.

* Add auto_postpone_period to all board response examples in API docs

* Use auto_postpone_period_in_days in JSON responses and API docs

* Use valid period values in permission tests
This commit is contained in:
Rob Zolkos
2026-03-10 11:31:00 -04:00
committed by GitHub
parent 1cf0406d81
commit 8c2318e267
11 changed files with 143 additions and 21 deletions
@@ -4,11 +4,12 @@ class Account::EntropiesController < ApplicationController
before_action :ensure_admin
def update
Current.account.entropy.update!(entropy_params)
@account = Current.account
@account.entropy.update!(entropy_params)
respond_to do |format|
format.html { redirect_to account_settings_path, notice: "Account updated" }
format.json { head :no_content }
format.json { render "account/settings/show", status: :ok }
end
rescue ActiveRecord::RecordInvalid
head :unprocessable_entity
@@ -5,7 +5,10 @@ class Account::SettingsController < ApplicationController
before_action :set_account
def show
@users = @account.users.active.alphabetically.includes(:identity)
respond_to do |format|
format.html { @users = @account.users.active.alphabetically.includes(:identity) }
format.json
end
end
def update
@@ -10,7 +10,7 @@ class Boards::EntropiesController < ApplicationController
respond_to do |format|
format.turbo_stream
format.json { head :no_content }
format.json { render "boards/show", status: :ok }
end
rescue ActiveRecord::RecordInvalid
head :unprocessable_entity
@@ -1 +1,3 @@
json.(Current.account, :name)
json.(@account, :id, :name, :cards_count)
json.created_at @account.created_at.utc
json.auto_postpone_period_in_days @account.entropy.auto_postpone_period_in_days
+1
View File
@@ -1,6 +1,7 @@
json.cache! board do
json.(board, :id, :name, :all_access)
json.created_at board.created_at.utc
json.auto_postpone_period_in_days board.auto_postpone_period_in_days
json.url board_url(board)
json.creator board.creator, partial: "users/user", as: :user
+75 -3
View File
@@ -434,6 +434,7 @@ __Response:__
"name": "Fizzy",
"all_access": true,
"created_at": "2025-12-05T19:36:35.534Z",
"auto_postpone_period_in_days": 30,
"url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm",
"creator": {
"id": "03f5v9zjw7pz8717a4no1h8a7",
@@ -460,6 +461,7 @@ __Response:__
"name": "Fizzy",
"all_access": true,
"created_at": "2025-12-05T19:36:35.534Z",
"auto_postpone_period_in_days": 30,
"url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm",
"creator": {
"id": "03f5v9zjw7pz8717a4no1h8a7",
@@ -484,7 +486,7 @@ Creates a new Board in the account.
|-----------|------|----------|-------------|
| `name` | string | Yes | The name of the board |
| `all_access` | boolean | No | Whether any user in the account can access this board. Defaults to `true` |
| `auto_postpone_period` | integer | No | Number of days of inactivity before cards are automatically postponed |
| `auto_postpone_period_in_days` | integer | No | Number of days of inactivity before cards are automatically postponed (e.g. `30`) |
| `public_description` | string | No | Rich text description shown on the public board page |
__Request:__
@@ -514,7 +516,7 @@ Updates a Board. Only board administrators can update a board.
|-----------|------|----------|-------------|
| `name` | string | No | The name of the board |
| `all_access` | boolean | No | Whether any user in the account can access this board |
| `auto_postpone_period` | integer | No | Number of days of inactivity before cards are automatically postponed |
| `auto_postpone_period_in_days` | integer | No | Number of days of inactivity before cards are automatically postponed (e.g. `30`) |
| `public_description` | string | No | Rich text description shown on the public board page |
| `user_ids` | array | No | Array of *all* user IDs who should have access to this board (only applicable when `all_access` is `false`) |
@@ -524,7 +526,7 @@ __Request:__
{
"board": {
"name": "Updated board name",
"auto_postpone_period": 14,
"auto_postpone_period_in_days": 30,
"public_description": "This is a **public** description of the board.",
"all_access": false,
"user_ids": [
@@ -567,6 +569,7 @@ HTTP/1.1 201 Created
"name": "Fizzy",
"all_access": true,
"created_at": "2025-12-05T19:36:35.534Z",
"auto_postpone_period_in_days": 30,
"url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm",
"creator": {
"id": "03f5v9zjw7pz8717a4no1h8a7",
@@ -591,6 +594,72 @@ __Response:__
Returns `204 No Content` on success.
## Account
### `GET /account/settings`
Returns the current account.
__Response:__
```json
{
"id": "03f5v9zjvypwh0t0e2rfh0h7k",
"name": "37signals",
"cards_count": 5,
"created_at": "2025-12-05T19:36:35.401Z",
"auto_postpone_period_in_days": 30
}
```
The `auto_postpone_period_in_days` is the account-level default in days (e.g. `30`). Cards are automatically moved to "Not Now" after this period of inactivity. Each board can override this with its own value.
### `PUT /account/entropy`
Updates the account-level default auto close period. Requires admin role.
__Request:__
```json
{
"entropy": {
"auto_postpone_period_in_days": 30
}
}
```
__Response:__
Returns the account object:
```json
{
"id": "03f5v9zjvypwh0t0e2rfh0h7k",
"name": "37signals",
"cards_count": 5,
"created_at": "2025-12-05T19:36:35.401Z",
"auto_postpone_period_in_days": 30
}
```
### `PUT /:account_slug/boards/:board_id/entropy`
Updates the auto close period for a specific board. Requires board admin permission.
__Request:__
```json
{
"board": {
"auto_postpone_period_in_days": 90
}
}
```
__Response:__
Returns the board object.
## Webhooks
Webhooks notify another application when something happens on a board. Only account admins can list, view, create, update, delete, or reactivate webhooks.
@@ -757,6 +826,7 @@ __Response:__
"name": "Fizzy",
"all_access": true,
"created_at": "2025-12-05T19:36:35.534Z",
"auto_postpone_period_in_days": 30,
"url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm",
"creator": {
"id": "03f5v9zjw7pz8717a4no1h8a7",
@@ -810,6 +880,7 @@ __Response:__
"name": "Fizzy",
"all_access": true,
"created_at": "2025-12-05T19:36:35.534Z",
"auto_postpone_period_in_days": 30,
"url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm",
"creator": {
"id": "03f5v9zjw7pz8717a4no1h8a7",
@@ -1077,6 +1148,7 @@ __Response:__
"name": "Fizzy",
"all_access": true,
"created_at": "2025-12-05T19:36:35.534Z",
"auto_postpone_period_in_days": 30,
"url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm",
"creator": {
"id": "03f5v9zjw7pz8717a4no1h8a7",
@@ -16,8 +16,9 @@ class Account::EntropiesControllerTest < ActionDispatch::IntegrationTest
test "update as JSON" do
put account_entropy_path, params: { entropy: { auto_postpone_period_in_days: 7 } }, as: :json
assert_response :no_content
assert_response :success
assert_equal 7.days, entropies("37s_account").reload.auto_postpone_period
assert_equal 7, @response.parsed_body["auto_postpone_period_in_days"]
end
test "update requires admin" do
@@ -35,4 +36,20 @@ class Account::EntropiesControllerTest < ActionDispatch::IntegrationTest
assert_response :unprocessable_entity
assert_equal original_period, entropies("37s_account").reload.auto_postpone_period
end
test "update as JSON rejects invalid auto_postpone_period" do
original_period = entropies("37s_account").auto_postpone_period
put account_entropy_path, params: { entropy: { auto_postpone_period_in_days: 1 } }, as: :json
assert_response :unprocessable_entity
assert_equal original_period, entropies("37s_account").reload.auto_postpone_period
end
test "update as JSON requires admin" do
logout_and_sign_in_as :david
put account_entropy_path, params: { entropy: { auto_postpone_period_in_days: 7 } }, as: :json
assert_response :forbidden
end
end
@@ -16,13 +16,6 @@ class Account::SettingsControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to account_settings_path
end
test "show as JSON" do
get account_settings_path, as: :json
assert_response :success
assert_equal Current.account.name, @response.parsed_body["name"]
end
test "update as JSON" do
put account_settings_path, params: { account: { name: "New Account Name" } }, as: :json
@@ -36,4 +29,13 @@ class Account::SettingsControllerTest < ActionDispatch::IntegrationTest
put account_settings_path, params: { account: { name: "New Account Name" } }
assert_response :forbidden
end
test "show as JSON" do
get account_settings_path, as: :json
assert_response :success
assert_equal Current.account.name, @response.parsed_body["name"]
assert_equal Current.account.cards_count, @response.parsed_body["cards_count"]
assert_equal Current.account.entropy.auto_postpone_period_in_days, @response.parsed_body["auto_postpone_period_in_days"]
end
end
@@ -41,14 +41,14 @@ class FlatJsonParamsTest < ActionDispatch::IntegrationTest
put board_entropy_path(board), params: { auto_postpone_period_in_days: 90 }, as: :json
assert_response :no_content
assert_response :success
assert_equal 90.days, board.entropy.reload.auto_postpone_period
end
test "update account entropy with flat JSON" do
put account_entropy_path, params: { auto_postpone_period_in_days: 7 }, as: :json
assert_response :no_content
assert_response :success
assert_equal 7.days, Current.account.entropy.reload.auto_postpone_period
end
@@ -17,10 +17,13 @@ class Boards::EntropiesControllerTest < ActionDispatch::IntegrationTest
end
test "update as JSON" do
assert_no_difference -> { Current.account.entropy.reload.auto_postpone_period } do
put board_entropy_path(@board), params: { board: { auto_postpone_period_in_days: 90 } }, as: :json
assert_response :no_content
assert_response :success
assert_equal 90.days, @board.entropy.reload.auto_postpone_period
assert_equal 90, @response.parsed_body["auto_postpone_period_in_days"]
end
end
test "update requires board admin permission" do
@@ -42,4 +45,24 @@ class Boards::EntropiesControllerTest < ActionDispatch::IntegrationTest
assert_response :unprocessable_entity
assert_equal original_period, @board.entropy.reload.auto_postpone_period
end
test "update as JSON rejects invalid auto_postpone_period" do
original_period = @board.entropy.auto_postpone_period
put board_entropy_path(@board), params: { board: { auto_postpone_period_in_days: 1 } }, as: :json
assert_response :unprocessable_entity
assert_equal original_period, @board.entropy.reload.auto_postpone_period
end
test "update as JSON requires board admin permission" do
logout_and_sign_in_as :jz
original_period = @board.entropy.auto_postpone_period
put board_entropy_path(@board), params: { board: { auto_postpone_period_in_days: 7 } }, as: :json
assert_response :forbidden
assert_equal original_period, @board.entropy.reload.auto_postpone_period
end
end
@@ -258,6 +258,7 @@ class BoardsControllerTest < ActionDispatch::IntegrationTest
get board_path(boards(:writebook)), as: :json
assert_response :success
assert_equal boards(:writebook).name, @response.parsed_body["name"]
assert_equal boards(:writebook).auto_postpone_period_in_days, @response.parsed_body["auto_postpone_period_in_days"]
end
test "show as JSON includes public_url when published" do