In the admin search, links to site settings for plugins that
are not using the new show page for plugins were pointing to
the admin route for the plugin. This is not useful, because most
plugins do not show their site settings here.
Instead, we should link to the plugin category on the
/admin/site_settings
route.
1. Make consistent use of `is_me?`, `is_my_own?`, etc. since these are
more robust and don't use the `user` accessor method (soon to be
deprecated) directly.
2. Add missing test coverage for `BookmarkGuardian` methods.
The test cases added in 470b2891c5 caused
core backend tests to start timing out on CI because MessageBus messages
were being processed in a background thread outside of the current
database transation.
We are currently working around the problem by updating the test cases
to just assert that the right MessageBus message is being published.
This commit fixes an issue in multi-process setups where the following
would happen:
1. Admin changes a theme site setting. The new value is stored in memory
in the process that made the change. For this example, changing
`enable_welcome_banner` from `true` to `false`
2. Another user visits the site and hits another process, which has the
old value of `enable_welcome_banner` still set to `true` in memory
3. The other user's value for `enable_welcome_banner` is cached in
the cache for theme site settings, which is shared across all
processes
The issue is fixed by doing the same thing as site settings: when the
new value is saved, we send a MessageBus message to all processes via
`SiteSettingExtension` which calls `refresh!` and reloads the in-memory
cache of theme site settings from the DB.
c.f.
https://meta.discourse.org/t/difficulty-understanding-the-enable-welcome-banner-setting/377321
Admins can view the list of invites created by other users and they can
see the delete button for invites in the list, but it currently doesn't actually
delete anything due to a bug in the `invites#destroy` controller action
where it looks up the invite record by the given id and expects it to be
created by the current user, but when an invite is being deleted by an admin,
this logic fails because the invite isn't created by the admin.
This commit fixes the issue by removing this check for current user and
adding a proper guardian check that validates the action is performed by
either the user who created the invite or an admin.
Internal topic: t/158288.
If you have a query like `category:1 tag:A,B tag:C,D` it should bring
all topics that are in category 1 and have tags (A or B) and (C or D).
Currently it works for `category:1 tag:A tag:C,D` -> it brings topics in
category 1 that have tag A and either (tag C OR tag D)
This is a step towards unifying how reviewable types are defined.
In this change, we add a new `ReviewableActionBuilder` concern, which can be included by the various reviewable types to give them a standard helper for adding actions that can be performed on the reviewable.
The first feature for this concern takes the `build_action()` helper that some reviewables used, and makes it available to all reviewables. This is done in a backward compatible fashion, so it will work even whilst we transition to the new reviewable UI.
Since the introduction of dedicated login and signup pages (as opposed
to modals), we've been seeing reports of issues where visitors aren't
redirected back to the "page" they were at when they initiated the
_authentication_ process.
Since we have a bazillion of ways a user might authenticate
(credentials, social logins, SSO, passkeys, discourse connect, etc...),
it's really hard to know what a change will impact.
The goal of this PR is to "simplify" the way we handle this "redirection
back to origin" by leveraging the use of a single `destination_url`
cookie set on the client-side.
The changes remove scattered cookie-setting code and consolidate the redirection logic to ensure users are properly redirected back to their original page after authentication.
- Centralized destination URL cookie management in routes and authentication flows
- Removed manual cookie setting from various components in favor of automatic handling
- Updated test scenarios to properly test the new redirection behavior
# Hide IP Addresses from Moderators When `moderators_view_ips` is
Disabled
## Summary
Feature Request Link -
https://meta.discourse.org/t/option-to-hide-ip-addresses-from-moderators/207715/51
This PR implements a feature to **hide IP addresses from moderators**
when the `moderators_view_ips` site setting is disabled. Previously,
moderators could view IPs in multiple locations across the admin UI.
This update ensures that IP addresses are visible to moderators when the
setting allows it.
## Changes Implemented
### Backend Updates
- **Added `moderators_view_ips` site setting** in `site_settings.yml`
- **Updated `CurrentUserSerializer`** to include `can_see_ip` field
based on the user’s role and site setting.
- **Modified `AdminUserSerializer`** to restrict IP address visibility.
- **Updated `UsersController`** to prevent IP addresses from being
included in API responses.
- **Restricted IPs in `ScreenedIpAddressesController`** by throwing
`Discourse::InvalidAccess` if the user lacks permission.
### Frontend Updates
- **Hid "Screened IPs" tab** in `/admin/logs` when `moderators_view_ips`
is disabled.
- **Blocked direct access to `/admin/logs/screened_ip_addresses`** for
unauthorized users.
- **Updated `user-index.hbs` and `logs.hbs`** to conditionally hide IP
fields.
### UI Screenshots
New option for Admins in the Admin Security settings dashboard:

Moderator's view before:

Moderator's view after:

Moderator's view before:

Moderator's view after:

---------
Co-authored-by: Bennett Dungan <bennettdungan@gmail.com>
This change adds a new `from_described_class` helper to `RSpec::Mocks`, allowing stubs to only be used when called from the described class in a given spec.
The practical application of this helper is to handle flaky specs, where other code can call the mocks before the test target can.
This commit responds to feedback in the Discourse Meta discussion
https://meta.discourse.org/t/monospace-font-in-the-markdown-only-editor/359936
This change introduces a user preference that allows users to choose
whether the Markdown editor uses a monospace font. The default setting
is `true` for new sites, but set to `false` for existing sites to avoid
disrupting current users' experiences.
Admins can change the `default_other_enable_markdown_monospace_font`
site setting to manage this for all users.
Building the Discourse ember app is resource-intensive process. This
commit introduces a framework for us to build these assets centrally,
and make them available for people to download.
On every commit to `main`, a new GitHub actions workflow will build
development & production versions of the core assets, and publish them
as a github release under the `discourse/discourse-assets` repository. A
separate repository is being used to avoid polluting the main
`discourse/discourse` repository with one-git-tag-per-release.
The `assemble_ember_build.rb` script is updated to fetch the relevant
asset bundle. Requests are made to `get.discourse.org`, which then
redirects to GitHub releases. This redirection service is being used so
that we have the option to switch away from GitHub releases in future
without breaking existing Discourse installations.
For now, this behavior can be enabled by setting
`DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS=1`. In the near future, we hope to
make this the default, with opt-out via
`DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS=0`.
This commit adds a new dropdown preference to set the default color mode for
the user and change the color mode for the current device. It works the same way
as the interface color selector in the sidebar footer (or header), but it also allows
setting the default mode for the user that gets used when the user logs in on a
new device. It remains possible to set a color mode per device using the
sidebar/header selector or this new preference.
Internal topic: t/159358.
In a previous PR I had to work with TopicGuardian#can_delete_topic? and I had to whip out pen and paper to untangle the single conditional that governs it. Now that that task is done, I'm going back to it to clear it up.
Commit by commit:
1. Move the tests to topic_guardian_spec.rb.
2. Add missing test cases for trashed- and category topics.
3. Break the conditional into individual code paths using guard clauses.
The edit_all_post_groups used to have TL4 as the default setting. This update:
- Adds in admins and moderators as well as makes those mandatory values.
- Gets rid of now-redundant is_staff? check.
- Makes use of the magic #edit_all_post_groups_map method.
The previous form template validator did not detect non-existent tag
group names, which would result in the page being saved normally when an
incorrect name was entered, but causing the interface to crash during
preview and a 500 error to be thrown when the user used it.
This commit adds detection for non-existent tag group names and fixes
this issue
This PR adds localized language names to settings. The language names
are localized in the frontend, not the backend, due to setting
initialization complexity.
This change affects these areas:
- `SiteSetting.available_locales`
- this "setting" is a lookup table to get language names. use
`languageNameLookup` service to get the name for a locale
- it returns an object that looks like the following, then gets
re-hydrated with client localized values when initializing the
`siteSettingService` in the frontend.
```
[
{"native_name":"اللغة العربية","value":"ar","name":"languages.ar.name"},
...
]
```
- `SiteSetting.default_locale`
- this is a single-value `enum` setting that has always been hardcoded.
This caused quite an issue as it is not initialized the same way as
other site settings in the yml file. It has always relied on reading
directly from a `names.yml` file to load native language names, thus
bypassing the need for I18n to be initialized from the backend. A new
locale_enum type has been introduced for this setting, and any future
settings.
- `SiteSetting.content_localization_supported_locales` - this is a
`enum_list` setting,
- enum_list is introduced, leveraging both `list` and `enum`
- theme translations
- site texts
- Wizard's default_locale choices
- it was set up from the backend using `LocaleSiteSetting.value`. This
proved problematic, as a Japanese user would be getting the locales in
English because the values are initialized using English even without
memoization
- therefore we're now initializing the choices in the frontend using
`available_locales` as defined above
- content localization meta data
- post language in the composer, localization composer, post history
modal, post language tooltip, language switcher
/t/151409
This icon is used in the rich editor. Normally it works fine because
it's the default icon for the "Editor" badge. But if that icon was
changed, or the badge was disabled, then the icon was unavailable.
We believe the rich editor is a great experience for the
vast majority of sites and users, so we are enabling it
for all sites and all users by default.
This commit does the following:
* Hides the rich_editor site setting and sets it to true by default.
It can still be overridden by sites that want to disable it
completely.
* Sets `rich_editor` to true for all sites to enable the rich editor
everywhere.
* Adds a new `default_composition_mode` site setting and corresponding
user option that defaults to Rich for all users. The other option is
Markdown.
* Changes the rich editor toggle in the composer to use the new
database-backed user option (`composition_mode`) instead of a local
storage key/value store. This makes the preference persistent
across devices.
Existing key/value store settings for the markdown toggle are
kept, the preference will be saved to the user option automatically.
This commit is a complete reimplementation of our theme JS compilation
system.
Previously, we compiled theme JS into AMD `define` statements on a
per-source-file basis, and then concatenated them together for the
client. These AMD modules would integrate with those in Discourse core,
allowing two way access between core/theme modules. Going forward, we'll
be moving away from AMD, and towards native ES modules in core. Before
we can do that, we need to stop relying on AMD as the 'glue' between
core and themes/plugins.
This change introduces Rollup (running in mini-racer) as a compiler for
theme JS. This is configured to generate a single ES Module which
exports a list of 'compat modules'. Core `import()`s the modules for
each active theme, and adds them all to AMD. In future, this consumption
can be updated to avoid AMD entirely.
All module resolution within a theme is handled by Rollup, and does not
use AMD.
Import of core/plugin modules from themes are automatically transformed
into calls to a new `window.moduleBroker` interface. For now, this is a
direct interface to AMD. In future, this can be updated to point to real
ES Modules in core.
Despite the complete overhaul of the internals, this is not a breaking
change, and should have no impact on existing themes. If any
incompatibilities are found, please report them on
https://meta.discourse.org.
---------
Co-authored-by: Jarek Radosz <jarek@cvx.dev>
Co-authored-by: Chris Manson <chris@manson.ie>
By default, Rack/Rails will include the session cookie in every
response, even if its content hasn't changed. This makes race conditions
very likely when multiple requests are made in parallel.
Preparatory refactoring:
1. Lift-and-shift the guardian tests relating to TagGuardian into tag_guardian_spec file.
2. Reorganize the tests a bit so that each top-level describe matches a guardian method.
Necro-posting by spammers will bump the topic, and once you delete them,
those topics will still sit in `/latest` without any benifit.
This commit implements automatic resetting of topic bump date when a
post is deleted, so the topic will go to the correct place it belongs on
`/latest` based on its last public post.
The personal_message_enabled_groups setting now has admins and moderators as mandatory values, so we don't need to check for is_staff? as well.
Also removes a duplicated test case.
This commit removes the value transformers introduced
to Horizon back in
274e5f7a1f
and
897d34132e
in favor of the new themeable site settings introduced in
19af83d39e , as this is what they
are for.
No migration for existing sites...they will already have
ThemeSiteSetting values from a previous migration to ensure
site setting values were preserved in theme site settings.
We do delete the ThemeField storing the Horizon custom theme
setting definition though, otherwise the UI still shows the old
settings.
When enabled this will convert uploaded videos to a standard format that should
be playable on all devices and browsers.
The goal of this feature is to prevent codec playback issues that
sometimes can occur with video uploads.
It uses an adapter pattern, so that other services for video conversion
could be easily added in the future.
Extracted from #33103
The goal here is for `append_tree` to be the only interface for
introducing new source files, and for all compilation to be deferred
until the final `compile!` call. This change will allow us to swap out
the compiler internals without any changes to call sites.
We check for membership in invite_allowed_groups, which has admins and moderators as a mandatory value, so it's redundant to check is_staff? as well.
I also unfurled this one long conditional into multiple guard clauses.
The refactoring is covered by existing tests in invite_guardian_spec.rb.