Commit Graph

1295 Commits

Author SHA1 Message Date
Loïc Guitaut 584424594e DEV: Replace `params` by the contract object in services
This patch replaces the parameters provided to a service through
`params` by the contract object.

That way, it allows better consistency when accessing input params. For
example, if you have a service without a contract, to access a
parameter, you need to use `params[:my_parameter]`. But with a contract,
you do this through `contract.my_parameter`. Now, with this patch,
you’ll be able to access it through `params.my_parameter` or
`params[:my_parameter]`.

Some methods have been added to the contract object to better mimic a
Hash. That way, when accessing/using `params`, you don’t have to think
too much about it:
- `params.my_key` is also accessible through `params[:my_key]`.
- `params.my_key = value` can also be done through `params[:my_key] =
  value`.
- `#slice` and `#merge` are available.
- `#to_hash` has been implemented, so the contract object will be
  automatically cast as a hash by Ruby depending on the context. For
  example, with an AR model, you can do this: `user.update(**params)`.
2024-10-25 14:48:34 +02:00
Loïc Guitaut 41584ab40c DEV: Provide user input to services using `params` key
Currently in services, we don’t make a distinction between input
parameters, options and dependencies.

This can lead to user input modifying the service behavior, whereas it
was not the developer intention.

This patch addresses the issue by changing how data is provided to
services:
- `params` is now used to hold all data coming from outside (typically
  user input from a controller) and a contract will take its values from
  `params`.
- `options` is a new key to provide options to a service. This typically
  allows changing a service behavior at runtime. It is, of course,
  totally optional.
- `dependencies` is actually anything else provided to the service (like
  `guardian`) and available directly from the context object.

The `service_params` helper in controllers has been updated to reflect
those changes, so most of the existing services didn’t need specific
changes.

The options block has the same DSL as contracts, as it’s also based on
`ActiveModel`. There aren’t any validations, though. Here’s an example:
```ruby
options do
  attribute :allow_changing_hidden, :boolean, default: false
end
```
And here’s an example of how to call a service with the new keys:
```ruby
MyService.call(params: { key1: value1, … }, options: { my_option: true }, guardian:, …)
```
2024-10-25 09:57:59 +02:00
Jarek Radosz 587264f9d2
DEV: Remove extraneous spec code (#29386)
namely `js: true`, requiring `rails_helper`, and default `freeze_time` args
2024-10-24 14:15:32 +02:00
Krzysztof Kotlarek cd077ef93b
FIX: visual regression for new features (#29359)
Bug introduced in this PR https://github.com/discourse/discourse/pull/29244

When the experiment toggle button was introduced, new features did not look right when the toggle button was not available.

In addition, the plugin name can be an empty string. In that case, information about new features should be displayed.
2024-10-23 16:16:19 +11:00
Loïc Guitaut f79dd5c8b5 DEV: Stop injecting a service result object in the caller object
Currently, when calling a service with its block form, a `#result`
method is automatically created on the caller object. Even if it never
clashed so far, this could happen.

This patch removes that method, and instead use a more classical way of
doing things: the result object is now provided as an argument to the
main block. This means if we need to access the result object in an
outcome block, it will be done like this from now on:
```ruby
MyService.call(params) do |result|
  on_success do
    # do something with the result object
    do_something(result)
  end
end
```

In the same vein, this patch introduces the ability to match keys from
the result object in the outcome blocks, like we already do with step
definitions in a service. For example:
```ruby
on_success do |model:, contract:|
  do_something(model, contract)
end
```
Instead of
```ruby
on_success do
  do_something(result.model, result.contract)
end
```
2024-10-22 16:58:54 +02:00
Gerhard Schlager 07ff21d045
FIX: Restoring backup could fail due to missing `discourse_functions` (#29332)
Database dumps sometimes reference functions in the `discourse_functions` schema. It's possible that some of these functions have been dropped in a newer version of Discourse. In that case, restoring an older backup will fail with a `ERROR:  function discourse_functions.something_something() does not exist` error. The restore functionality contains a workaround for that problem, but it didn't work with functions created in plugin migrations.

This commit adds support for temporarily creating missing `discourse_functions` from plugins. And it adds a simple check if the DB migration file even contains the required `DROPPED_TABLES` or `DROPPED_COLUMNS` constant. We don't need to create an instance of the DB migration class unless one of those constants is used. This makes the restore slightly faster and works around a problem with migrations that execute without `up` or `down` methods (e.g. `BackfillChatChannelAndThreadLastMessageIdsPostMigrate`).
2024-10-22 16:13:01 +02:00
Krzysztof Kotlarek 433fadbd52
FEATURE: allow admins to enable announced experimental features (#29244)
Toggle the button to enable the experimental site setting from "What's new" announcement.

The toggle button is displayed when:
- site setting exists and is boolean;
- potentially required plugin is enabled.
2024-10-22 10:56:58 +11:00
Régis Hanol 88449541a5
FIX: participating users statistics... (#29293)
* FIX: participating users statistics...

... was (mis-)counting

- bots
- anonymous users
- suspended users

There's now a "valid_users" function that holds the AR query for valid users and which is used in all "users", "active_users", and "participating_users" queries.

Internal ref - t/138435
2024-10-21 18:18:42 +02:00
Ted Johansson 56df077931
FIX: Don't error out on empty reserved_usernames setting (#29305)
We're seeing errors in logs due to some sites setting the reserved_usernames setting to nil. This is causing multiple use cases upstream of User#reserved_username? to error out.

This commit changes from using the raw #reserved_usernames to using the #reserved_usernames_map helper which exists on list-type site settings. It returns an empty array if the raw value is nil or empty string.
2024-10-21 14:38:37 +08:00
David Battersby 48308a5ee6
FIX: show lightbox for small images (#29140)
We want to allow lightboxing of smaller images, even if they are below the minimum size for image thumbnail generation.

This change sets a minimum threshold of 100 x 100 pixels for triggering the lightbox.

---------

Co-authored-by: Régis Hanol <regis@hanol.fr>
2024-10-18 09:45:08 +04:00
Loïc Guitaut 23c486799f DEV: Improve `array` type in service contracts
This patch improves the custom `array` type available in contracts.
It’s now able to split strings on `|` on top of `,`, and to be more
consistent, it also tries to cast the resulting items to integers.
2024-10-17 17:02:02 +02:00
Juan David Martínez Cubillos 789aa2d9de
DEV: Add PluginRegistry modifiers to #review and #recalculate (#29128)
* DEV: Add PluginRegistry modifiers to #review and #recalculate

* added tests

* changed added registry logic
2024-10-16 10:26:10 -05:00
Loïc Guitaut 281570226b DEV: Output failing MF keys when compilation fails
Currently, when the MessageFormat compiler fails on some translations,
we just have the raw output from the compiler in the logs and that’s not
always very helpful.

Now, when there is an error, we iterate over the translation keys and
try to compile them one by one. When we detect one that is failing, it’s
added to a list that is now outputted in the logs. That way, it’s easier
to know which keys are not properly translated, and the problems can be
addressed quicker.

---

The previous implementation of this patch had a bug: it wasn’t handling
locales with country/region code properly. So instead of iterating over
the problematic keys, it was raising an error.
2024-10-15 12:45:23 +02:00
Jeff Wong d92d65fe73
Revert "DEV: Output failing MF keys when compilation fails" (#29200)
This reverts commit 8eff922ace.
2024-10-14 17:42:36 -07:00
Mark VanLandingham 882c2da29e
DEV: Add modifier to SuggestedTopicsBuilder#add_results (#29164) 2024-10-10 10:03:26 -05:00
Jarek Radosz 8105b545c3
DEV: Fix random typos (#29161) 2024-10-10 16:11:55 +02:00
Kelv 32e261ef73
DEV: Migrate user passwords data to UserPassword table (#28746)
* Add migrations to ensure password hash is synced across users & user_passwords

* Persist password-related data in user_passwords instead of users

* Merge User#expire_old_email_tokens with User#expire_tokens_if_password_changed

* Add post deploy migration to mark password-related columns from users table as read-only

* Refactored UserPassword#confirm_password? and changes required to accommodate hashing the password after validations
2024-10-10 09:23:06 +08:00
Alan Guo Xiang Tan ed6c9d1545
DEV: Call Discourse.redis.flushdb after the end of each test (#29117)
There have been too many flaky tests as a result of leaking state in
Redis so it is easier to resolve them by ensuring we flush Redis'
database.

Locally on my machine, calling `Discourse.redis.flushdb` takes around
0.1ms which means this change will have very little impact on test
runtimes.
2024-10-09 07:19:31 +08:00
Loïc Guitaut 229773e7a8 DEV: Drop `OpenStruct` for the context object in services
While using `OpenStruct` is nice, it’s generally not a very good idea as
it usually leads to performance problems.

The `OpenStruct` source code even says basically to avoid it.

Since the context object is crucial in our services, this patch replaces
`OpenStruct` with a custom implementation instead.
2024-10-08 10:34:55 +02:00
Penar Musaraj 92ac6be82a
SECURITY: prevent topic list filtering by hidden tags for unathorized users
This fixes an issue where unathorized users were able to filter topics
by tags that are hidden from them.
2024-10-07 11:48:55 +08:00
Loïc Guitaut 8eff922ace DEV: Output failing MF keys when compilation fails
Currently, when the MessageFormat compiler fails on some translations,
we just have the raw output from the compiler in the logs and that’s not
always very helpful.

Now, when there is an error, we iterate over the translation keys and
try to compile them one by one. When we detect one that is failing, it’s
added to a list that is now outputted in the logs. That way, it’s easier
to know which keys are not properly translated, and the problems can be
addressed quicker.
2024-10-04 23:38:27 +09:00
Loïc Guitaut fc1c5f6a8d DEV: Have `contract` take a block in services
Currently in services, the `contract` step is only used to define where
the contract will be called in the execution flow. Then, a `Contract`
class has to be defined with validations in it.

This patch allows the `contract` step to take a block containing
validations, attributes, etc. directly. No need to then open a
`Contract` class later in the service.

It also has a nice side effect, as it’s now easy to define multiples
contracts inside the same service. Before, we had the `class_name:`
option, but it wasn’t really useful as you had to redefine a complete
new contract class.
Now, when using a name for the contract other than `default`, a new
contract will be created automatically using the provided name.

Example:
```ruby
contract(:user) do
  attribute :user_id, :integer

  validates :user_id, presence: true
end
```
This will create a `UserContract` class and use it, also putting the
resulting contract in `context[:user_contract]`.
2024-10-02 17:00:01 +09:00
Sam baeca887d9
FEATURE: improve the suppression for admins when required (#29041)
Previously admins could still click on topics when `suppress_secured_categories_from_admin` was set

This change improves the block so admins without permission will not be allowed to click through till they add themselves to appropriate groups

Keep in mind this setting is a quality of life setting and not a SECURITY
setting, admins have an infinite way of bypassing visiblity limits
2024-10-02 10:52:02 +10:00
Daniel Waterworth c544686540
DEV: Add expires flag to enable_readonly (#29033)
... to control whether readonly mode expires or not.
2024-09-30 13:59:51 -05:00
Bianca Nenciu e2f3474bc3
FIX: permanent delete of posts by deleted users (#28992)
Permanently deleting posts that no longer have a user associated was not
working as expected because of UserAction.log which expected user_id to
be present.
2024-09-24 12:26:31 +03:00
Loïc Guitaut 78d9f9fa40 DEV: Rename `ServiceRunner` to `Service::Runner` for consistency 2024-09-20 10:04:42 +02:00
Loïc Guitaut afdb1ac0a0 DEV: Disallow default params in service steps
With the current implementation, a service step can be written as:
```ruby
def my_step(a_default_value: 2)
  …
end
```
That’s a pattern we want to avoid as default values (if needed) should
be probably defined in a contract.

This patch makes a service raise an exception if a default value is
encountered.
2024-09-19 14:47:55 +02:00
Loïc Guitaut fe1098ebac FIX: Don’t raise on some search terms
Currently, when certain search terms are provided, this can lead to
`Search.need_segmenting?` raising an error because it makes `URI#path`
to return `nil` instead of a string.

This patch forces a cast to string so it won’t raise anymore.
2024-09-19 11:35:10 +02:00
Linca 741e9d70ad
FIX: Don't show move topic for private messages for TL4 (#28871)
In TopicController, in addition to ensure_can_move_posts!, we also
checked if the topic is private message in this line:

```ruby
raise Discourse::InvalidAccess if params[:archetype] == "private_message" && !guardian.is_staff?
```

However, this was not present in `guardian.can_move_posts?`. As a result,
the frontend topic view got an incorrect serialized result, thinking
that TL4 could move the private message post. In fact, once they tried
to move it, they got the `InvalidAccess` error message.

This commit fixes that TL4 will no longer sees the "move to" option in
the "select post" panel for a private message.
2024-09-16 11:30:05 +08:00
Osama Sayegh 64b67e0a4f
FIX: Exclude inactive and silenced users from /about page stats (#28877)
The user directory (`/u`) excludes inactive and silenced users from the list, so for the sake parity, it makes sense to also exclude those users from the /about page stats.

Internal topic: t/70928.
2024-09-12 22:28:49 +03:00
Martin Brennan 78268ca767
DEV: Fix another report flaky (#28868)
Followup 0323b366f3

This was happening because another spec was adding a
report using the plugin API, but there was nothing
resetting that, so later in the reports controller
when we did Report.singleton_methods, we ended up
with another report with no translation, causing another
error.
2024-09-12 10:34:38 +10:00
Krzysztof Kotlarek 1f1709d249
FIX: use a custom prefix for custom flags (#28839)
Currently, when the custom flag has the same name as the system flag (which is disabled) then it is not displayed. To fix the problem, `custom_` prefix as `name_key` is used to distinguish between the system and the custom flag.

I considered writing a migration to fix existing custom flags name key. However, at the end of migration I would need to run rails code to reset cache `Flag.reset_flag_settings!`. I decided to skip that step as it is a very edge case. If someone has the same flag name as the system flag, then all they have to do is edit the flag and click save.

In addition, I made 2 small fixes:
- edit flag title was missing translation;
- flag form UI was not showing that description is the required field.
2024-09-11 15:30:20 +10:00
David Taylor 7d8974d02f
UX: Upgrade to fontawesome 6.6.0 (#28778)
This upgrade is designed to be fully backwards-compatible. Any icon names which have changed will be automatically remapped to the new name. For now, this will happen silently. In future, once core & official themes/plugins have been updated, we will start raising deprecation errors to help theme/plugin authors update their code.

Extracted from https://github.com/discourse/discourse/pull/28715

Announcement at https://meta.discourse.org/t/were-upgrading-our-icons-to-font-awesome-6/325349

Co-authored-by: awesomerobot <kris.aubuchon@discourse.org>
2024-09-09 14:40:56 +01:00
Sérgio Saquetim f8e3a90ab9
DEV: Forces custom search filter matchers to be case insensitive (#28785) 2024-09-06 12:30:51 -03:00
Jarek Radosz 02f8396cfc
DEV: Remove `register_color_scheme` api (#28777)
This was added 10 years ago, but currently there's not a single use in our public and private plugins and no reference in third-party plugins on github
2024-09-06 17:26:53 +02:00
Gabriel Grubba a98d3d40f2
FEATURE: Add user to topic_tags_changed event (#28714)
* FEATURE: Add user to topic_tags_changed event

Add user to topic_tags_changed event context
Update automation plugin with new arguments in event
Update tests for new arguments

relates to https://github.com/discourse/discourse-chat-integration/pull/214

* DEV: change variable name for better readability

changed `tags` to be payload and used `values_at` to get the values of the keys
2024-09-06 11:23:30 -03:00
Loïc Guitaut e94707acdf DEV: Drop `WithServiceHelper`
This patch removes the `with_service` helper from the code base.
Instead, we can pass a block with actions directly to the `.call` method
of a service.

This simplifies how to use services:
- use `.call` without a block to run the service and get its result
  object.
- use `.call` with a block of actions to run the service and execute
  arbitrary code depending on the service outcome.

It also means a service is now “self-contained” and can be used anywhere
without having to include a helper or whatever.
2024-09-05 09:58:20 +02:00
Osama Sayegh 280adda09c
FEATURE: Support designating multiple groups as mods on category (#28655)
Currently, categories support designating only 1 group as a moderation group on the category. This commit removes the one group limitation and makes it possible to designate multiple groups as mods on a category.

Internal topic: t/124648.
2024-09-04 04:38:46 +03:00
Joffrey JAFFEUX e418f7056f
FIX: prevents PM to large groups (#28681)
This commit introduces a new hidden site setting: `group_pm_user_limit`, default to `1000` which will raise an error when attempting to create a PM target a large group.
2024-09-03 12:08:14 +02:00
David Taylor 80b9c280ba
DEV: Switch to pnpm for JS dependencies (#28671)
This will bring significant improvements to install speed & storage requirements. For information on how it may affect you, see https://meta.discourse.org/t/324521

This commit:
- removes the `yarn.lock` and replaces with `pnpm-lock.yaml`
- updates workspaces to pnpm format
- adjusts package dependencies to work with pnpm's stricter resolution strategy
- updates Rails app to load modules from more specific node_modules directories
- adds a `.pnpmfile` which automatically cleans up old yarn-managed `node_modules` directories
- updates various scripts to call `pnpm` instead of `yarn`
- updates patches to use pnpm's native patch system instead of patch-package
- adds a patch for licensee to support pnpm
2024-09-03 10:51:07 +01:00
Loïc Guitaut 9b4b5b5028 FIX: Return proper results when searching for a topic in Japanese
Currently, when the default locale is Japanese, the search for a topic
using its URL, path or ID doesn’t work as expected. It will either
return wrong results or no result at all.

The problem lies with how we process the provided terms in Japanese
mode. For example, if `http://localhost/t/-/55` is provided, currently
this will result in `http localhost t 5 5` to be searched for.

This patch addresses the issue by checking whether the provided term
needs segmenting. If the provided term is a number, or a path or a full
URL, then it doesn’t need segmenting. When that happens we skip the
processing we normally apply for Japanese, making the search return the
expected results.
2024-09-03 09:48:58 +02:00
Krzysztof Kotlarek 7577231ba2
DEV: the ability to define setting areas (#28570)
A new setting attribute is used to define the areas (separated by `|`).

In addition, endpoint `/admin/config/site_settings.json` accepts new `filter_area` data.
2024-09-03 09:25:45 +10:00
Joffrey JAFFEUX b0059c735c
DEV: uses context blocks (#28658) 2024-08-30 11:26:15 +02:00
Joffrey JAFFEUX d81fc1448b
DEV: implements register_modifier(:custom_homepage_enabled) (#28657)
This commit will allow plugin developers to enable/disable the custom homepage.

Usage:

```ruby
register_modifier(:custom_homepage_enabled) do |enabled, args|
  true
end 
```

Args might contain request and/or current_user.
2024-08-30 11:06:07 +02:00
Bianca Nenciu 1f206349fd
DEV: Split slow test in multiple smaller tests (#28646)
* DEV: Split slow test in multiple smaller tests

This might be faster because the  smaller chunks of the test may run in
parallel.

* DEV: Fabricate reviewables only once
2024-08-30 14:47:29 +10:00
Krzysztof Kotlarek 80449d39d3
FIX: Flaky flags spec (#28591)
Because of caching, whenever flags are created, they have to be destroyed to not modify the state.
2024-08-28 17:03:43 +10:00
Gabriel Grubba c8f5445030
Revert "DEV: Removal of create_post_for_category_and_tag_changes setting (#28…" (#28587)
This reverts commit fc33826dc5.
2024-08-27 16:19:51 -03:00
Martin Brennan e58e7a49f5
FIX: Bookmark reminder was clearing incorrectly (#28506)
Followup 76c56c8284

The change introduced above made it so the expired
bookmark reminders were cleared when using the bulk
action menu for bookmarks. However this also affected
clearing reminders for bookmarks when sending notifications.

When clearing bookmark reminders after sending notifications,
we take into account the auto delete preference:

* never          - The bookmark `reminder_at` date should not be cleared,
                   and the bookmark is kept.
* clear_reminder - The bookmark `reminder_at` date is cleared and
                   the bookmark is kept

The `never` option made it so "expired" bookmark reminder show
on the user's bookmark list.

This commit fixes the change from the other commit and only
forces clearing of `reminder_at` if using the bookmark bulk
action service.
2024-08-26 09:17:39 +10:00
锦心 ac365a86a2
FIX: Trigger user_logged_out event when the user logs out (#28482)
What did this fix?
===============

Previously, we only triggered this event in the `user.logged_out` method.
This resulted in the event being triggered only when the user was logged
out by the administrator or the site had strict logout mode enabled.
This bug affected customers who managed user status via webhooks.

meta topic: https://meta.discourse.org/t/user-log-out-event-not-triggered-in-webhooks/249464
2024-08-22 21:48:27 +08:00
Osama Sayegh 10ae7ef44a
FEATURE: Add estimated number of global and EU visitors to the about page (#28382)
This commit implements 2 new metrics/stats in the /about page for the _estimated_ numbers of unique visitors from the EU and the rest of the world. This new feature is currently off by default, but it can be enabled by turning on the hidden `display_eu_visitor_stats` site settings via the rails console.

There are a number of assumptions that we're making here in order to estimate the number of unique visitors, specifically:

1. we're assuming that the average of page views per anonymous visitor is similar to the average number of page views that a logged-in visitor makes, and
2. we're assuming that the ratio of logged in visitors from the EU is similar to the ratio of anonymous visitors from the EU

Discourse keeps track of the number of both logged-in and anonymous page views, and also the number of unique logged-in visitors and where they're from. So with those numbers and the assumptions above, we can estimate the number of unique anonymous visitors from the EU and the rest of the world.

Internal topic: t/128480.
2024-08-21 00:03:42 +03:00