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.
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>
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.
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).
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.
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>
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.
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`
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>
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
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>
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.
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.
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.
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`.
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.
- 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
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**

**AFTER**

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.
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
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"
/> |
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.
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.
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>
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.
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.
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.
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`
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.
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.
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:
- 
## 🔍 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
