Commit Graph
13789 Commits
Author SHA1 Message Date
Osama Sayegh 4c9ceb97b8 FIX: Consider all eligible notification types when notifying about a post (#36472) 2025-12-08 08:41:14 +11:00
Amanda Alves BranquinhoandGerhard Schlager 15e267f791 DEV: Optimize core user merger (#36455)
Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org>
2025-12-05 14:45:54 -03:00
Tethys Plex 5dba734bc3 FIX: Ensure tag diffs use persisted topic tags (#35187)
Prevents small_action creation and notifications when restricted tags
are rejected.
2025-12-04 16:58:10 +01:00
Alan Guo Xiang Tan 010126bd70 DEV: Fix state leak in MiniSchedulerLongRunningJobLogger spec (#36453)
`MiniScheduler` writes to Redis so we need to flush it at the end of
each test.
2025-12-04 16:47:01 +08:00
Bannon Tanner 4195aed70c FIX: update rack sendfile middleware for x-accel-redirect (#36354)
Background: mp4 video type was not playing in Safari on macOS or iOS if
served from Discourse instead of S3. The response was a 200 instead of a
206 for partial response. There was a
[change](https://github.com/rack/rack/compare/v2.2.19...v2.2.20) in Rack
v2.2.20 that forces apps to be explicit about X-Accel-Redirect on the
Sendfile command

Change: Be explicit about enabling X-Accel-Redirect in application
middleware for Rack::Sendfile.
Also add guards for environment to not get `X-Accel-Mapping header
missing` on local env logs
2025-12-03 14:01:49 -06:00
Gabriel Grubba b72cfbaa7a FEATURE: Add modifier hook for tags being saved (#36400)
This PR adds the `:tags_for_saving` modifier hook to allow plugins to
modify the list of tags before they are saved to a topic. This is useful
for scenarios where additional tags need to be added or existing tags
need to be altered based on custom logic.

example:

```ruby
register_modifier(:tags_for_saving) do |saving_tags, original_tags, guardian, opts|
  # Custom logic to modify saving_tags
  saving_tags << "additional-tag" unless saving_tags.include?("additional-tag")
  saving_tags
end
```
2025-12-03 13:40:49 -03:00
Loïc Guitaut a8b312426b DEV: Add symbol to ActiveModel attribute types (#36420)
`ActiveModel` doesn’t have a `symbol` type by default, but it can be
quite handy for contracts from our service framework.

This way, it’s easy to get a symbol from an attribute. Any non-blank
value will get converted to a symbol by being converted to a string
before. A blank value will return `nil`.
2025-12-03 10:57:44 +01:00
Sam b9056effe4 FEATURE: improve bulk selection in search (#36373)
- Allow deleting posts vs topics
- New operator for in:replies so you can search replies only
2025-12-03 19:18:43 +11:00
Alan Guo Xiang Tan 6a4ea0a7b9 DEV: Refactor ApplicationHelper#server_plugin_outlet take 2 (#36418)
Take 1 reverted in
https://github.com/discourse/discourse/commit/dc97318ad12c16d28d2e80b944278aaed2c10d24
as it ended up causing a memory leak.
2025-12-03 15:55:39 +08:00
Osama Sayegh dc97318ad1 Revert "DEV: Refactor ApplicationHelper#server_plugin_outlet (#36307)" (#36417) 2025-12-03 15:16:34 +08:00
David Battersby 45c2a725d0 DEV: remove magnific lightbox (#36375)
Now that we have transitioned lightbox to PhotoSwipe, we can remove the
Magnific library and the `SiteSetting.experimental_lightbox` code paths.

The site setting value will be fully removed from the database in a
follow up migration.

Internal ref - /t/165699
2025-12-03 09:57:53 +04:00
Natalie Tay 0538dba91b FIX: Don't show empty switcher (#36407)
There exists a state where the language switcher would be clickable but
have an empty list as the language list will not be returned when the
setting is disabled. This is now fixed.
2025-12-03 11:46:01 +08:00
Blake Erickson e44be4eab5 DEV: Sync optimized videos secure status (#36403)
Uploads in the composer are marked as `secure: true` because they are
drafts. Later when they are published their secure status is changed,
but optimized videos were not being updated as well.
2025-12-02 18:56:19 -07:00
Jarek Radosz b81f4104ef DEV: Normalize (ok)lch values in computed style matcher (#36404)
We can't compare **computed** (ok)lch values since those are not stable.
For example, one of the values used in "User color palette selector"
spec:

* `oklch(0.92 0.0708528 68.5036)` - the value hardcoded in the spec
* `oklch(0.92 0.0708528 68.5037)` - the value on my machine (the spec
was failing)
* `oklch(0.92 0.070857 68.5063)` - the value after updating pitchfork
(that's why the [PR](https://github.com/discourse/discourse/pull/36352)
is failing)

All those are effectively the same. When converted to hex they all
resolve to `#ffddb2`.
2025-12-03 02:13:09 +01:00
Kris bed4079cdb UX: update heading style in review queue refresh (#36391)
This inverts the flag header colors so we get clearer separation between
items, and removes the color coding from the flag type. The header is
also now a little shorter which felt right due to the higher contrast.

Before:

<img width="1704" height="1570" alt="image"
src="https://github.com/user-attachments/assets/59159044-26a0-42bb-b5b8-d1407b1ef08a"
/>


After:

<img width="1702" height="1486" alt="image"
src="https://github.com/user-attachments/assets/3bb6fc01-9cfd-494d-9d63-f4e26e2106b7"
/>
2025-12-02 16:54:00 -05:00
Régis Hanol 734699ef19 DEV: remove leftover "puts" in specs (#36387) 2025-12-02 18:16:24 +01:00
Régis Hanol 05552b190d DEV: Move test cleanup to correct scope in tasks/uploads_spec.rb (#36386)
The "after" block that removes the JSON file was inside the "when
login_required" context, but tests outside that context also create the
file. This caused leftover files when running tests in parallel with
bin/turbo_spec.
2025-12-02 17:45:28 +01:00
Jarek Radosz d30d4e764f DEV: Add a computed style matcher (#36381) 2025-12-02 15:14:08 +01:00
Krzysztof Kotlarek 24cbeeddbf UX: Display moderation history in review insights (#36370)
Adds a new "Moderation history" section to the review queue insights tab
that displays:
- Number of times the user has been silenced
- Number of times the user has been suspended
- Number of rejected posts

<img width="806" height="440" alt="Screenshot 2025-12-02 at 11 19 22 am"
src="https://github.com/user-attachments/assets/280891fc-2019-43b3-abf5-8848dc57d96e"
/>
2025-12-02 11:58:41 +08:00
Blake Erickson e4dc604f00 DEV: Ensure optimized videos have the correct acl (#36364)
Ensure optimized_upload inherits the secure flag from the original
upload
when created. This prevents ACL mismatches that cause 403 errors when
accessing converted videos, especially when video conversion completes
before the post is published.
2025-12-01 19:50:08 -07:00
Krzysztof Kotlarek f97c5fe21c UX: Display user's email in review queue insights (#36344)
When moderators review flagged posts, they can now see the email address of the flagged user in the user insights section. This additional context helps moderators more quickly identify spam accounts and determine if a post should be flagged as spam.
Feature respects `moderators_view_emails` site setting. 
  
<img width="795" height="650" alt="Screenshot 2025-12-01 at 4 14 38 pm"
src="https://github.com/user-attachments/assets/f3db2889-e18a-4941-8a4c-bf777a1fb81b"
/>
2025-12-02 09:10:56 +08:00
Blake Erickson 46cdf7b939 DEV: Add video conversion support for chat messages (#36275)
Video conversion was happening already for chat videos, but was not
updating the chat messages. Now chat messages will be updated with the
optimized video.
2025-12-01 12:34:56 -07:00
Régis Hanol f453463cfb FIX: Emoji.exists? should be consistent with Emoji[] (#36347)
This ensures that both "Emoji.exists?" and "Emoji[]" use the same lookup
"algorithm" when trying to match an emoji "name" with an emoji in the
database.

This ensures the normalization of the name into a single value handles
both skin tones and aliases.

Closes #33130
2025-12-01 18:58:30 +01:00
Gabriel Grubba 568afbae47 DEV: Add optional s3_stale_while_revalidate and s3_max_age for uploads (#36298)
With this change, S3's `stale-while-revalidate` and `max-age` response
directives can be controlled.

By default, off for `stale-while-revalidate`, and both are hidden site
settings.
2025-12-01 14:57:50 -03:00
Yuriy Kurant abbd5f2426 FIX: edit theme navigation link should be in active state (#36350)
When editing a theme, an active state for `Themes & components` was
lost. This change keeps the link active.

|Before|After|
|---|---|
|<img width="783" height="468" alt="Screenshot 2025-12-01 at 21 13 22"
src="https://github.com/user-attachments/assets/b980a608-8817-42fb-8427-80cb48bcdb68"
/>|<img width="744" height="460" alt="Screenshot 2025-12-01 at 21 14 53"
src="https://github.com/user-attachments/assets/194a414d-1cce-4a47-92ba-d9a0ea080102"
/>|
2025-12-01 22:40:09 +08:00
Gerhard Schlager 2421612d90 DEV: Check existence of wizard_js only in client.en.yml (#36349) 2025-12-01 14:46:59 +01:00
Ted Johansson 53b806d4b2 DEV: Deprecate the assignment of nil to site settings (#36093)
We currently allow assigning nil to site settings, which lead to implicit casting to other values. Forcing explicit handling of this case helps avoid accidental misconfiguration.

This should not affect changing site settings from the UI, which is already well-behaved in this regard.
2025-12-01 15:04:23 +08:00
Krzysztof Kotlarek a4b3f74497 FEATURE: Add claim history to reviewable timeline (#36243)
This enhances the reviewable timeline by tracking and displaying when
reviewables are claimed and unclaimed by moderators.

Changes include:
- Modified reviewable_claimed_topics_controller to send user information
and claimed status for both claim and unclaim operations
- Added reviewable_histories to ReviewableSerializer to expose history
data
- Updated ReviewableItem component to track claim/unclaim events via
MessageBus and add them to the reviewable's history
- Fixed MessageBus initialization to start in Rails testing environment
to support system tests

<img width="1111" height="741" alt="Screenshot 2025-11-26 at 3 24 28 pm"
src="https://github.com/user-attachments/assets/84e0bf2a-adb3-4ed2-93cb-eda6d771f5af"
/>
2025-12-01 14:58:43 +08:00
Alan Guo Xiang Tan f62da89a15 DEV: Refactor ApplicationHelper#server_plugin_outlet (#36307)
Avoid using Rails internal APIs and rely on
`ActionController::Base.append_view_paths` instead.
2025-12-01 14:10:16 +08:00
Ted Johansson 540dc392cd FEATURE: Add new configurable moderation guide (#36287)
This PR adds a new site setting for configuring a community moderation topic that will be linked from the reviewable sidebar.

It involves adding a new site setting type "topic" which uses the TopicChooser component in the front-end.
2025-12-01 10:30:32 +08:00
Bannon TannerandGabriel Grubba e2af9b5e0b Revert "FIX: update rack sendfile middleware for x-accel-redirect (#36322)
(#36279)"

This reverts commit 015d2e17cf.

Co-authored-by: Gabriel Grubba <70247653+Grubba27@users.noreply.github.com>
2025-11-28 13:31:26 -06:00
Sérgio Saquetim 711bed90dc DEV: Sync category permissions when group membership changes
Syncs category permission info to the client when a user is added to or removed from a group.

* Add Category.set_permission! to compute and set category.permission (full, create_post, readonly, or nil) using Guardian checks.
* Change Group#add and Group#remove to guard against nil users and duplicate membership, send membership notifications when requested, and invoke a new publish flow after membership changes.
* Add Group helpers send_membership_notification and publish_category_updates; publish_category_updates serializes updated category permissions and a deleted_categories list and publishes them to the user via MessageBus, falling back to a client refresh when the group exceeds Group::PUBLISH_CATEGORIES_LIMIT.
* Ensure add/remove trigger publishing so the client receives permission updates or removals immediately after membership changes.
* Update tests to verify Category.set_permission! behavior for admin/full/create_post/readonly/none scenarios and to assert MessageBus payloads for category permission updates, deletions, and the refresh fallback.
2025-11-28 15:44:33 -03:00
Kris 75628079c1 FEATURE: include IP info in refreshed reviewable insight tab (#36273)
Requires `Reviewable UI refresh` to be enabled. 

This removes the "IP Lookup" button and includes an IP lookup when a
reviewer switches to the "Insights" tab

<img width="600" alt="image"
src="https://github.com/user-attachments/assets/fa8562e1-0eb3-474c-9a08-f5059a291a99"
/>

The duplicate account check is included behind a link that opens a
modal, which allows the initial IP lookup to happen separately (and a
little faster)

<img width="600" alt="image"
src="https://github.com/user-attachments/assets/e04ad1f5-e37b-47ce-892c-be6d8750cb82"
/>

I've also split out the duplicate account table into a separate
component so we can reuse it in this modal and on individual users'
admin pages.

A couple other minor changes: 
* Updated the unlisted text, technically an unlisted topic *is* public
as long as you have the link
* Hid the "flag count" insight if there's only 1 flagger, this should be
apparent based on the flag existing at all so the insight only seems
useful to indicate that multiple people flagged it
2025-11-28 11:24:02 -05:00
Bannon Tanner 015d2e17cf FIX: update rack sendfile middleware for x-accel-redirect (#36279)
Background: mp4 video type was not playing in Safari on macOS or iOS if
served from Discourse instead of S3. The response was a 200 instead of a
206 for partial response. There was a
[change](https://github.com/rack/rack/compare/v2.2.19...v2.2.20) in Rack
v2.2.20 that forces apps to be explicit about `X-Accel-Redirect` on the
Sendfile command

Change: Be explicit about enabling `X-Accel-Redirect` in application
middleware for `Rack::Sendfile`

Report:
https://meta.discourse.org/t/issue-playing-videos-on-ios-and-macos-safari/387497
2025-11-28 09:08:06 -06:00
small-lovely-cat 1d592aec3e FIX: Lightbox failed to start in components due to null imgEl element. (#36310)
#36156 introduced `const imgEl = el.tagName === "IMG" ? el :
el.querySelector("img");` to the lightbox component to capture the image
element on the page.

However, when it comes to applying the lightbox to an element without
`<img>` , i.e., discourse solved, backquote, activity page, etc. The
`imgEl` will turn into null, and the following `data.origSrc =
imgEl.getAttribute("data-orig-src");` will result in `Uncaught
TypeError: can't access property "getAttribute", imgEl is null`,
preventing the lightbox from starting properly.

This commit add a safety check when `imgEl` is used, and add fallback
logic to null if the `<img>` element doesn't exist.

Before:
<img width="1603" height="845" alt="image"
src="https://github.com/user-attachments/assets/6e588a00-53bf-410a-bbac-3f24a820d494"
/>

After:
<img width="1603" height="848" alt="image"
src="https://github.com/user-attachments/assets/07868ade-0e1b-43d2-83cc-c2fec3da9109"
/>
2025-11-28 14:19:47 +01:00
Régis Hanol 0ead2f8722 FEATURE: add support for "updating" an application on discourse id (#35384)
This will automatically update the IDP whenever at least one of the
following site setting changes

- title
- description
- logo url
- small logo url

Ref - meta/t/385471/2

---

Depends on https://github.com/discourse/discourse-login/pull/81
2025-11-28 13:07:51 +01:00
Loïc Guitaut 4791accfa1 FIX: Fallback to upload URLs when SHA1 doesn’t match (#36299)
Currently, when uploads have a different SHA1 in their URL from the one
that has been computed (it can happen with secure uploads), and those
uploads are images, then the cooked post processor won’t link them
properly to their post. The post has them as `Post#uploads` but not as
`Post#image_upload`. This in turn will make the associated topic
thumbnail-less when the post is the first one.

To address the issue, it’s a matter of adding fallbacks to
`CookedPostProcessor#update_post_image` when fetching the uploads. This
is something we already do in
`HasPostUploadReferences#link_post_uploads`.
2025-11-28 12:25:38 +01:00
Alan Guo Xiang Tan e4be1b4bee DEV: Refactor and add missing tests for upload type in objects schema (#36285)
Follow-up to 664e6244b0

1. Introduce `SchemaSettingsObjectValidator.property_values_of_type` to
   reduce logic duplication across `SiteSetting`, `ThemeSiteSetting` and
`ThemeSetting` which all supports objects schema setting.

2. Add missing test cases for `ThemeSiteSetting` and `ThemeSetting`
2025-11-28 04:02:23 +08:00
Osama Sayegh 168c1fee94 PERF: Fix memory leak in server-side plugin outlets (#36284)
We've identified a memory leak that occurs when rendering custom
templates into server-side plugin outlets where each rendered template
leaves at least 1 object in the heap that can never be claimed back by
the GC. This happens due to ActionView's caching of compiled template
and is [intended
behavior](https://github.com/rails/rails/issues/33019#issuecomment-409379676),
however in our case, this is problematic because it can make memory
usage grow extremely fast if a plugin connects to an outlet on a page
that gets visited a lot (e.g. the topic page).

This PR moves away from using ActionView's `render` method, which
creates a new `ActionView::Template` instance which gets compiled and
cached, to a custom solution that creates an `ActionView::Template`
instance only once for a given template and reuses the instance when the
template is needed again.

In development, to avoid having to restart the server when changing a
plugin's template, the `PLUGIN_OUTLET_TEMPLATE_CACHE` constant where
`ActionView::Template` are kept, gets reset on code reload via the
`to_prepare` hook.

Internal topic: t/169204.
2025-11-27 16:03:05 +03:00
Alan Guo Xiang Tan 0464682ab8 FIX: BadgeQueries.sharing_badge not counting unique visitors (#36281)
Prior to this change, the SQL query string returned by
`BadgeQueries.sharing_badge`
was simply counting the number of `incoming_links` rows for a given post
and sharer (user_id). This is however incorrect as the sharing badges
description states that the visitors have to be unique.

This commit updates `BadgeQueries.sharing_badge` to count only unique
(ip_address, current_user_id) pairs in incoming_links, so repeated hits
from the same visitor no longer inflate share badge counts.
2025-11-27 14:37:27 +08:00
Ted Johansson 12fdb69279 DEV: Allow specifying dependent settings in configuration (#36061)
Currently, when updating several settings in bulk, they are updated in a non-deterministic order. This means that if Setting B depends on Setting A being enabled, and we try to enable B and A together, there's a chance that fails. This is why we need to remove the up-front values_are_valid policy from the service as well.

This change first sorts the settings topologically, i.e. in order of dependency, so if C depends on B depends on A, then we will update them in order [A, B, C].
2025-11-27 13:23:43 +08:00
Gary Pendergast ced8c2c127 FIX: UserDestroyer should unclaim any claimed reviewables. (#36277)
When a user has been destroyed, any claimed reviewables belonging to
that user are partially orphaned, which the review queue doesn't know
how to handle. Ensuring those reviewables are unclaimed (and cleaning up
any orphaned claims on existing sites) ensures the review queue is able
to cleanly handle claimed reviewables.
2025-11-27 13:54:48 +11:00
Keegan George 6a2d2b2b51 FIX: GlobalSetting should treat negative integers as integers (#36276)
## 🔍 Overview
`GlobalSetting` was converting negative integers into strings. This
update ensures that negative integers are treated as the correct type.
2025-11-26 15:52:19 -08:00
Amanda Alves Branquinho 2c863c6232 FIX: blocks post action merge for duplicated flags (#36265)
- Blocks user action merge if source and target users has flags for the
same post. As a result, after merging 2 users, only 1 flag should
persist.
2025-11-26 16:17:57 -03:00
Sérgio Saquetim c2c1cd978e DEV: Purge the widget rendering system (#36109)
This commit removes the legacy widget rendering system from the Discourse codebase.

See the topics below for more information:

- https://meta.discourse.org/t/upcoming-eol-for-the-widget-rendering-system/375332
- https://meta.discourse.org/t/upcoming-post-stream-changes-how-to-prepare-themes-and-plugins/372063
2025-11-26 16:10:02 -03:00
Régis Hanol 9eb2a66879 FIX: update PM tracking state when marking messages as unread (#36258)
When marking a private message as unread via "destroy_timings", two
  issues prevented old PMs from appearing in the Unread list:

1. PostTiming.destroy_for used Topic.listable_topics which excludes PMs,
so first_unread_pm_at was never updated. Now it explicitly handles PMs
by calling set_minimum_first_unread_pm!

2. The client-side PM tracking state wasn't notified of the change.
Unlike regular topics which sync state on navigation, PM tracking relies
on MessageBus for updates. Added publish_read call to notify the client.

Internal ref - t/155983
2025-11-26 18:29:35 +01:00
chapoi afa873fcc1 UX: transparent button modifiers (#36252)
As a last part of the [button
refactor](https://github.com/discourse/discourse/commit/759fc040419d30a52885bbc71065de98013b3033),
these double declarations should no longer be used.

Instead, when using a `btn-transparent` that needs to be a different
colour, use the `--primary`, `--danger`, or `--success` modifiers.

This commit 
* adds the modifiers, while keeping the original declarations for safety
* updates the usages I can find
2025-11-26 17:26:07 +01:00
benj 664e6244b0 DEV: Adds 'upload' type to schema setting (#36071)
The `type: upload` exists on main site settings, but not under the
`type: objects` schema setting. This adds this feature for `objects` in
Site Settings, Theme Settings, and Theme Site Settings.
2025-11-26 09:46:26 -06:00
Penar Musaraj f64b89b96b UX: Remove "Getting Started" button in header when in bootstrap mode (#36231) 2025-11-26 10:01:40 -05:00
Régis Hanol 40c7f586b6 DEV: bump 'mail' gem from 2.8.1. to 2.9.0 (#36254)
This required fixing some specs.

Internal ref - t/168669/10

Closes #35581
2025-11-26 14:08:39 +01:00