Commit Graph

523 Commits

Author SHA1 Message Date
Mike Dalessio cb61b36715 Allow boosts on cards (#2411)
* Add reactions association to Card model

Adds `has_many :reactions` to Card, matching the implementation in Comment.
This allows cards to be reacted to directly with emoji reactions.

The association:
- Orders reactions chronologically
- Uses polymorphic `:reactable` interface
- Deletes reactions when card is destroyed

Includes test coverage for the new association.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add reactions UI to card detail view

- Create Cards::ReactionsController with turbo stream responses
- Add card reactions views (reactions list, new form, menu partial)
- Position reaction button flush-right when no reactions exist
- Show reactions on bottom-left when present, with button inline
- Handle narrow viewports by flowing button below meta section
- Add controller tests for card reactions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add boost count to card preview

Display reaction count alongside comment count on card tiles in board
columns. Introduces a .card__counts wrapper to group both counts with
proper positioning on all viewport sizes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Consolidate reaction views for cards and comments

Extract shared views to app/views/reactions/ using polymorphic routing.
Both card and comment reactions now render the same partials, with a
helper to compute the correct path prefix for nested routes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix emoji picker width in card reactions

Override .card .popup { inline-size: 260px } for the reaction popup
so the emoji grid displays without horizontal scrollbar.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Hide boost count where comment count is hidden

Add .card__boosts alongside .card__comments in:
- Tray view (display: none)
- Cards with background images (opacity toggle on hover)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix reactions button overlap with zoom button in card footer

When a card has a background image, the footer contains both a reactions
button and a zoom button. Previously they would overlap because the
reactions button was absolutely positioned to the bottom-right.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Tighten up previews

* Move card reactions from meta partial to container

Fixes two issues:

1. Reactions were duplicated each time a card was assigned because the
   turbo stream replaced the meta div with the full perma/meta partial,
   which included reactions outside the replaced element.

2. Draft cards incorrectly showed the boost button because the meta
   partial was shared between published and draft containers.

Moving reactions to _container.html.erb (published cards only) fixes
both issues and keeps the meta partial focused on meta content.

Fixes https://app.fizzy.do/5986089/cards/3837
Fixes https://app.fizzy.do/5986089/cards/3835

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* WIP adjust perma page

* Position and style the footer

* Render the stamp in the card body instead of the footer

* Fix undefined local variable in public cards view

Changed `card` to `@card` when rendering the stamp partial.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Preload card reactions to avoid N+1 queries

Include reactions and their reacters in the preloaded scope, matching
what we already do for comments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add model tests for card and comment reaction cleanup

Test that:
- Creating a card reaction touches the card's last_active_at
- Reactions are deleted when their parent comment is destroyed
- Reactions are deleted when their parent card is destroyed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Minor improvements to reactions code

- Use size instead of count in boosts partial to avoid extra SQL query
  on already-loaded collection
- Add else clause to reaction_path_prefix_for to raise ArgumentError
  for unknown reactable types instead of silently returning nil

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Bump specificity of reaction popup in the card perma

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Smith <andy@37signals.com>
2026-01-23 13:25:55 -05:00
Mike Dalessio 9aa15e9fb2 Forbid comments on draft cards
- Add Card#commentable? method that returns true only for published cards.
- CardsController#create ensures that the card is commentable.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 11:28:26 -05:00
Mike Dalessio bb2d3a59b5 prefactor: update search to use published cards
We're about to make a change to assert that draft cards are not added
to the search index, and so let's make the intention behind these
tests clear first.
2026-01-23 11:07:43 -05:00
Mike Dalessio 6b8a571fd3 Merge pull request #2383 from basecamp/flavorjones/3722-self-assign
Fix "M" hotkey to not use stale user ID from the fragment cache
2026-01-16 13:47:18 -05:00
Mike Dalessio 2527f07365 Fix "M" hotkey using stale user from fragment cache
Add a SelfAssignmentsController to resolve the current user at request
time, avoiding the use of an incorrect user id baked into a cached URL.

ref: #2211 originally added the "M" hotkey
ref: https://app.fizzy.do/5986089/cards/3722
2026-01-16 13:41:33 -05:00
Jorge Manrubia 4ab1e3ff7d Solve problem when Action Text raises on missing attachables
Reverts the previous patch. The problem was that I hadn't update
 Lexxy in the saas version https://github.com/basecamp/lexxy/pull/596
2026-01-16 17:32:41 +01:00
Andy Smith 64fdbf6b8f Clean up blank slates 2026-01-12 15:37:06 -06:00
Stanko Krtalić eceb6c9b43 Add self-service account deletion (#2246)
* Add self-service account deletion

* Disable access to cancelled accounts & implement Stripe interactions

* Add tests

* Fix failing tests

* Remove cancelled accounts from lists

* Fix incorrect redirect

* Use _path instead of _url for consistency

* Don't track how far the inicieration job got

We still want the step tracking so that the job can be interrupted. But, since the scope is idempotent, we don't need to track how far it got.

* Specify the exact time when the data will be deleted

* Fix crash due to unadvancable cursor

* Rename up_for_incineration to due_for_incineration

* Regenrate the schema

* Fix incorrect path check

* Migrate the SQLite schema

* Only show the cancel button on cancellable accounts

* Check that a subscirption method exists before calling it

* Ignore job failures due to missing records when an account gets deleted

* Skip sending notifications on cancelled accounts

* Use collbacks to integrate

* Add a blank line between queue_as and discard_on

* Break checks into methods

* Inline methods

* Rename Account::IncinerateJob

* Run migrations

* Migrate SQLite
2026-01-12 14:21:05 +01:00
Jorge Manrubia f58a1aeb31 Use a dedicated resource for showing cards in draft mode
Mobile team needs this. Also, this lets us get rid from some conditionals for handling
both modes with a single template.

https://3.basecamp.com/2914079/buckets/44843469/messages/9437287330
2026-01-08 10:40:21 +01:00
Jorge Manrubia fb6bcaa18e Merge pull request #2227 from scart88/main
Redirect back to account settings page when the user role is changed …
2026-01-07 16:27:05 +01:00
Rosa Gutierrez 5f390f72df Support local installations where the app is loaded over HTTP
In this case requests won't be performed from a secure context [1] and
the browser won't send the Sec-Fetch-Site header. This means non-GET
requests will be rejected because CSRF protection will fail.

With this change, we allow these requests with missing Sec-Fetch-Site
headers if:
- They happen over HTTP
- The app is not configured to force SSL

The Origin check happens in any case.

[1] https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts#potentially_trustworthy_origins
2026-01-05 18:50:14 +01:00
Stanko Krtalić 24c20ad55f Merge pull request #2244 from basecamp/expose-card-ids-on-comments
Expose the card ID and URL on comments
2025-12-24 08:50:47 +01:00
Stanko K.R. 822c3bb2ad Expose the card ID and URL on comments 2025-12-24 08:45:31 +01:00
Rosa Gutierrez 3fcf5a9d08 Require authorization for direct uploads
Respond with 403 to JSON requests that are unauthorized, instead of
redirecting.
2025-12-23 11:08:51 +01:00
scart88 ba887225a5 Redirect back to account settings page when the user role is changed or when the user is removed from an account. 2025-12-22 10:47:23 +02:00
Jason Zimdars bc4745c6ce Add a test 2025-12-20 18:12:42 -06:00
Stanko K.R. e0270c6c49 Clean up interfaces
I talked to the mobile team, and to keep things simple we agreed to send
the token via a cookie.
2025-12-19 19:21:57 +01:00
Stanko K.R. 23fc7b594f Split tests by controller or responsibility 2025-12-19 19:21:57 +01:00
Stanko K.R. 1a1f4a077b Simplify auth logic 2025-12-19 19:21:57 +01:00
Fernando Olivares cddddcf83a Fix due to unit test when creating with invalid emails 2025-12-19 19:21:57 +01:00
Fernando Olivares fb487f598c Restore sessions_controller test on creating invalid email address 2025-12-19 19:21:57 +01:00
Fernando Olivares be447f90ba Move magic link api tests to their own files 2025-12-19 19:21:57 +01:00
Fernando Olivares 6be20e215b Rename test to clarify what they're about 2025-12-19 19:21:57 +01:00
Fernando Olivares 6e8d6a3df0 Update to always return a pending auth token for JSON responses. 2025-12-19 19:21:57 +01:00
Fernando Olivares fbf829b346 Update API test for cross code 2025-12-19 19:21:57 +01:00
Fernando Olivares 9009e0fb49 Change test expectation on single tenant mode account creation 2025-12-19 19:21:57 +01:00
Fernando Olivares a2333623b6 Add unit tests for the new endpoints 2025-12-19 19:21:57 +01:00
Stanko K.R. c0a0786539 Return the session cookie
We had a call about this. In short, we could reuse access tokens but then the user would see access tokens for every mobile device they have without any indication as to what is going on. So, since this really is just logging in instead of an integration which seems to be the primary purpose of access tokens, we can just use our regular session cookie for authentication.
2025-12-19 19:21:57 +01:00
Stanko K.R. 58a92f0bb7 Add tests for sign in via API 2025-12-19 19:21:57 +01:00
Jorge Manrubia eb1d112013 Merge pull request #2203 from basecamp/remove-unused-param
Remove unused `tag_ids` parameter from `CardsController#update`
2025-12-19 12:16:32 +01:00
Jorge Manrubia 33fc239571 Merge pull request #2140 from dilberryhoundog/fix-stale-account-cache
Fix: resolve stale account names in jump menu and page titles
2025-12-19 11:26:23 +01:00
Rosa Gutierrez 1e640643e9 Remove unused tag_ids parameter from CardsController#update
This is no longer used in the normal flow of the app. The tags are added
via `Cards::TaggingsController`.
2025-12-19 11:16:20 +01:00
Mike Dalessio 2b388dd241 Merge pull request #2164 from basecamp/flavorjones/user-validate-name
Validate User name presence and handle blank names gracefully
2025-12-16 10:49:13 -05:00
Jorge Manrubia ee80b87c8c Add billing system with Stripe
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Jason Zimdars <jz@37signals.com>
2025-12-16 16:44:20 +01:00
Mike Dalessio b75d2ae6d8 Validate User name presence and handle blank names gracefully
Addresses an issue where User#familiar_name assumed `name` was always
present, potentially raising an exception during view rendering. Now
User validates name presence, and User#familiar_name handles blank
strings without error, in case any existing invalid records exist.
2025-12-16 10:44:10 -05:00
Kevin McConnell 741eff7bdc Revert "Merge pull request #1865 from basecamp/public-avatar-caching"
This reverts commit c628f14c01, reversing
changes made to 4bafc73236.
2025-12-15 13:07:13 +00:00
Stanko Krtalić 2058743be9 Merge pull request #2146 from basecamp/show-only-published-cards-on-public-boards
Show only public cards on public boards
2025-12-15 13:26:12 +01:00
Kevin McConnell c628f14c01 Merge pull request #1865 from basecamp/public-avatar-caching
Serve own avatar from its own endpoint
2025-12-15 12:20:28 +00:00
Stanko K.R. 87081aa617 Show only public cards on public boards 2025-12-15 13:15:36 +01:00
Dylan f01a648441 🐛 fix: resolve stale account names in jump menu and page titles
Add account data to fresh_when etag arrays so Rails serves fresh responses after account changes.

- Add @accounts to menus controller etag

- Add Current.account to boards controller etag

- Add ETag cache invalidation tests for both controllers
2025-12-15 15:59:25 +08:00
Mike Dalessio cbaf5d245f Merge pull request #2136 from afurm/test/tenancy-timezone
Add focused tests for tenancy middleware and timezone cookie caching
2025-12-14 16:20:56 -05:00
Jorge Manrubia 31542373ee Merge pull request #2112 from JangoCG/feature/rate-limit-join-codes
feat: protect join codes from brute-force attacks
2025-12-14 09:43:28 +01:00
Jorge Manrubia cac9088ad3 Merge pull request #2105 from seuros/main
feat: expose closed boolean in card JSON API
2025-12-14 09:36:32 +01:00
Jorge Manrubia d7e5d4218f Merge pull request #2032 from tomycostantino/update-columns-on-actions
Fix: board columns actions are stale when moving a column moves
2025-12-14 09:28:57 +01:00
Andrii Furmanets f3bd38ea79 Add tests for tenancy middleware and timezone cookie 2025-12-13 22:10:21 +02:00
Mike Dalessio 139bf3cf81 Validate avatar sizes 2025-12-13 13:05:30 -05:00
Mike Dalessio 9cff236f66 Drop staff restriction in beta and staging
because it was preventing testing of signups.
2025-12-12 15:12:46 -05:00
Rosa Gutierrez 7f5fa6d715 Use Sec-Fetch-Site exclusively for CSRF protection
And close the gap with JSON requests, which shouldn't be allowed if
Sec-Fetch-Site is 'cross-site' or 'none', only if it's empty as this
wouldn't be coming from a browser.
2025-12-12 18:37:32 +01:00
Cengiz Guertusgil 09a2e7d7d7 feat: add rate limit to join codes controller 2025-12-12 17:21:57 +01:00
Abdelkader Boudih b5caa8716d feat: expose closed boolean in card JSON API
Adds `closed` field to card JSON response, allowing API consumers
to detect closed status without parsing the status enum or making
additional API calls.
2025-12-12 10:12:21 +01:00