BEFORE: if you click the "reply" button on a post and then decided that you want to "edit" the same post, clicking the "edit" button would do nothing. Clicking "edit" on another post works, but editing the same post would appear broken.
AFTER: if you click the "edit" button, it will properly load the content of the post you're trying to edit. No matter which one it is.
This was somewhat tricky to track down as the system specs seemed to contradict the qunit tests until I realized that the qunit tests were only testing the edit on the 1st post and the system specs were testing on replies.
I improved the qunit tests to test both editing OP and a reply and (hopefully) made the system specs a little bit clearer.
This is a follow up to bbe62d88d2.
In order to limit issues with duplicate inline CSS definitions, this will now deduplicate inline CSS styles with the "last-to-be-defined-wins" strategy.
Also removes unecessary whitespaces in inline styles.
Context - https://meta.discourse.org/t/resolve-final-styles-in-email-notifications/310219
Co-authored-by: Thomas Kalka <thomas.kalka@gmail.com>
The hierarchical search for categories is composed of several complex
nested queries. This change ensures that the secured categories are
filtered out as soon as possible to ensure that the default limit of 5
categories is reached.
Without this fix, the search can return less than 5 categories if any
of the first 5 categories cannot be displayed due to permissions.
Non-admin/moderator users can bulk select items in new/unread, but not in
latest/top/hot. This commit ensures that when the user can no longer
bulk select items in a list, the bulk select checkboxes in the topic list
rows are hidden.
Spec was flaky cause work could still be in pipeline after the defer
length is 0. Our length denotes the backlog, not the in progress
count.
This adds a mechanism for gracefully stopping the queue and avoids
wait_for callse
We already add the "delete user" and "delete and block user" options to the drop-down for potential spam, but we should do this for potentially illegal posts as well.
This is entirely based on the implementation for the potential spam one, including caching the status on the reviewable record.
Also note that just as for potential spam, the user must be "deletable" for the option to appear.
I also took the liberty to move the options in the drop-down to what I think is a more intuitive place. (Between delete post and suspend/silence user.)
Sometimes changes to "What's new?" feed items are made or the feed items are
removed altogether, and the polling interval to check for new features is 1 day.
This is quite long, so this commit introduces a "Check for updates"
button for admins to click on the "What's new?" page which will bust
the cache for the feed and check again at the new features endpoint.
This is limited to 5 times per minute to avoid rapid sending of
requests.
* FEATURE: Add `freeze_original` option to `PostMover`
This option will allow the api user to specify if the original topic should be `frozen`(locked and posts not deleted neither moved)
With this option when moving topic posts your posts will be `copied` to the new topic and the original topic will be kept there.
* DEV: update tests to check raw instead of ids
* DEV: Implement `freeze_original` option for `PostMover`
update specs to use `*array` matcher
* DEV: add tests to `MovedPost` model in post mover
* DEV: Update `MovedPost` model rspec
* DEV: add back empty line to `post_mover.rb`
* FIX: Solve flaky tests in `PostMover`
* FEATURE: Add `freeze_original` option to `PostMover`
This option will allow the api user to specify if the original topic should be `frozen`(locked and posts not deleted neither moved)
With this option when moving topic posts your posts will be `copied` to the new topic and the original topic will be kept there.
* DEV: update tests to check raw instead of ids
* DEV: Implement `freeze_original` option for `PostMover`
update specs to use `*array` matcher
* DEV: add tests to `MovedPost` model in post mover
* DEV: Update `MovedPost` model rspec
* DEV: add back empty line to `post_mover.rb`
We ran into an edge case where it was possible for a
ReviewableFlaggedPost to end up in a state where it was hidden
and the topic was already deleted. This meant that the Ignore
action bundle for the reviewable ended up empty, with no associated
actions.
This commit fixes the server-side issue where this was ending up
empty. A further commit will aim to make the client more resilient
to these issues by gracefully failing if a reviewable action bundle
is detected with no associated actions.
The Admin UI guidelines states that buttons should have text, not icons. This was an oversight on the admin emoji listing.
Part of this change is also opportunistically removing the CSS file for admin emojis, none of which is used any more since the conversion.
At the top of the theme show page we have a link
to the theme About and License, which are supposed
to be URLs. However some themes have left placeholder
text in these metadata fields, which leads to a wonky
experience.
Instead, we can just not serialize these fields if they
are not valid URLs, then they will not show as links
in the UI.
This fix handles the case where an In-Reply-To mail header
can contain multiple Message-IDs. We use this header to
try look up an EmailLog record to find the post to reply
to in the group email inbox flow.
Since the case where multiple In-Reply-To Message-IDs is
rare (we've only seen a couple of instances of this causing
errors in the wild), we are just going to use the first one
in the array.
Also, Discourse does not support replying to multiple posts
at once, so it doesn't really make sense to use multiple
In-Reply-To Message-IDs anyway.
Previously, the secure-upload redirection logic would fail for extension-less files. This commit updates it to work, and adds a spec for the behavior.
Extension-less file uploads are not allowed by default, so this is a very niche situation.
* DEV: Gracefully handle `regex_replace` violations of column length constraints
This is a follow-up to the `remap` [refactor](9b0cfa99c5).
Similar to `remap`, the entire `regex_replace` operation fails if the new content exceeds the column’s max length.
This change introduces an optional mode, controlled by the new `skip_max_length_violations` param
to skip records eligible for `regex_replace` where the new content violates the max column length constraint.
It also includes updates to the exception message raised when `regex_replace` fails to include more details
* DEV: Remove string escapes in heredoc text
This commit introduces a new feature that allows staff to bulk select and delete users directly from the users list at `/admin/users/list`. The main use-case for this feature is make deleting spammers easier when a site is under a large spam attack.
Internal topic: t/140321.
Uploads that are linked to site settings shouldn't be flagged as secure in login-required sites that enable secure uploads. However, in order for site setting uploads to not be marked secured, the frontend uploader has to include 2 params in the upload request: `for_site_setting: true` and `type: "site_setting"`.
Since these 2 params are semantically identical, we want the `type: "site_setting"` param alone to make the upload correctly treated as a site setting upload. To achieve that, we need to include the `site_setting` type in the public types list because the `for_site_setting` param has the same effect — it marks the upload as a public type.
b138eaf9e5/lib/upload_security.rb (L128-L131)
We recently tried to default the normalize_emails site setting to true to avoid spam. What this does is it considers e-mails the same regardless of plus addressing, e.g. bob+1@mail.com == bob+2@mail.com. This caused some problems for SSO users.
This PR makes it so that DiscourseConnect never normalizes e-mails.
This moves the logic of setting the correct permalink values back into the controller. And it replaces the validation with a simpler one, that always works, even when the model is loaded from the DB.
Follow-up to #29634 which broke import scripts and lots of documentation on Meta.
- Add bulk actions component on /filter page for both desktop & mobile view.
- Add system specs to assert bulk actions to be available on /filter page.
while it is ok to have the check for if the person can delete a topic, for this feature some times you might want some more flexibility.
Instead of relying on patching this class and method, it would be better to have a modifier that can be decide if the topic should be deleted after the merge.
Sometimes `Jobs::PushNotification` gets stuck, probably because of the
network call. This commit replaces `Excon` with `FinalDestination::HTTP`
which is safer.
This commit is going to try using the `have_read_post` page object from
`topic_view` instead of the page object for `topic` because it's
implementation has a longer wait time as it uses the ENV variable for
wait time: `Capybara.default_max_wait_time * 2`.
If this works out we should probably remove the duplicated
`have_read_post` page object so that we have a single implementation.
This spec helper was introduced as a temporary solution to the problem
of mismatched types between primary key and foreign key columns. All
plugins have been migrated and the only remaining use of this helper is
in core Discourse.
This patch adds a new step to services named `try`.
It’s useful to rescue exceptions that some steps could raise. That way,
if an exception is caught, the service will stop its execution and can
be inspected like with any other steps.
Just wrap the steps that can raise with a `try` block:
```ruby
try do
step :step_that_can_raise
step :another_step_that_can_raise
end
```
By default, `try` will catch any exception inheriting from
`StandardError`, but we can specify what exceptions to catch:
```ruby
try(ArgumentError, RuntimeError) do
step :will_raise
end
```
An outcome matcher has been added: `on_exceptions`. By default it will
be executed for any exception caught by the `try` step.
Here also, we can specify what exceptions to catch:
```ruby
on_exceptions(ArgumentError, RuntimeError) do |exception|
…
end
```
Finally, an RSpec matcher has been added:
```ruby
it { is_expected.to fail_with_exception }
# or
it { is_expected.to fail_with_exception(ArgumentError) }
```
As part of a previous fix we changed which groups are serialized for a user, in order to fix a bug in the default group selector under user preferences.
However, we should only change this when serializing the current user. This change combines the old code-path and the new based on who is serializing.
* DEV: Gracefully handle remaps which violate DB column constraints
This change implements length constraint enforcement to skip remaps
which exceed column max lengths
* DEV: Only perform skipped column stats lookup when verbose is true
* DEV: Tidy up specs
* DEV: Make skipping violating remap behaviour opt-in
This change introduces a new `skip_max_length_violations` param for
`remap`, set to `false` by default to ensure we still continue to fail
hard when max lenth constraints are violated.
To aid in quick resolution when remaps fail, this change also
adds more context to the exception message to include the offending table
and column information
* Apply suggestions from code review
Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org>
* FIX: Various fixes
- Linter errors
- Remap status "logger" early return condition
---------
Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org>
Firstly, we need to understand that ActiveRecord can be
connected to a role which prevent writes and this happens in Discourse when a
replica database has been setup for failover purposes. When a role
prevent writes from happening, ActiveRecord will raise the
`ActiveRecord::ReadOnlyError` if a write query is attempted.
Secondly, theme fields are baked at runtime within GET requests. The
baking process involves writing the baked value to the
`ThemeField#baked_value` column in the database.
If we combine the two points above, we can see how the writing of the
baked value to the database will trigger a `ActiveRecord::ReadOnlyError`
in a GET requests when the database is connected to a role preventing
writes. However, failing to bake a theme is not the end of the world and
should not cause GET requests to fail. Therefore, this commit adds a rescue
for `ActiveRecord::ReadOnlyError` in the `ThemeField#ensure_baked!`
method.
Followup 0568d36133
Followup 97cf069a06
Due to the S3 dualstack endpoint change, sites with
S3 backups configured but _not_ S3 uploads were erroring,
with admins unable to access the backups page. This
commit fixes the error by not enabling S3 dualstack
endpoints if S3 uploads have not been enabled, backups
don't need to use them.
c.f. https://meta.discourse.org/t/unable-to-backup-or-navigate-to-backups/335899
When using chat in drawer mode, after you've clicked on a chat bookmark in the user menu, clicking any other chat bookmark would "do nothing".
In 8b18fd1556 we added an optimization to prevent the same route from being reloaded, but it ended up breaking the bookmarks.
This commit reverts the changed made the above commit and adds a system specs that ensure we can click two chat bookmarks in the user menu when using chat in drawer mode.
Internal ref - t/134362
* FEATURE: Add skip notification option to group invite to topic
* DEV: rename `skip_notification` to `should_notify`
* DEV: update `should_notify` param to be default `true` in controllers
* DEV: update spec to use `greater than` instead of `equal to` to prevent flakiness
* Update app/controllers/topics_controller.rb
Co-authored-by: David Taylor <david@taylorhq.com>
* DEV: merged two `#invite_group` specs into one
* DEV: Added test case for `invite-group` in requests spec
---------
Co-authored-by: David Taylor <david@taylorhq.com>
When a parent category shows topics from subcategories, dismissing
should dismiss posts in both parent and subcategories.
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
- Uses a more appropriate image, with immutable tag (so update prompts work correctly)
- Updates port forwarding
- Improves mount setup (inc. persistant PG/Redis when rebuilding)
- Fixes ember-cli live reload
- Automatically configures VSCode & extensions
Redesign the permalinks page to follow the UX guide. In addition, the ability to edit permalinks was added.
This change includes:
- move to RestModel
- added Validations
- update endpoint and clear old values after the update
- system specs and improvements for unit tests
Follow up to 6f8f6a7726
Prior to the linked commit, the `uploads#create` endpoint had a `upload_type` and `type` param that acted as aliases for each other and raised an error if both of them were missing. In the linked commit, we removed the `type` param and always required the `upload_type` param which break API consumers that only included `type` in their requests.
This commit adds back the `type` param temporarily and introduces a deprecation message for it so that API consumers are made aware of the eventual removal of the `type` param.
These URLs allow the state of a headless browser to be viewed and debugged using any other browser, without needing to restart the test with `SELENIUM_HEADLESS=0`.
It splits the hide_profile_and_presence user option and the default_hide_profile_and_presence site setting for more granular control. It keeps the option to hide the profile under /u/username/preferences/interface and adds the presence toggle in the quick user menu.
Co-authored-by: Régis Hanol <regis@hanol.fr>
This is a very simple change, which creates a permanent table in the DB, rather than generating a temporary table when moving posts. This change is about capturing data and any usage will appear in a follow-up.
I did include a new column created_new_topic in the new table, so that it can be easily audited without having to compare destination topic created_at with moved_post records.
This commit modernizes the post menu by migrating it from the existing widget-based implementation to Glimmer components. This transition aims to improve the maintainability, performance, and overall developer experience.
It also introduces a new DAG-based transformer API for customizations that aims to be more flexible than the widget base one.
---------
Co-authored-by: David Taylor <david@taylorhq.com>
This commit removes the new optimized category style introduced in
previous commits (d37a0d40, 9a80d718 and 430c42ac), in favour of the
existent `categories_only`.
When performing bulk dismissal in Unread and New views, the dismiss button stays at the top of the UI. Because of this we want to provide the dismiss action also in the "sticky" menu that's always in view, even when scrolling a long list of topics.
This reverts commit 5a00a041f1.
Implementation is currently not correct. Multiple uploads can share the
same etag but have different paths in the S3 bucket.
Follow-up to a5497b74be
In the linked commit, as part of simplifying the invite modal, we removed the option to skip sending an email when creating an invite restricted to a specific address. This has caused confusion about whether an email will be sent by Discourse or not, so we're adding back the option to create a restricted invite without emailing.
Internal topic: t/134023/48.
Followup 0568d36133
S3 itself and other S3-compatible providers do not
allow using an S3 custom endpoint and dualstack at
the same time, so this commit fixes that by not using
dualstack when the endpoint is present.
A "bad upload" in this context is a upload with a mismatched URL. This can happen when changing the S3 bucket used for uploads and the upload records in the database have not been remapped correctly.
"Resume editing" would do nothing when going through the `/new-message` flow.
This seems to be broken since [this commit](b0f6d074be). which moved `this._setModel` calls around – the same we're doing now, but to different places: the first one needs to happen after the `draft.data` has been set , while the second needs to happen before the `this.open` call.
When we added direct S3 uploads to Discourse, which use
presigned URLs, we never took into account the dualstack
endpoints for IPv6 on S3.
This commit fixes the issue by using the dualstack endpoints
for presigned URLs and requests, which are used in the
get-presigned-put and batch-presign-urls endpoints used when
directly uploading to S3.
It also makes regular S3 requests for `put` and so on use
dualstack URLs. It doesn't seem like there is a downside to
doing this, but a bunch of specs needed to be updated to reflect this.
This PR adds a small visual change to the new feature item on the `/admin/whats-new` page. When features are marked with an experimental site setting, they should show an indication on the feature item that it is "Experimental"
Currently, if an association is added as a tracked field in
`PostRevisor`, the `PostRevisionSerializer` class will try to serialize
it somehow. This will raise an error as ActiveRecord collection proxies
can't be serialized.
This patch addresses this issue by skipping any association tracked by
the `PostRevisor` class.
Prior to Uppy, the `uploads#create` endpoint used to receive a `type` param that indicated the purpose/target of the upload, such as `avatar`, `site_setting` and so on. With the introduction of Uppy, the `type` param became the MIME type of the file being uploaded, and the purpose/target of the upload became a new param called `upload_type`, however the backend could still use the `type` param (which now contains MIME type) as the purpose/target of the upload if `upload_type` is absent.
We technically don't need to send the MIME type over the network, but it seems like it's done by Uppy and we have no control over the `type` param that Uppy includes:
758de8167b/app/assets/javascripts/discourse/app/lib/uppy/uppy-upload.js (L146-L151)
This commit does a couple of things:
1. It amends the `uploads#create` endpoint so it always requires the `upload_type` param and doesn't fallback to `type` if `upload_type` is absent
2. It forces consumers of the `UppyUpload` class (and by extension `UppyImageUploader`) to specify `type` of the upload
Internal topic: t/140945.
The normalize_emails setting makes it so that only canonical e-mails are considered for validation purposes. This means disallowing "plus addressing". For example, with this enabled, bob@discourse.org and bob+foo@discourse.org are considered the same address, and you can only sign up with one of them.
Currently this is disabled by default, leading to a lot of spam sign-ups. It's healthier to consider this an opt-out setting.
This commit adds an API `upload_image` to `FormKitField` page object for setting an image file on an `Image` field in FormKit. Usage is like this:
```ruby
form.field("image_field").upload_image(image_path)
```
The `value` API also now supports `Image` fields; it returns an `Upload` record if the field has an uploaded image.
Recently we added a new feature for automatically gridding images in the composer (https://github.com/discourse/discourse/pull/29260). After testing this feature under a setting for a short period of time, the feature is no longer experimental anymore.
This PR removes the site setting `experimental_auto_grid_images`.
The primary key is usually a bigint column, but the foreign key columns
are usually of integer type. This can lead to issues when joining these
columns due to mismatched types and different value ranges.
This was using a temporary plugin / test API to make tests pass. After
more careful consideration, we concluded that it is safe to alter the
tables directly.