From e47f2d93eb63c6d8e45c0dffcb75cb8ccdaacd11 Mon Sep 17 00:00:00 2001 From: Rob Zolkos Date: Thu, 5 Mar 2026 20:48:03 -0500 Subject: [PATCH] Add JSON response format to board publication toggle (#2663) --- .../boards/publications_controller.rb | 10 ++++ app/views/boards/_board.json.jbuilder | 2 + docs/API.md | 49 ++++++++++++++++++- .../boards/publications_controller_test.rb | 25 ++++++++++ test/controllers/boards_controller_test.rb | 18 +++++++ 5 files changed, 103 insertions(+), 1 deletion(-) diff --git a/app/controllers/boards/publications_controller.rb b/app/controllers/boards/publications_controller.rb index 9435bd8bf..b2f3d46dd 100644 --- a/app/controllers/boards/publications_controller.rb +++ b/app/controllers/boards/publications_controller.rb @@ -5,10 +5,20 @@ class Boards::PublicationsController < ApplicationController def create @board.publish + + respond_to do |format| + format.turbo_stream + format.json { render partial: "boards/board", locals: { board: @board }, status: :created } + end end def destroy @board.unpublish @board.reload + + respond_to do |format| + format.turbo_stream + format.json { head :no_content } + end end end diff --git a/app/views/boards/_board.json.jbuilder b/app/views/boards/_board.json.jbuilder index fd4e891d7..7c85a1dc5 100644 --- a/app/views/boards/_board.json.jbuilder +++ b/app/views/boards/_board.json.jbuilder @@ -4,4 +4,6 @@ json.cache! board do json.url board_url(board) json.creator board.creator, partial: "users/user", as: :user + + json.public_url published_board_url(board) if board.published? end diff --git a/docs/API.md b/docs/API.md index e55faf400..fae64650a 100644 --- a/docs/API.md +++ b/docs/API.md @@ -469,10 +469,13 @@ __Response:__ "email_address": "david@example.com", "created_at": "2025-12-05T19:36:35.401Z", "url": "http://fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7" - } + }, + "public_url": "http://fizzy.localhost:3006/897362094/public/boards/aB3dEfGhIjKlMnOp" } ``` +The `public_url` field is only present when the board is published. + ### `POST /:account_slug/boards` Creates a new Board in the account. @@ -544,6 +547,50 @@ __Response:__ Returns `204 No Content` on success. +## Board Publications + +Publishing a board makes it publicly accessible via a shareable link, without requiring authentication. Only board administrators can publish or unpublish a board. + +### `POST /:account_slug/boards/:board_id/publication` + +Publishes a board, generating a shareable public link. + +__Response:__ + +``` +HTTP/1.1 201 Created +``` + +```json +{ + "id": "03f5v9zkft4hj9qq0lsn9ohcm", + "name": "Fizzy", + "all_access": true, + "created_at": "2025-12-05T19:36:35.534Z", + "url": "http://fizzy.localhost:3006/897362094/boards/03f5v9zkft4hj9qq0lsn9ohcm", + "creator": { + "id": "03f5v9zjw7pz8717a4no1h8a7", + "name": "David Heinemeier Hansson", + "role": "owner", + "active": true, + "email_address": "david@example.com", + "created_at": "2025-12-05T19:36:35.401Z", + "url": "http://fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7" + }, + "public_url": "http://fizzy.localhost:3006/897362094/public/boards/aB3dEfGhIjKlMnOp" +} +``` + +If the board is already published, the existing publication is returned. + +### `DELETE /:account_slug/boards/:board_id/publication` + +Unpublishes a board, removing public access. + +__Response:__ + +Returns `204 No Content` on success. + ## Cards Cards are tasks or items of work on a board. They can be organized into columns, tagged, assigned to users, and have comments. diff --git a/test/controllers/boards/publications_controller_test.rb b/test/controllers/boards/publications_controller_test.rb index 568c21571..e9dafeb1e 100644 --- a/test/controllers/boards/publications_controller_test.rb +++ b/test/controllers/boards/publications_controller_test.rb @@ -27,6 +27,31 @@ class Boards::PublicationsControllerTest < ActionDispatch::IntegrationTest assert_turbo_stream action: :replace, target: dom_id(@board, :publication) end + test "publish a board via JSON" do + assert_not @board.published? + + assert_changes -> { @board.reload.published? }, from: false, to: true do + post board_publication_path(@board), as: :json + end + + assert_response :created + body = @response.parsed_body + @board.reload + assert_equal @board.name, body["name"] + assert_equal published_board_url(@board), body["public_url"] + end + + test "unpublish a board via JSON" do + @board.publish + assert @board.published? + + assert_changes -> { @board.reload.published? }, from: true, to: false do + delete board_publication_path(@board), as: :json + end + + assert_response :no_content + end + test "publish requires board admin permission" do logout_and_sign_in_as :jz diff --git a/test/controllers/boards_controller_test.rb b/test/controllers/boards_controller_test.rb index 6c171b6b2..7dd2b2f06 100644 --- a/test/controllers/boards_controller_test.rb +++ b/test/controllers/boards_controller_test.rb @@ -250,6 +250,24 @@ class BoardsControllerTest < ActionDispatch::IntegrationTest assert_equal boards(:writebook).name, @response.parsed_body["name"] end + test "show as JSON includes public_url when published" do + board = boards(:writebook) + board.publish + + get board_path(board), as: :json + assert_response :success + assert_equal published_board_url(board), @response.parsed_body["public_url"] + end + + test "show as JSON excludes public_url when not published" do + board = boards(:writebook) + assert_not board.published? + + get board_path(board), as: :json + assert_response :success + assert_nil @response.parsed_body["public_url"] + end + test "create as JSON" do assert_difference -> { Board.count }, +1 do post boards_path, params: { board: { name: "My new board" } }, as: :json