This PR addresses the issue discussed in
https://meta.discourse.org/t/failed-error-when-trying-to-un-star-the-bug-reporter-badge/330523
1. Fixed an issue in `user_badges_controller.rb` where the
`toggle_favorite` method could incorrectly treat badges already marked
as favorite as not being favorite.
2. Automatically synchronize the `is_favorite` status for new badges
when a user is granted a multiple-grant badge.
Previously, clicking "Groups" on the admin dashboard would bring you to the public groups page. Historically, the public and admin actions have been mixed together on that page.
This is a bit of a frustrating experience when working on the admin dashboard, and also prevented us from adding a "Settings" tab for group-related site settings.
This PR adds an "admin groups" page, which is just an exact copy of the public groups index for now. This allows us to add the "Settings" tab, and lets us gradually work un disentangling the public- and admin parts of groups.
Adds support for a tag-chooser in form templates. It supports single tag
and multi tags. The source of the displayed tags has to be a tag_group
name.
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Don't require password to create users with previous authentication in
the session, regardless of email/email verification during user creation
Before my changes we were calling `user.password_required!` in
`UserAuthenticator.authenticated?` based on whether authentication
session data contained a matching email address and email verified
externally. I believe `authenticated?` is intended for our own email
validation during the activation process, but shouldn't be a gate for
password requirement.
Even when we were setting `user.password_required`, then during user
creation we were creating random passwords to get around the blank
password restriction when creating accounts with external auth.
After my change we can remove the random password creation because we no
longer require a password when the session has previous authentication
info at all.
Looks like this extra password requirement may have been introduced as a
side effect during a previous refactor of `UserController` here:
51eff92170
Before that change, password requirement was simply based on whether
session[:authentication] existed, but after that change it was based on
the email/email_valid fields as well.
This commits changes the language for components that aren't used on any themes to be "used/unused" instead of "active/inactive" throughout the new components listing page.
On sites with many components, serializing and rendering all components
in one-go on a page can take quite a bit of time. The new components
listing page that was introduced in
https://github.com/discourse/discourse/pull/32164 currently loads all
components in one-go, so this commit implements infinite-scrolling
pagination for the page to address this performance issue for sites with
many components.
When a watched words CSV file is uploaded, we assume it's utf-8 encoded, but that's not always going to be the case. This change loads the CSV and converts it to utf-8 before processing it.
Added button to remove password from account if user has a linked
external account or passkey
The button only displays if the user has at least one associated account
or a passkey set up. Uses the ConfirmSession dialog in addition to a
warning about deleting the password.
Users can still reset their password via the Reset Password button
(which will now display "Set Password" if they've removed it).
Also prevent user from removing their last remaining associated account
or passkey if they have no password set.
Replaces PR #31489 from my personal repo, with some fixes for conflicts
since then.
Follow-up to https://github.com/discourse/discourse/pull/31887
This commit introduces a new design for the components listing page, which
is not linked from anywhere in the UI at the moment, but it can be
accessed by heading to the `/admin/config/customize/components` path
directly. We'll make this new design available from the sidebar and
remove the old page once we've tested and validated the new design
internally.
Internal topic: t/146007.
---------
Co-authored-by: Ella <ella.estigoy@gmail.com>
`GroupsController#search` now accepts an `include_everyone` parameter to
include the "everyone" group in the results. discourse-ai relies on this
endpoint for configuring personas' allowed groups and needs this group
to be present. You still need to be able to see the group.
New configure fonts section was added. Because now we have two sections
completed (logos and fonts), new /branding page was introduced and old
/logo and /font pages was removed.
When text size is changed, modal is displayed to ask if preferences of
existing users should be retrospectively updated.
https://github.com/user-attachments/assets/f6b0c92a-117f-4064-bd76-30fa05acc6d3
---------
Co-authored-by: Ella <ella.estigoy@gmail.com>
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
When replying to a post, the user who is getting the reply should be
prioritized in the autocomplete
- Added in composer a getter for getting `.replyingToUser`
- Added in d-editor the reference to the user that is getting the
reply(`this.composer.replyingToUser`)
- Passed along the reference to the user that is getting the reply to
the user-search service as `replyingToUser`
- Controller `users_controller.rb` was modified to accept the `user_id`
parameter and pass it to the `UserSearch` model
- The `UserSearch` model was modified to accept the `user_id` parameter
and use it to prioritize the user that is getting the reply in the
autocomplete on the first time you call the autocomplete service and
while the username is included in the searched term
- Had to update the serializer to pass the id of the `replyingToUser`
from the post
When a site has the `must_approve_users` setting enabled, new user data is stored on the Reviewable model, including username, email, and any other data that is entered during signup. If the user is rejected, that data is retained, without a clear path to deleting it.
In order to allow data that could be PII to be removed, without breaking Discourse's audit and logging trails, this change scrubs the PII from the relevant `ReviewableUser` and `UserHistory` objects, replacing that data with who scrubbed it, and why.
Some site settings support backfilling if the user specified it. This works fine for singular site settings sent to the SiteSettingsController#update endpoint, but with bulk save we need to support this for a list of settings as well.
This change alters the params format for SiteSetting::Update.
It also moves the backfill logic into the service.
This PR moves the logic that checks if a site setting we're trying to update has been deprecated from one of the controllers into a policy of the SiteSetting::Update service.
It also gives us the opportunity to shift the error message into a locale file.
When editing a color palette via the new page introduced in
https://github.com/discourse/discourse/pull/31742, it should apply the
color changes for the admin making the change automatically upon save.
Internal topic: t/148628/12.
When multiple admins are working in the review queue, it's quite easy for two people to try and handle the same reviewable at the same time. This change addresses the two major situations where this can occur.
The `ReviewableClaimedTopic` model has been extended to allow the system to mark a reviewable as claimed as soon as the first moderator starts handling the reviewable, even when the `reviewable_claiming` setting is disabled. This ensures that reviewable actions with client-site activity (for example, `agree_and_suspend`) will lock the reviewable before another moderator starts working on it.
When someone handles handles a reviewable, we now use `MessageBus` to inform other moderators that it's changed. If any of the other moderator have that reviewable open (either individually, or on the list screen), it will automatically refresh that data.
Fixes the custom homepage crawler output to include links to the site's
top menu.

This also provides a way to override that content via a plugin. Example
usage in a `plugin.rb` file:
```
register_html_builder("server:custom-homepage-crawler-view") do |c|
"<div>override</div>"
end
```
The service worker isn't served via normal asset paths or the CDN.
Instead, the ERB was being compiled by sprockets, fished out of the
`public/` directory by the static_controller, and then the
sprockets-specific stuff like `sourceMappingUrl` was being removed.
Instead, we can put the ERB under `views/static/`, and have it evaluate
at runtime. There are only a couple of super-cheap interpolations, plus
the route is cached in nginx, so there is no performance concern.
This takes us one step closer to removing sprockets.
There are a number of minor changes in this commit :
1. Combine the "Themes" and "Components" links in the admin sidebar into
a single tab labelled "Themes and components"
2. The combined tab links to the `/admin/config/customize/themes` page
(titled as "Themes and components")
3. Add a new "Components" tab to the "Themes and components" page.
There's already an existing "Themes" tab
4. Add a "back to" link at the top of individual theme/component page to
navigate back to the respective tab in the "Themes and components" page
5. Remove the themes/components list/sidebar that currently serves for
navigating between themes/components
6. Remove the header in the theme/component page
Changes 4–6 apply only if the admin sidebar is enabled; they have no
effect otherwise.
Internal topic: t/146006.
A new user joining a community via DiscourseHub and logging in via oauth
goes through this process. This would break down for two reasons.
Reason 1: in some cases, especially on Safari mobile, the redirect in
the omniauth callback was happening too early. A new user may not be
signed in yet by that point, which means the redirect to
`/user-api-key/new` triggers a redirect to `/login` which ends up in a
bit of an infinite loop. Not all browsers exhibited this behaviour, but
Safari definitely did.
Reason 2: `/user-api-key/new` is gated via group membership using the
`user_api_key_allowed_groups` site setting. By default that is set to
include `trust_level_0`, however, auto group assignment wasn't taking
place for all user `create` events (only some that go through staged
users).
This list of all reports is needed in the admin search
controller as well, so this commit refactors it into
a service, adds specs, and also updates the admin
search code to use this new service & avoid a second
AJAX call to the server.
When a tag has a description defined, we should use that in the `<meta
name="description"...` tag on the tagged topic list page. This matches
the behaviour on the equivalent category pages.
We are developing our new composer, and it would be useful
if we could know how posts are being created by members.
To this end, we are going to start storing the following
on post_stats, which are created at the same time as a post
is created:
* writing_device - Based on `BrowserDetection.device`, which in
turn is based on user agent. Will store .e.g iphone, android,
mac, windows etc.
* writing_user_agent - Stores the full user agent (truncated at
400 chars) of the device/browser the member used to write the post.
* composer_version - Either `1` for our old composer, or
`2` if the new rich composer is enabled in site settings and
the user has toggled it on
Redesigned page to update site logos. `AdminBrandingLogoFormComponent`
is attached to the old logos page and the new branding page. In the next
steps, branding will replace the logos page.
A new `AdminConfigAreaCardSection` component was added hidden and less
frequently used settings.
An image placeholder was also needed because many additional logos have
a fallback to the site logo.
Finally, `twitter_summary_large_image` was renamed to
`x_summary_large_image`.
Desktop

Mobile

This commit moves most of emoji logic into the discourse-emojis gem:
https://github.com/discourse/discourse-emojis/
Most notably:
- images are now symlinked from the gem
- the gem provides path to the json files
Search aliases have also been made asynchronous and memoized. When you
will search for an emoji we will now load the aliases and store the list
for future use.
---------
Co-authored-by: David Taylor <david@taylorhq.com>
This change standardises the `User-Agent` header that Discourse will send when talking to other sites.
`Discourse.user_agent` is now the authority on what the user agent value should be. For Onebox requests, this changes the user agent from their existing value to match the new value (unless overridden).
For all other requests, `Net::HTTPHeader` is monkey-patched to add a default `User-Agent` header when one hasn't been provided.
Followup e26a1175d7c33746bddbc858ad89e68cc14beefe
Adds extra functionality and tests for the admin search modal.
* Show third level plugin config pages in search, e.g. AI Usage
* Remember last used search filters
* Allow navigating search results with keyboard, using tab or up/down
and enter to go to result
* Add a placeholder beneath search input to tell the admin what to do
* Add a full page search at `/admin/search` which can be reached from
pressing Enter on the search input
* Add specs for modal and full page search
* Change admin sidebar filter "no results found" to point to full page
search
* Add keyboard shortcut help to modal for admin search
This reverts commit 38de3d7bd1f503743c5d0237bc8a8d9d89effb8e. This
changed seemed to be blocking our own AI helper as well if it has the
“Search” tool.
This change detects if a crawler is trying to load a search results page, and returns a simple response that should indicate to them that there's no content of interest available there.