10685 Commits

Author SHA1 Message Date
cb0b8351a9 A11Y: onebox avatars/images are decorative, so screenreaders can skip (#33572)
Adding `alt=""` to tell screenreaders to skip these, we don't reliably
have alt content available for onebox images and they tend to be
decorative, so better to omit.


<img width="738" height="151" alt="learn.microsoft.com onebox with the
link whats new in C# 11, there's a purple C# badge to the left of the
link"
src="https://github.com/user-attachments/assets/15bdc830-683f-4c69-a11b-9d54c66fa627"
/>


We already do this in some oneboxes, so this covers some more cases
including the generic.
2025-07-11 09:55:48 -04:00
afc5d13c63 FEATURE: Text heading/paragraph menu in composer toolbar (#33461)
This PR introduces a heading/paragraph dropdown menu for  the
composer toolbar, that works for both the new rich text editor, and
the old markdown editor.

Features include:

* Dynamically changing the icon based on the heading level
* Checking the current heading level in the dropdown list
* Applying the same heading level to multiple selections

---------

Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Renato Atilio <renatoat@gmail.com>
2025-07-11 12:29:58 +10:00
bccf4e0b53 FIX: improve "read only" modes (#33521)
The reasons for these changes is https://meta.discourse.org/t/-/89605
broke and admins were not able to log back in if they had previously
enabled the "read only" mode.

Thus ensued a deep dive into how all the "read only" modes worked, which
was made difficult due to the lack of tests.

The "cornerstone" of this PR is the `read_only_mixin.rb` file which was
improved to be able to differentiate between the "readonly" mode and the
"staff writes only" mode.

I then made use of the `allow_in_readonly_mode` and
`allow_in_staff_writes_only_mode` method to **explicitely** list all the
actions that should work in those modes.

I also added the "readonly" mixin to the `WebhooksController` since it
doesn't inherit from the `ApplicationController`.

I improved the security of the `/u/admin-login` endpoint by always
sending the same message no matter if we found or not an admin account
with the provided email address.

I added two system specs:

1. for ensuring that admins can log in via /u/admin-lgoin and then
clicking the link in the email they received while the site is in
readonly mode.
2. for ensuring the "staff writes only mode" is _actually_ tested by
ensuring a moderator can log in and create a topic while the site is in
that mode.

Plenty of specs were updated to ensure 100% converage of the various
"read only" modes.
2025-07-10 09:08:00 +02:00
0dcbbe0de4 DEV: Load admin JS bundles from plugins for staff users (#33540)
JS assets defined under `admin/` in plugins are compiled into a separate
bundle that should be loaded for staff users only, but we currently load
it for all users including normal users and anons. This is wasteful and
unexpected since it could cause errors if an asset in the admin bundle
of a plugin imports a module from the admin bundle in core (which
doesn't get loaded for non-staff users).
2025-07-10 07:39:11 +03:00
12d433dfca FIX: Also update topic locale on creation (#33544)
When a user creates a new topic via the composer and sets the locale, we
currently set the post's locale but not the topic's. This PR updates
that.
2025-07-10 00:33:20 +08:00
11bf7ad539 FIX: Handle restore URLs ending with query params (#33384)
Moving parsing the URL to the constructor ensures that is_archive is
correctly initialized. This allows .sql.gz backups to be restored.
2025-07-07 18:43:31 +03:00
4c7089f817 DEV: Deprecate external_system_avatars_enabled (#33436)
We want to deprecate the enabled/disabled toggle for this setting and rely entirely on the presence of a URL.

This change:

- Deprecates and hides the enabled/disabled setting.
- Updates all code paths and tests that rely on the old setting.
- Adds a migration that clears the URL if the enabled/disabled setting is set to false.
2025-07-04 16:02:04 +08:00
01d42ab524 FEATURE: Display locale change in post history modal (#33469)
This commit adds locale changes to the post history modal, and also updates
the topic's locale if the first post is being updated.
2025-07-03 23:08:47 +08:00
38194c2aec DEV: First pass of review queue redesign
This is the start of the review queue redesign. Due to the rapidly
growing size of this redesign, this PR is being merged in a
semi-functional state: large chunks of it have the new design, but there
are substantial sections that may not function at all.

This PR is focussed on the variations of reviewable posts, other
reviewables (eg, users, chat messages) will continue to use the old UI.

Co-authored-by: Gary Pendergast <gary@pento.net>
2025-07-03 14:32:43 +08:00
ffeec9fb27 Revert "DEV: Introduce reviewable_ui_refresh site setting (#33404)"
This reverts commit bc29e5088eb21b10ce3f3055f9dd961900c75ff7.
2025-07-03 13:31:27 +08:00
02e17ddb7f FIX: Make hide_new_user_profiles work with manually upgraded users (#33458)
The site setting hide_new_user_profiles states:

> Hide trust level 1 or lower user profiles from the public and trust level 1 users until they post for the first time.

This implies that TL2 and above should be visible.

However, the actual logic encodes the assumption that TL2 have posted at some point. This fails to account for the fact that admins can manually upgrade a user without posts to a higher TL. This PR covers for that scenario.
2025-07-03 13:00:30 +08:00
052cebce48 FIX: Horizon default color scheme must be user selectable (#33428)
Improvements:
- When import Horizon theme, ensure that default color scheme is marked
as `user_selectable`
- Dark version of the theme is `user_selectable` as well
- When merge remote Horizon into system Horizon, also ensure that
default color scheme is marked as `user_selectable`
2025-07-02 13:40:44 +08:00
bc29e5088e DEV: Introduce reviewable_ui_refresh site setting (#33404)
This commit introduces an experimental `reviewable_ui_refresh` site
setting of `group_list` type. When a user is part of any group
configured in the site setting, the new reviewable UI will be shown to
the user.

Co-authored-by: Gary <gary@pento.net>
2025-07-01 15:31:26 +08:00
c42333f264 FIX: improve the merge horizons task (#33394)
When the remote horizon color scheme is `user_selectable`, the system
color scheme should be as well.
2025-07-01 08:36:33 +08:00
b20d6792bf FEATURE: Add a hidden setting to limit number of content localization locales (#33378)
We want to add a hidden limit to the number of locales an admin can set
for localization. This is a safe limit to prevent excessive localization
(if each post can be localized to 10 locales, that's 10x the amount of
storage and tokens needed).


t/157677
2025-06-30 15:29:58 +08:00
39a43f7e76 DEV: rake task to merge the manually installed Horizon (#33355)
Rake task to merge a single installation of Horizon into the system
Horizon.

What task do:
- Set Horizon as `experimental_system_themes` if not yet included;
- Set system Horizon as the default if manual Horizon was the default;
- Set the system Horizon as selectable if the manual Horizon was
selectable;
- Link components from the manual Horizon to the system Horizon;
- Update UserOptions `theme_id`, `color_scheme_id` and `dark_scheme_id`;
- Update the system Horizon color palette to match the manual Horizon
color palette;
- Move ThemeSettings from manual Horizon to system Horizon;
- Move ThemeTranslations from manual Horizon to system Horizon;
- Delete manual Horizon color schemes;
- Delete the manual Horizon.

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
2025-06-30 14:40:46 +08:00
12dbbadbc1 DEV: Add modifier for restricting theme creation endpoints (#33313)
This commit adds a new modifier that plugins can hook into to add further
restriction to who can install themes and components via the admin UI. It
isn't possible to use this modifier to open up the theme installation
permissions to more than core allows, e.g. this modifier can't be used
to allow moderators to install themes on the site.

Internal topic: t/156924.
2025-06-30 09:26:02 +03:00
88b37a715a DEV: ensure retries do not re-set attempts=0 (#33365) 2025-06-27 06:51:10 -03:00
Sam
e180c62d2e FEATURE: new search order for read topics (#33353)
Introduces order:read and r to search through recently read topics

Also applies to filter route
2025-06-26 17:02:52 +10:00
00c97178d5 FIX: Don't allow submitting bulk topic actions without a notification… (#33292)
… level

See report https://meta.discourse.org/t/-/371074

---------

Co-authored-by: Blake Erickson <blake@discourse.org>
2025-06-25 14:48:36 -06:00
99ab4608dc FIX: Ignore recent posts offset in search when before/after filters are used (#33323)
There exists a hidden `search_recent_regular_posts_offset_post_id` site
setting which is used to optimize the searching of recent posts through
the use of a partial index. However, we do not want this optimization to
apply when the `before` and `after` advanced search filters are used
since the partial index only contains the most recent posts 1 million
posts and the `before`/`after` filter may be searching for posts that
falls outside of the
most recent posts range.
2025-06-25 15:23:08 +08:00
b9628ad40a DEV: Update uploads:sync_access_control rake task to remove ACLs (#33286)
The `uploads:sync_access_control` rake task should reset the access
control
of all s3 objects linked to an upload record. This means that if the
`s3_use_acls` site setting has been disabled, the rake task should
remove the existing ACL that has been set previously.
2025-06-25 15:03:05 +08:00
3eb252c9d1 Bump version to v3.5.0.beta8-dev 2025-06-25 10:52:27 +08:00
fd2f543a08 Bump version to v3.5.0.beta7 2025-06-25 10:52:27 +08:00
0b1dd04550 SECURITY: Don't display user's old whispers if not in allowed group
Before this change, users were able to see their own whispers even if
they are no longer in the groups specified by the `whispers_allowed_groups` site setting.

This commit fixes that by disallowing users to see their own whispers if
they are no longer part of any `whispers_allowed_groups`.
2025-06-25 10:25:44 +08:00
cef46d612f DEV: Add "UI" as a humanizable acronym (#33322)
Site settings with the acronym "ui" in them will now have it formatted as "UI".
2025-06-24 15:42:35 +10:00
5b236ccc07 DEV: Move site setting name humanization to server side (#33311)
This commit moves the humanization of site setting names from the client
side to the server side, since this is becoming more widely used and
will be useful for specs to be able to access the same humanized name
formatting without duplicating the logic on the server.

There are only a couple of places in the admin UI that we send this
down in the JSON, the `site.sitSettings` object does not include these
humanized names as they are not needed.
2025-06-24 13:20:29 +10:00
3fbb2954cb DEV: Refactor Chat::ListChannelMessages service a bit
- improve the contract a little
- use `model` where possible
- extract message existence logic to a dedicated policy, allowing easier
  testing.
- remove unused code
- refactor specs to follow current guidelines/best practices
2025-06-23 14:18:49 +02:00
9dadc0141c FEATURE: add link to "associated accounts" providers (#33275)
This adds a link for each authentication providers that are listed in
/my/preferences/account in the "Associated Accounts" section.

This is particularly useful when Discourse is being used in the PWA or
in the DiscourseMobile app where there's no browser bar available and
the only way to visit the provider's website is to open a browser
window.

That way, they can _just_ click the provider's name.

Internal ref - t/156255

---

**BEFORE**

![Screenshot 2025-06-19 at 21 04
46](https://github.com/user-attachments/assets/3d2be5d0-d857-4b8a-b0a5-5672301c59c6)

**AFTER**

![Screenshot 2025-06-19 at 21 03
39](https://github.com/user-attachments/assets/4c8bc5e9-3c99-4924-8d33-547f567bb346)
2025-06-20 10:22:29 +02:00
1a9f577044 DEV: Don’t check model validity when no changes have been made
When fetching a model using the `model` step in a service, if that model
is an `ActiveRecord` object, we check if it’s in a valid state. While
this is useful when manipulating the model or when we create a new one,
it’s not the case for a model we just pulled from the DB, as it should
be valid.

In some cases, running the validations can be costly (it can lead to N+1
queries if the model validates associated items for example).

This patch introduces a small optimization by checking if the model has
any pending changes on it, thus requiring validation. If that’s not the
case, we just skip the validation part, as the model should be valid
anyway.
2025-06-20 09:09:33 +02:00
81b4cb776b FIX: prevent login loop when logging out when only one idp (#33266)
When we migrated to the full page /login, we added a nice feature that
will automatically redirect a user to the idp if it's the only way they
can log in, thus avoiding unecessary click.

But when logging out, we would redirect to the /login page which would
start the /login process by automatically redirecting the user to the
idp...

The fix is easy, redirect back to `/login-required` after logging out
instead. This will show the "splash" screen that asks the user to either
log in or sign up.

Note: I also removed the `Discourse::Utils::EMPTY_KEYWORDS` since it was
its last occurence and I'm pretty sure we dropped support for Ruby 2 a
while ago...

Internal ref - t/156834
2025-06-19 15:02:54 +02:00
fe30ffa3f9 DEV: Remove 'experimental' prefix from settings (#33233)
This PR takes the localization features out of "experimental" to prep
for the announcement
- rename settings and gives them its own area
- `experimental_content_localization` to `content_localization_enabled`
- `experimental_content_localization_allowed_groups` to
`content_localization_allowed_groups`
- `experimental_content_localization_supported_locales` to
`content_localization_supported_locales`
- `experimental_anon_language_switcher` to
`content_localization_anon_language_switcher`
- migration
- related to https://github.com/discourse/discourse-ai/pull/1439

| screenshot 📸 |
|---|
| <img width="964" alt="Screenshot 2025-06-17 at 5 06 32 PM"
src="https://github.com/user-attachments/assets/9a8b2c38-c846-4fc9-8ddd-815c45cc3d0e"
/> |
2025-06-19 12:23:42 +08:00
15a491d2d0 FEATURE: add emojis to seeded categories (#33248)
This change adds some flair to the default seeded categories by adding
emojis for new sites.
2025-06-18 17:25:12 +04:00
b1833b6473 FIX: Incorrect key being used in S3Helper#upsert_tag (#33245)
This is a follow up to b02bc707dec12c607511d4a95c7d791f63131b49 where
the `S3Helper#upsert_tag` method was introduced. Using the method
resulted in an error being thrown because the key was incorrect.
2025-06-18 14:08:56 +08:00
6e22f8fac8 DEV: Remove generic exception in model step in services
Currently when a model is not found, we raise an `ArgumentError`
exception and that exception is stored in the resulting context object.

However, since we’re also storing unexpected exceptions, this default
exception can pollute the context object when we need to inspect it or
act on it.

This patch addresses that issue by raising a custom exception instead,
and we then discard it from the context object.
2025-06-17 16:12:28 +02:00
d45ebd746c DEV: Add Discourse ID authenticator (#33186)
Adds a Discourse ID authenticator. Not available for use in production
just yet, but soon communities will be able to use this service to let
users authenticate using a central Discourse ID account.

Includes a support for a `/revoke` action, allowing users to log out of
multiple client instances from a central auth service.

Internal ticket: t/155397
---------

Co-authored-by: Loïc Guitaut <loic@discourse.org>
2025-06-17 09:47:00 -04:00
342e9208b3 FIX: Upload#update_secure_status not updating s3 access control (#33232)
This commit is a follow-up to b02bc707dec12c607511d4a95c7d791f63131b49
where `Upload#update_secure_status` does not call
`FileStore::S3Store#update_upload_access_control` if
`s3_use_acls` is disabled. This is no longer correct as an upload's
access control on S3 can now be based on tags if the
`s3_enable_access_control_tags` site setting is
enabled.

To fix this, this commit removes the `s3_use_acls` check in
`Upload#update_secure_status` and updates
`FileStore::S3Store#default_s3_options`
to not set the `acl` option if the `s3_use_acls` site setting is
disabled.
2025-06-17 16:28:36 +08:00
da1de52a06 FIX: Wrong argument error in FileStore::S3Store#update_access_control (#33231)
This commit is a follow up to b02bc707dec12c607511d4a95c7d791f63131b49.
When the `s3_enable_access_control_tags` site setting is enabled,
calling `FileStore::S3Store#update_access_control` will result in a
argument error.
2025-06-17 15:18:14 +08:00
6ea31d32f0 DEV: Fix lograg logger and log_level not following rails log_level (#33218)
Before this change, we were relying on the `lograge`'s gem default
`log_level` of `info`. However, `lograge` should be following
`Rails.application.config.log_level` instead and this commits seeks to
correct that behaviour.
2025-06-17 09:59:58 +08:00
6c049af5c4 FIX: ignore SiteSetting.max_image_size_kb for theme screenshots (#33215)
Theme screenshots have their validations:
https://github.com/discourse/discourse/blob/main/lib/theme_screenshots_handler.rb#L4

Therefore, validations in `UploadCreator` can be ignored. Currently, the
import of system themes is crashing when the value is too low for
`SiteSetting.max_image_size_kb` .
2025-06-17 08:58:37 +08:00
b02bc707de DEV: Add setting to tag s3 objects enabling tag based access control policies (#32988)
This commit introduces a `s3_enable_access_control_tags` site setting
which,
when enabled, adds a `discourse:acl` tag with values `public` or
`private` to
S3 objects created by the application. The presence of the tags on S3
objects
enables bucket administrators to implement tag-based access control
policies, providing an alternative to
object ACLs which AWS now discourages.

The `discourse:acl` tag can be customized via the
`s3_access_control_tag_key ` site setting.
Values for `public` and `private` can also be customized via the
`s3_access_control_tag_public_value` and
`s3_access_control_tag_private_value ` site settings respectively.

### Reviewer Notes

To test it locally, run the following commands in your working discourse
directory:

1. `script/install_minio_binaries.rb`
2. Start a local minio server by running: `bundle exec rails runner
script/local_minio_s3.rb`
3. bundle exec rails runner "SiteSetting.enable_s3_uploads = true"
5. Start your development rails server with the following environment
variables: `DISCOURSE_ENABLE_S3_UPLOADS=true
DISCOURSE_S3_ENABLE_ACCESS_CONTROL_TAGS=true
DISCOURSE_BACKUP_LOCATION=s3`
2025-06-16 13:26:18 +08:00
862116a176 FEATURE: Add description to invites (#33207)
Add the ability to attach a description to an invite for easier organization.
2025-06-16 11:31:07 +08:00
290b435a72 FIX: Admin can edit the name even if enable_names is disabled (#33170)
There is a bug that when `SiteSetting.enable_names` is disabled, the
admin can click the pencil next to the user and successfully update the
name. However, the change is not saved as the action is blocked by the
guardian.

Meta:
https://meta.discourse.org/t/disabling-enable-names-makes-admin-act-strange/291912
2025-06-16 09:24:17 +08:00
777b80be6c UX: make all preference icons unique (#33202)
We repeat the user icon here, making the icons kind of pointless.

This changes the account and profile icons to potentially be a little
more useful.

Before:

![image](https://github.com/user-attachments/assets/2fce16fb-5ddf-4cd2-9053-c5a946f9500c)

After:

![image](https://github.com/user-attachments/assets/729962c9-c466-456a-95a6-04a767d95ed3)

Mentioned here:
https://meta.discourse.org/t/ux-improvements-on-header-dropdown-notifications/370110
2025-06-13 15:13:09 -04:00
bc4844cb93 FEATURE: allow date-based filters to accept a day count (#33197)
This allows date based filters to use a count of days as well as the
existing date string system (`YYYY-MM-DD`). This is convenient if you
want a dynamic list based on the current date, you could use:
`created-after:7` to return topics from the past week.

This will work for: 

 - created-before/after
 - activity-before/after
 - latest-post-before/after
 
This also makes filters consistent with our existing query params like
`?before=7`



This came up in:
https://meta.discourse.org/t/creating-a-custom-filter-homepage/370062
and is something that we mentioned internally while defining our domain
specific language for the /filter route, but never implemented.
2025-06-13 13:45:50 -04:00
2536768a43 FEATURE: system themes (#32681)
Introduction of system themes.  System themes are local themes which:
- Cannot be deleted;
- Cannot have “custom code” added, components only;
- Cannot have uploads;
- Cannot edit color palettes;
- Are updated on deploy, like core plugins.

This PR added the Foundation system theme, which is an empty theme like
Default. The Foundation theme will be added in the next PR.

In a development environment, when system theme files are
changed/added/deleted, the theme is reuploaded and the page is reloaded
to make it a good experience for the engineer working on improvements.

System themes are not visible until
`SiteSetting.experimental_system_theme` is enabled.
2025-06-13 10:36:31 +08:00
e39c7b4cbb DEV: Add Plugin modifier for reviewable creation (bot posts) (#33161)
I need reviewables to be created for bot users in a private plugin. This
allows me to do that.
2025-06-11 14:57:33 -05:00
4d380a28e7 FEATURE: Add post language on creating a new post (#33160)
This is a second attempt at:
https://github.com/discourse/discourse/pull/33001

We had to [revert the
commit](https://github.com/discourse/discourse/pull/33157) because it
was performing a site-setting check at boot time, which is prone to
issues and not allowed.

This PR:
- re-introduces the changes in the original PR
- a fix by not performing a site-setting check at boot time (verified
by: `SKIP_DB_AND_REDIS=1 DISCOURSE_DEV_DB="nonexist" bin/rails runner
"puts 'booted'"` locally and should be caught by the new CI check
introduced here: https://github.com/discourse/discourse/pull/33158)
- adds a fix to the translation editor to not show the original post
locale in the dropdown, as well as adding an indicator of what the
original post locale is in a small badge in the header:
- ![Screenshot 2025-06-11 at 08 42
36](https://github.com/user-attachments/assets/5f0944c5-ec4d-40b3-b97f-25b1fcab8329)
2025-06-11 10:39:01 -07:00
d5b72a54ae Revert "FEATURE: Add post language on creating a new post (#33001)" (#33157)
This reverts commit b55af383f779d01d983a3ccf1149438aee9c6725.
2025-06-11 08:01:56 -07:00
b55af383f7 FEATURE: Add post language on creating a new post (#33001)
## 🔍 Overview
Previously we added the ability to translate existing posts in different
languages: https://github.com/discourse/discourse/pull/32564. In this
update we add the ability to set a post language upon initially creating
a post.

Internally, we also clean-up/improve a few things, like:
- adding a `PostLanguageSelector` component
- Adding a `available_content_localization_locales` onto `SiteSetting`
so it's available in the service (without needing to parse the JSON to
access it)
- fix issues with the translation-editor not working due to some
regressions from here: https://github.com/discourse/discourse/pull/32869
- ensure everything works for replies/drafts/edits

## 📷 Screenshots
![Screenshot 2025-06-05 at 12 03
24](https://github.com/user-attachments/assets/ff334575-ba30-4c52-9e9a-4054f69795ec)
2025-06-11 07:29:05 -07:00