Commit Graph
2723 Commits
Author SHA1 Message Date
Gary PendergastandKrzysztof Kotlarek 3b3064498b FEATURE: Update the ReviewableUser UI for the review queue refresh. (#35515)
##  What's This?

See: t/165312

This is an initial update to make `ReviewableUser`s work inside of the
refreshed review queue experience.

## 📺 Screenshots

<img width="1148" height="524" alt="Screenshot 2025-10-27 at 10 35
29 am"
src="https://github.com/user-attachments/assets/c9c52904-0706-4338-91a4-ca944ce19e89"
/>

---------

Co-authored-by: Krzysztof Kotlarek <kotlarek.krzysztof@gmail.com>
2025-10-29 08:54:08 +08:00
Alan Guo Xiang Tan 3ea1b663c8 SECURITY: Error responses missing Cache-Control header
By default, we want all responses to have the `Cache-Control` header set
to `no-cache, no-store`. Individual controller actions can override the
header when need be.
2025-10-28 14:40:41 +08:00
marstall 1b90310eea UX: add modifier to customize invite template (#35458)
Adds two modifiers :
- one to add a template to the list of email templates
- one to allow setting of email template during email rendering
meta:
https://meta.discourse.org/t/understanding-how-email-template-is-used-for-invites/369488?u=chrism
2025-10-27 11:58:58 -04:00
Blake Erickson 737c4ea194 DEV: Update tag_groups api doc schema (#35520)
This just updates the api docs to use the new json schema format for the
json response of the GET tag_groups.json endpoint.
2025-10-21 12:43:41 -06:00
Gary Pendergast d8e7741d96 DEV: Send a 204 response when updating site settings. (#35349)
When a `PUT`, `POST`, or `DELETE` operation doesn't need to return any
data, we've historically either returned nothing, or `{ success: "OK"
}`.

A more consistent way to return the same data would be with a 204 status
response. This gives the same information as the `{ success: "OK" }`
body (ie, that the operation successfully completed), without needing to
read or parse the response body.

This change adds a 204 response for `Admin::SiteSettingsController`.
Additional controllers could be migrated in follow-up PRs, or on an
ad-hoc basis.
2025-10-21 11:43:10 +11:00
David Taylor 585ba17f56 DEV: Rename theme-transpiler to asset-processor (#35498)
This is already used for more than just themes, and we plan to extend
its usage even further
2025-10-20 14:16:46 +01:00
Loïc Guitaut 695533b99c DEV: Add a compact_blank option to the ActiveModel array type (#35476)
Instead of having to clean an array in a contract using a
`before_validation` block, for example, we can now pass `compact_blank:
true` to the attribute, like this:

```ruby
attribute :ids, :array, compact_blank: true
```
2025-10-20 11:33:36 +02:00
Régis Hanol 1fe35c74e1 FIX: unsuspend a moderator (#35452)
If, for some reasons, you were to try to "unsuspend" a moderator, you
wouldn't be able to because the "can_suspend" was checking for
"user.regular?".

Added a "can_unsuspend?" to support this use-case.

Ref - https://meta.discourse.org/t/-/385786
2025-10-16 21:05:47 +02:00
Blake Erickson 57bec16515 DEV: Update api-docs for posts locked endpoint (#35453)
This commit updates the `/posts/{id}/locked.json` api endpoint docs to
match the new json schema format.
2025-10-16 12:56:34 -06:00
Régis Hanol bd94fcbce6 FIX: DeleteReplies should use the guardian instead of checking for staff (#35443)
Category moderators (who aren't staff member) are able to a topic timer
to automatically delete replies after a certain amount of time but the
background job (DeleteReplies) was deleting the "topic timer" because
the category moderators wasn't a staff member.

There was a discrepency between the UX who used "can_delete" to
show/hide the "topic timer" option and the back-end who was checking for
"staff" membership.

This fixes it by changing the backend to use the guardian's "can_delete"
method instead.

Internal ref - t/165077
2025-10-16 18:26:41 +02:00
Kelv daac912405 DEV: add api docs for discourse-calendar events index endpoint (#35400)
This creates an overriding `rswag:specs:swaggerize` rake task that also
adds plugin paths, and updates spec helpers to handle plugin paths.

Also adds the spec files for the discourse-calendar events index
endpoint.

### Testing

Running `rake rswag:specs:swaggerize` now generates the same
`openapi/openapi.yaml` file, with `/discourse-post-event/events.ics` and
`/discourse-post-event/events.json` GET documentation.
2025-10-16 07:39:08 +08:00
Blake Erickson faefa28792 DEV: Update api doc specs for post actions (#35428)
This change updates the api doc specs for `/post_actions.json` endpoint
so that it uses the new json schema format.
2025-10-15 17:01:08 -06:00
Osama Sayegh c091f109f9 DEV: Rework a couple of specs to avoid state leak (#35410)
Using `store_translations` to override translations causes overridden
strings to leak between tests and generate flaky failures. I initially
tried `I18n.reload!` in an `ensure` block around the specs that override
translations, but for some reasons it didn't fix the issue and I don't
want to spend too much time digging into `I18n` internals and our
patches to figure this out. Let's switch to the `TranslationOverride`
system which does the same thing as the `store_translations` method but
in a way that doesn't leak.

To get the specs in questions to fail, use seed 21911:
```
bin/turbo_rspec --seed 21911 spec/requests/application_controller_spec.rb
```
2025-10-15 12:41:19 +03:00
Osama Sayegh 8a22edb8b0 DEV: Make specs pass with ruby 3.4 (#35411) 2025-10-15 12:40:18 +03:00
Blake Erickson 66c63774ac DEV: Fix api docs openapi spec validation errors (#35361)
When validating the openapi spec we were getting the following errors:

```
{
  "messages": [
    "attribute paths.'/categories.json'(post).responses.200.content.'application/json'.schema. is not of type `object`",
    "attribute paths.'/categories/{id}.json'(put).responses.200.content.'application/json'.schema. is not of type `object`",
    "attribute paths.'/c/{id}/show.json'(get).responses.200.content.'application/json'.schema. is not of type `object`",
    "attribute paths.'/posts.json'(get).responses.200.content.'application/json'.schema.items is not of type `object`",
    "attribute paths.'/groups/by-id/{id}.json'(get).operationId is repeated"
  ]
}
```

These changes resolve those openapi spec validation errors.

See:
https://github.com/discourse/discourse_api_docs/pull/139#issuecomment-3393138056
2025-10-14 07:32:58 -06:00
Régis Hanol c5b32aff76 FEATURE: disable link notification user preference (#35352)
This adds a new notification's user preference to allow users to control
whether they are notified whenever one of their topic is being linked in
another post.

Internal ref - t/160259
2025-10-14 10:53:05 +02:00
Gary Pendergast 0154286caa FIX: Treat the topic status enabled param as a truthy value. (#35366)
When making requests to `/t/:id/status.json`, the behaviour of the
`enabled` parameter is a bit confusing: only the string `"true"` is
treated as a true value, everything else is false (including boolean
`true`, for example).

This change makes use of the ActiveModel Boolean type to cast
falsey/truthy values to `false` and `true`.
2025-10-14 16:00:19 +11:00
MeghnaandYuriy Kurant c87277b2a5 FEATURE: allow adding anchor tag to 404 page title (#35318)
<img width="1131" height="485" alt="Screenshot 2025-10-10 at 1 42 53 PM"
src="https://github.com/user-attachments/assets/bc5251dc-8461-44e1-8cc6-dc680c7fb1a9"
/>

---------

Co-authored-by: Yuriy Kurant <yuriy@discourse.org>
2025-10-10 19:29:05 +05:30
Penar Musaraj 8cbc3bcdfc UX: Better separate login and authentication settings (#33711)
This splits the Login and Authentication admin page into multiple
sections: Settings, social logins, DiscourseConnect, OAuth2.0, OIDC.
Internal ticket `t/161648`

This PR also adds a new extension point for plugins that want to extend
this area of the app.

```
register_site_setting_area("oauth2")
register_admin_config_login_route("oauth2")
```

Adding this to a plugin allows it to extend both the setting areas
(existing functionality) and add a tab to this admin settings screen via
`register_admin_config_login_route`.
2025-10-09 15:29:21 -04:00
David Taylor fd4cdf862d FEATURE: Introduce 'google_site_verification_token' site setting (#35229) 2025-10-08 11:08:33 +01:00
Jarek RadoszandLoïc Guitaut 71834c898f DEV: Update rubocop-discourse to 3.13 and autofix issues (#35073)
Co-authored-by: Loïc Guitaut <loic@discourse.org>
2025-10-06 16:11:01 +02:00
Osama Sayegh 7d2256c455 FEATURE: Split setting for allowing mods to manage categories and groups (#35174)
This commit splits the `moderators_manage_categories_and_groups` setting
into 2 separate settings to allow for more precise control over
categories and groups management by moderators.

Internal topic: t/141392.
2025-10-06 10:43:42 +03:00
Osama Sayegh a7fb9e1897 FEATURE: Allow editing theme-owned palettes (#34722)
This commit allows editing colors of palettes that are installed with
themes. Prior to this commit, editing colors of theme-owned palettes wasn't
allowed because a theme update could override the edits made by admins
and there was no way to revert edits to the original values. With this
commit, all of that is solved by copying the palette when it's first edited
by an admin, and making future updates to the theme update the original
copy only with the ability for admins to revert to the colors in the
original copy at any time.

Internal topic: t/162130.
2025-10-06 09:02:39 +03:00
Jarek RadoszandLoïc Guitaut a54e3208cb DEV: Hand-pick Rails/WhereNot autofixes (#35117)
We can't enable `Rails/WhereNot` lint/autofix, because it would break
code that uses mini_sql instead of AR (which rubocop, and tbh also we,
can't easily differentiate)

Those are safe because they either:
* are executed in AR model scope definitions
* are clearly chained starting from a AR model
* are less-clearly chained, but still can be traced to a AR model/scope

---------

Co-authored-by: Loïc Guitaut <loic@discourse.org>
2025-10-03 13:29:22 +02:00
Osama SayeghandAlan Guo Xiang Tan 0bc18fdf78 FEATURE: Add site setting to prevent mods from changing trust levels (#35160)
This commit adds a new setting `moderators_change_trust_levels` to
control whether moderators are allowed to change trust level of users.
Moderators are currently allowed to change trust levels, so this new
setting is enabled by default to avoid sudden changes in behavior for
existing sites.

When the setting is disabled and moderators are not allowed to change
trust levels, they see the trust levels dropdown disabled.

Internal topic: t/141392.

---------

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
2025-10-03 13:19:24 +03:00
Loïc Guitaut 0c41ff0680 DEV: Move more data into the server session (#35145)
Now that `ServerSession` can store arbitrary data, we can move some more
data into it.

This patch moves some data related to authentication into it, as
sometimes that kind of data can be pretty big.
2025-10-03 10:20:32 +02:00
Joffrey JAFFEUX ba7fbd6d9c FIX: notification reminder is deleted with bookmark (#35141) 2025-10-03 08:34:19 +02:00
Martin Brennan f0e0b02494 FIX: Streamline topic bump functionality and notification settings behaviour (#34945)
Followup 2a65bf4522

With the above change, we inadvertently made it so that
when you edited the topic title or category, we bumped
the topic.

This fix makes it so we do not bump topics when only title, category,
or tags are changed, to restore the previous behaviour.

In addition, we are making it so the following settings no longer
influence topic bump behaviour, keeping only their intended notification
behaviour around. The site setting description never mentioned anything
about topic bumps:

* disable_category_edit_notifications
* disable_tag_edit_notifications
2025-10-03 10:16:54 +10:00
Martin Brennan 28a58a764b Revert "FIX: notification reminder is deleted with bookmark (#35069)" (#35138)
This reverts commit 74c60fef17.

There are still some outstanding questions about bookmark notification
behaviour.
2025-10-02 17:56:51 +10:00
Ted Johansson ebb1a49ea3 UX: Show remove password button without suspense (#34635)
We have this slightly awkward UX on the Preferences > Security page, where we offer to remove the password from an account if it has other means of signing in. You need to first click a cryptic Show button which may or may not lead you to the button you want. This button loads the associated accounts so we can evaluate whether to show the Remove password button or not.

This PR loads that data when entering the route, so that we can just show the button up-front. If removing password isn't possible, the button is disabled and shows an explainer underneath.
2025-10-02 15:04:13 +08:00
Régis Hanol 3c928df615 FIX: discourse_id_challenge response when using subfolder (#35123)
Added subfolder support for #discourse-id automated registration in
874c875e02 but we were missing returning the "path" in the response
from the "discourse_id_challenge".

This ensures we also return the "path" field in the challenge so it can
properly be validatated by id.discourse.com.

Internal ref - t/161934/21
2025-10-01 18:47:33 +02:00
Loïc Guitaut 2676c70572 Revert "DEV: Move more data into the server session" (#35115)
Reverts discourse/discourse#35009
2025-10-01 16:44:43 +02:00
Loïc Guitaut 066d3a1abc DEV: Move more data into the server session (#35009)
Now that `ServerSession` can store arbitrary data, we can move some more
data into it.

This PR moves some data related to authentication into it, as sometimes
that kind of data can be pretty big.
2025-10-01 15:00:48 +02:00
Joffrey JAFFEUX 74c60fef17 FIX: notification reminder is deleted with bookmark (#35069)
Prior to this fix a user could delete a chat bookmark but the
notification reminder if it had already fired would still show in
notifications.
2025-10-01 11:58:31 +02:00
Renato Atilio 9fba48486d FIX: topic pagination overflow with deleted posts (#35081)
Uses the topic's pre-calculated `posts_count` instead of
`highest_post_number` to determine if the pagination overflows and
should return a 404.
2025-09-30 14:36:12 -03:00
Keegan George ad21ae98ff FEATURE: Bulk select posts and delete drafts (#34972)
## 🔍 Overview

This PR adds bulk selection functionality to the PostList component and
implements optimized bulk deletion for the drafts page. Users can now
select multiple drafts and delete them all at once with a single network
request, significantly improving performance and user experience.

The implementation includes:
- A new reusable bulk selection system for PostList components
- Optimized bulk delete endpoint that reduces network requests by 90%
- Comprehensive bulk controls UI with select all/clear all functionality
- Shift+click range selection similar to topic lists
- Complete test coverage for all new functionality

##  More details

**Bulk Selection System**

The PostList component now supports optional bulk selection through
these new parameters:

- `@bulkSelectEnabled={{true}}` - Shows checkboxes next to each post
- `@bulkSelectHelper={{helper}}` - Manages selection state (use
`PostBulkSelectHelper`)
- `@bulkActions={{actions}}` - Array of bulk action objects for the
dropdown menu

**Usage Example:**
```gjs
import Component from "@glimmer/component";
import { action } from "@ember/object";
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
import PostBulkSelectHelper from "discourse/lib/post-bulk-select-helper";

export default class MyComponent extends Component {
  bulkSelectHelper = new PostBulkSelectHelper(this);

  constructor() {
    super(...arguments);
    // Initial updatePosts call
    this.updateBulkSelectPosts();
  }

  @action
  updateBulkSelectPosts() {
    if (this.shouldEnableBulkSelect && this.args.posts) {
      this.bulkSelectHelper.updatePosts(this.args.posts);
    }
  }

  get showBulkSelectHelper() {
    return this.shouldEnableBulkSelect ? this.bulkSelectHelper : null;
  }

  get bulkActions() {
    return [
      {
        label: "delete_selected",
        icon: "trash-can", 
        action: this.handleBulkDelete,
        class: "btn-danger"
      }
    ];
  }

  <template>
    <PostList 
      @posts={{@posts}}
      @bulkSelectEnabled={{this.shouldEnableBulkSelect}}
      @bulkSelectHelper={{this.showBulkSelectHelper}}
      @bulkActions={{this.bulkActions}}
      {{didUpdate this.updateBulkSelectPosts @posts}}
    />
  </template>
}
```

**Performance Optimization**

The drafts page now uses a new bulk delete endpoint (`DELETE
/drafts/bulk_destroy`) that:
- Processes multiple drafts in a single HTTP request instead of N
individual requests
- Uses database transactions for atomic operations (all-or-nothing)  
- Reduces database queries from 2N to 2 total queries
- Validates draft sequences upfront to fail fast on conflicts

**Technical Implementation**

- `PostBulkSelectHelper`: New helper class for managing selection state
with support for individual selection, range selection (shift+click),
and bulk operations with reactive posts tracking
- `PostListBulkControls`: New component providing selection count,
select all/clear all buttons, and bulk actions dropdown
- Enhanced PostList and PostListItem components with conditional bulk
selection UI
- Updated user-stream component to use optimized bulk deletion with
automatic selection cleanup
- Comprehensive styling with responsive design

**API Changes**

- New controller action: `DraftsController#bulk_destroy`
- New route: `DELETE /drafts/bulk_destroy`
- New JavaScript method: `Draft.bulkClear(drafts)`
- Enhanced `PostBulkSelectHelper` with `updatePosts()` method for
reactive data updates
- Fully backward compatible - existing single delete functionality
unchanged

**Testing**

- 9 new controller specs covering bulk deletion edge cases, validation,
and API access
- 11 integration tests for PostList bulk selection functionality  
- 10 system specs for end-to-end drafts page bulk selection workflows
- All existing tests continue to pass

## 📹 Screen Recording


https://github.com/user-attachments/assets/2d5a9b38-f1cb-43ee-88ac-285b71083612
2025-09-29 12:47:54 -07:00
Alan Guo Xiang Tan 128e2f98ce DEV: Add missing test case to ApplicationController (#35001)
Follow-up to a3e5a31674 made 8 years ago
2025-09-26 12:05:44 +08:00
Loïc Guitaut da12368682 DEV: Finish renaming secure_session to server_session 2025-09-23 10:35:02 +02:00
Natalie Tay eb40b4f980 DEV: Plugin api for saving category attribute (#34898)
This commit adds `register_category_update_param_with_callback` to the
plugin API, allowing plugins to register category parameters and apply a
transactional callback relating to the param. The callback receives the
category instance and parameter value, and any exception raised will
roll back the category update.

  Example usage:
```
    register_category_param_with_transaction_callback(:doc_index_topic_id) do |category, value|
      DocCategories::CategoryIndexManager.new(category).assign!(value)
    end
```

In the example above, `doc_index_topic_id` will be added to
`permitted_params` in the category controller on update, and the
callback will be invoked on `after_update`, to ensure the category save
does not happen if the callback fails.

**Dev note**: I had considered creating a `CategoryExtension` and just
doing the typical `Category.prepend`, but I thought a plugin API is
probably better.
2025-09-23 11:14:45 +08:00
Juan David Martínez Cubillos 587a180a66 FIX: DiscourseConnect provider redirect to forum instead of the sso_redirect_url in the payload (#34580)
**Description**

Currently, when using Discourse as an SSO provider through the
DiscourseConnect provider, if a user logs in using the login form, the
user is not redirected to the expected `return_sso_url`. Instead, it is
redirected to the forum's home page. This fixes this behaviour and
allows the user to return to the expected URL.
2025-09-19 15:09:34 +02:00
Loïc Guitaut 3fc6511278 FIX: Don’t store return path in the session
Since the session is backed by a cookie, storing too much data will lead
to a cookie overflow error.

A return path can be quite large sometimes, so intead of storing it in
the session, this patch stores it in our server session.
2025-09-19 10:05:20 +02:00
Colby Howell 7f40857a85 FIX: Allow reverting topic revisions with only tag changes (#34169)
Allow for tag-only revisions to be reverted through the UI.

Fixes: https://meta.discourse.org/t/cannot-undo-a-revision-if-it-only-includes-tag-edits/366439/3
2025-09-18 18:26:52 -07:00
Loïc Guitaut b4e4833d2a DEV: Rename SecureSession to ServerSession
This patch will be followed by
https://github.com/discourse/discourse/pull/34747.

`SecureSession` doesn’t make a lot of sense anymore and can be confusing
as the current cookie store used for the session is actually secure
since it’s encrypted.

Renaming it to `ServerSession` better conveys what it does: providing a
session but on the server side only.

This patch also makes some improvements, like injecting that server
session into Rack-like request objects, allowing the server session to
be available virtually everywhere.
2025-09-18 16:31:03 +02:00
Blake Erickson 0f91ce6079 DEV: Update api docs spec for invite enpoint (#34843)
This commit converts the api docs spec for the invite endpoint to use
the new json schema file format.
2025-09-17 14:50:53 -05:00
Blake Erickson 416e9b1048 DEV: API docs update for update group endpoint (#34823)
Update rspec api doc test to follow new format and use the shared
success_ok_response.
2025-09-16 07:35:57 -06:00
Blake Erickson c5d9a1b7a1 DEV: Update latest_posts api docs (#34807)
Just updating the api docs for GET /posts.json to match the format we
have been following with other endpoints where the response json is loaded
from a separate file instead of inline in the spec file.
2025-09-15 10:38:26 -06:00
Ted Johansson b36747163b FEATURE: Allow hiding user fields on signup form (#34672)
We want to allow configuring fields that are both optional and editable to not show up in the signup form.

- Fields that are optional but not editable need to be on the signup form, or they can never be filled in.
- Fields that are not optional need to be on the signup form, or you can never sign up.
2025-09-15 10:42:07 +08:00
Bianca Nenciu d82fcb8af8 FIX: Validate email length (#34786)
* The maximum total length of a user name or other local-part is 64
octets.

* The maximum total length of a domain name or number is 255 octets.
2025-09-11 18:58:07 +03:00
Penar MusarajandMartin Brennan 6f3a52c30d DEV: Add configurable limit for page param in TopicQuery (#34728)
Prevents pathological issues with crawlers querying topic lists with
very large page parameters. The new limit also allows us to tweak this
under specific instances or circumstances (high traffic, for example).

A `page` parameter above the limit will throw an `InvalidParameters`
400 error.

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
2025-09-04 12:20:44 -04:00
lewisakura b1ea35bb30 FEATURE: managed auth can override avatars (#34123)
This is mostly just a duplication of the equivalent DiscourseConnect
feature, but applies to managed authenticators instead.

FR:
https://meta.discourse.org/t/avatar-is-synching-only-on-creation/304286
2025-09-02 12:49:43 -04:00