- Run the CSP-nonce-related middlewares on the generated response
- Fix the readonly mode checking to avoid empty strings being passed (the `check_readonly_mode` before_action will not execute in the case of these re-dispatched exceptions)
- Move the BlockRequestsMiddleware cookie-setting to the middleware, so that it is included even for unusual HTML responses like these exceptions
This commit adds a `getCategoryIdByName` helper function to the context in
which theme migrations are ran in. The purpose of this commit is to
allow themes which may have stored category names in theme settings to
migrate to objects typed theme settings which supports properties of
categories typed which stores the category ids in the value of the
property.
This ensures we only ever store correct post and topic timing when the client
notifies.
Previous to this change we would blindly trust the client.
Additionally this has error correction code that will correct the last seen
post number when you visit a topic with incorrect timings.
When the user sees no results in their admin sidebar query,
we are adding two additional links:
* "Search site settings" - Navigates to the site settings page
with the filter prefilled in the search
* "Admin user list" - Navigates to the user list with the filter
prefilled in the username search
This will bridge the gap until we have a full admin-wide search.
Also make admin site setting search param refresh on filter changes
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Followup to 67a8080e33
This commit makes it so the topic footer button for bookmarks
uses the new BookmarkMenu component, and makes some tweaks to
that component to allow for a label and CSS class options.
Also introduces a TopicBookmarkManager to manage the saving/editing/
deleting of the topic level bookmarks and the reactivity that happens
in the topic UI afterward.
Next commit should rip out old bookmark associated code in the
topic controller as it will no longer be needed.
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
This commit ensures that additional keywords for admin
sidebar links (which are also stored in the admin sidebar state
manager) are translated with I18n, which was discussed
in https://meta.discourse.org/t/introducing-experimental-admin-sidebar-navigation/289281/58?u=martin
This also changes the admin sidebar state manager keywords to
not be a TrackedObject -- this is not necessary as keywords are
only set once, and it was causing rendering issues because
the keywords were being set at the same time they were read.
Finally this adds a "theme" keyword to the "Components" link
because we often refer to components as Theme Components
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
For e-mails, secure uploads redacts all secure images, and later uses the access control post to re-attached allowed ones. We pass the ID of this post through the X-Discourse-Post-Id header. As the name suggests, this assumes there's only ever one access control post. This is not true for activity summary e-mails, as they summarize across posts.
This adds a new header, X-Discourse-Post-Ids, which is used the same way as the old header, but also works for the case where an e-mail is associated with multiple posts.
* DEV: replace postAttrs dependencies in topic-map component by passing in topicDetails and postStream to topic-map to ensure state changes are passed properly down to child components
Automatically add `moderators` and `admins` auto groups to specific site settings.
In the new group-based permissions systems, we just want to check the user’s groups since it more accurately reflects reality
Affected settings:
- tag_topic_allowed_groups
- create_tag_allowed_groups
- send_email_messages_allowed_groups
- personal_message_enabled_groups
- here_mention_allowed_groups
- approve_unless_allowed_groups
- approve_new_topics_unless_allowed_groups
- skip_review_media_groups
- email_in_allowed_groups
- create_topic_allowed_groups
- edit_wiki_post_allowed_groups
- edit_post_allowed_groups
- self_wiki_allowed_groups
- flag_post_allowed_groups
- post_links_allowed_groups
- embedded_media_post_allowed_groups
- profile_background_allowed_groups
- user_card_background_allowed_groups
- invite_allowed_groups
- ignore_allowed_groups
- user_api_key_allowed_groups
This doesn't change anything in 99.9% of cases - by default d-header has only one child element `.wrap`.
There are only two themes that I'm aware of that add another child:
1. discourse-categories-navbar - which I'm currently updating to use the new header APIs, and where the column layout makes more sense
2. a private theme, which was recently updated to use those APIs and that works around the current layout by applying `flex-wrap: wrap` to d-header (I'll remove that override as it conflicts with this change)
CategoryBadgeSerializer and TopicCategorySerializer are too similar and
are used in similar contexts. This commit merges the two into a single
CategoryBadgeSerializer.
Full text search does not return ideal results for category dropdown.
Usually, in category dropdowns we want to search for categories as we
type. For example, while typing "theme", the dropdown should show
intermediary results for "t", "th", "the", "them" and finally "theme".
For some of these substrings (like "the"), full text search does not
return any results, which leads to an unpleasant user experience.
To add a components link to the sidebar refactoring was required to create unique URLs for themes and components. Before the query param was used. After changes, we have two URLs `/admin/customize/themes` and `/admin/customize/components`.
Prior to this fix we were manually expanding the composer but not setting the correct height. This commit adds a new `unshrink` function on the composer service to correctly set the state and the height on the composer model.
In discourse-assign the assign menu in the modal is using this `expandedOnInsert` option and was sometimes not opening correctly resulting in a broken state until you click two times on it. This should prevent this issue.
This commit will now change two behaviors:
- If composer is already opened on a specific post and we click on edit again for the same post, we will do nothing and not show the discard draft modal
- if composer is shrinked and we click on edit for the same currently edited post, we will just open the composer and not show the discard draft modal
This commit addresses an issue for sites where secure_uploads
is turned on after the site has been operating without it for
some time.
When uploads are linked when they are used inside a post,
we were setting the access_control_post_id unconditionally
if it was NULL to that post ID and secure_uploads was true.
However this causes issues if an upload has been used in a
few different places, especially if a post was previously
used in a PM and marked secure, so we end up with a case of
the upload using a public post for its access control, which
causes URLs to not use the /secure-uploads/ path in the post,
breaking things like image uploads.
We should only set the access_control_post_id if the post is the first time the
upload is referenced so it cannot hijack uploads from other places.
I needed to run `rake javascript:update_constants` for my previous
commit: 72ac675e4e
The change in this commit though was completely unrelated, so I saved it
for it's own commit.
This fixes a timing issue where, if a user (or the CI) was
on a slow network connection, clicking one of the bookmark
menu options would cause an error because we hadn't yet received
the response from the server after creating the bookmark.
It should be very smooth most of the times because (paraphrasing j.jaffeux):
a) Most likely when user clicks it’s already saved
b) If it’s not saved when user clicks, it should already be almost done so
the perceived wait when click the reminder option should be rather short
The breadcrumbs were updated everytime there were changes to the
categories which was not efficient and caused unnecessary rerendering
of the CategoryDrop elements when "lazy load categories" is enabled.
This commit also ensures that all category fields are serialized for
ancestors too for the categories#search endpoint.
The bulk actions menu for topics has multiple options to work
with tags on topics (append, replace, remove). Our tagging system
along with categories allows for some complicated tag restrictions
to be applied via tag groups. This was a problem for the topic bulk
actions because you couldn't append restricted tags to topics.
This commit allows restricted tags to be used in bulk tagging actions
as long as all selected topics are for a sole category. The category
information will be shown in the modal, and the category ID is used
for the tag search.
Include categories when fetching admin/web_hooks and make
'extras' more useful. 'extras' is the mechanism we use to provide
context for rest objects.
However, previously:
* When you fetched many objects, extras was only set on the ResultSet,
not on each object,
* If you need derived data from extras, there wasn't a sensible place to
put this code. Now, you can create an 'ExtrasClass' static field on
your rest model and this class will be used for your extras data,
This commit changes the identifier displayed in the navigation tree of
the theme objects editor from the generic "category 1" to "<category
name>, <category 2 name>" when a property of typed categories is set as
the identifier.
Example:
For the following theme objects schema:
```
some_setting:
type: objects
default: []
schema:
name: <some scheme name>
identifier: list_of_categories
properties:
list_of_categories:
type: categories
```
If the `list_of_categories` property's value has been set to `category
1` and `category 2`, the navigation tree will display `category 1,
category 2` as the text to represent the object in the navigation tree.
Previously, when the new site was created and after the first admin login, no one will receive notifications to review the user approval queue since only the moderators would receive the PMs about it. Also, this PR will change the "pending_users_reminder_delay_minutes" site setting to 5 minutes while the site is in bootstrap mode.
When lazy load categories is enabled, categories should be loaded with
user activity items and drafts because the categories may not be
preloaded on the client side.
This will automatically enable the glimmer header when all installed themes/plugins are ready. This replaces the old group-based site setting.
In 'auto' mode, we check for calls to deprecated APIs (e.g. decorateWidget) which affect the old header. If any are present, we stick to the old header implementation and print a message to the console alongside the normal deprecation messages.
To override this automatic behavior, a new `glimmer_header_mode` site setting can be set to 'disabled' or 'enabled'.
This change also means that our test suite is running with the glimmer header. This unveiled a couple of small issues (e.g. some incorrect `aria-*` and `alt` text) which are now fixed. A number of selectors had to be updated to ensure the tests were clicking the actual `<button>` elements rather than the surrounding `<li>` elements.
This started as a way to prevent "previewUpdated" from doing the same work twice when morphing.
Ended up refactoring "previewUpdated" and extracted into 5 distinct methods for clearer understanding and more consistent debouncing (using the "@debounce" decorator instead of the "discourseDebounce" method).
No "feature" was changed, other than not doing the "decorateCookedElement" when morphing is enabled, since we already did it _before_ morphing.
A lot of plugins are using "api.decorateCookedElement" to decorate the cooked preview.
Some of those plugins, like the "image-grid" ([grid]...[/grid]), changes the DOM. We have to call them _before_ morphing otherwise, there's no real point in morphing the preview.
The missing piece was triggering the "decorate-non-stream-cooked-element" application event.
This modifier allows plugins to alter the outcome of
`should_secure_uploads?` on a Post record, for cases when
plugins need post-attached uploads to always be secure (or
not secure) in specific scenarios.
Chrome's default is already Lax, so this change is a no-op there.
Firefox will soon be follow them, and has started warning about cookies with no samesite attribute. That's the motivation for this commit.
When choosing the "Custom..." option in the new bookmark
menu and then choosing a date + time in the modal for the
reminder, the bookmark icon on the post was not updating to
show the one with the clock to indicate the reminder.
This was just a data syncing issue between BookmarkFormData
and what the modal sets. Ideally all this would be refactored
because the data flow is messy...but hard to find time for
that right now.
Followup 67a8080e33
This commit changes enum typed theme objects property to be optional.
Previously, an enum typed property is always required but we have found
that this might not be ideal so we want to change it.
This method name is a bit confusing; with_secure_uploads implies
it may return a block or something with the uploads of the post,
and has_secure_uploads implies that it's checking whether the post
is linked to any secure uploads.
should_secure_uploads? communicates the true intent of this method --
which is to say whether uploads attached to this post should be
secure or not.
Display additional confirmation when:
- The public section is going to be updated;
- The public section is going to be deleted;
- The public section is going to be marked as private.
The complexity of the situation is that we don't want to load faker into production by default but fabricators and styleguide are available on production.
This is made possible through app/assets/javascripts/discourse/app/lib/load-faker.js which contains a function to ensure faker is loaded asynchronously (loadFaker) and another function to access the loaded faker (getLoadedFaker).
Note 1: this commit also refactors fabricators to have access to context and use faker where possible
Note 2: this commit moves automation to admin bundle
---------
Co-authored-by: David Taylor <david@taylorhq.com>
It was originally named bootstrap-json because it contacted a 'bootstrap' API in rails to generate the ember-cli html response. However, it has since been overhauled to remove that 'bootstrap' system. Now it is a much simpler proxy server which transforms the HTML sent by Rails.
The bug was due to the fact that the `<DModal />` is displayed inside a if block, when the condition was false to close the menu, the modal was just hidden without calling callbacks. The fix ensures we are correctly calling `modal.close()` before in this case.
This commit adds a new option `@modalForMobile` for `<DMenu />` which allows to display a `<DModal />` when expanding a menu on mobile.
This commit also adds a `@views` options to toasts which is an array accepting `['mobile', 'desktop']` and will control if the toast is show on desktop and/or mobile.
Finally this commit allows to hide the progressBar even if the toast is set to `@autoClose=true`. This is controlled through the `@showProgressBar` option.
This commmit removes the unused `/u/:username/preferences/categories`
route which was merged into the `/u/:username/preferences/tracking`
route in 2fc2d7d828.
Available as a normal synchronous module in tests
Available as an async import in core, or via the `loadFaker` helper in themes/plugins (which cannot use async import directly)
* DEV: Add `topic_embed_import_create_args` plugin modifier
This modifier allows a plugin to change the arguments used when creating
a new topic for an imported article.
For example: let's say you want to prepend "Imported: " to the title of
every imported topic. You could use this modifier like so:
```ruby
# In your plugin's code
plugin.register_modifier(:topic_embed_import_create_args) do |args|
args[:title] = "Imported: #{args[:title]}"
args
end
```
In this example, the modifier is prepending "Imported: " to the `title` in the `create_args` hash. This modified title would then be used when the new topic is created.
This change adds a progress bar to toast notifications when autoClose is enabled (true by default).
The progress bar allows users to visually see how long is left before the notification disappears.
When hovered on desktop, the progress and autoclose timer will be paused, it will resume again once the mouse is moved away from the toast notification.
Why this change?
For a `typed: objects` theme setting with an enum property, we are
adding a `default` key for `type: enum` fields which will be used
as the default value on the client side.
```
some_objects_setting:
type: objects
schema:
name: field
properties:
enum_field:
type: enum
default: awesome
choices:
- nice
- cool
- awesome
```
Adds the new quick menu for bookmarking. When you bookmark
a post (chat message behaviour will come later) we show this new quick
menu and bookmark the item straight away.
You can then choose a reminder quick option, or choose Custom... to open
the old modal. If you click on an existing bookmark, we show the same quick menu
but with Edit and Delete options.
A later PR will introduce a new bookmark modal, but for now we
are using the old modal for Edit and Custom... options.
Using around_action means `add_early_hint_header` is in the stack for every request, and gets included in the backtrace of any errors.
We can manage with an after_action instead, which avoids adding to the stack depth (and avoids people blaming me for unrelated application errors 😉)
When opening the user menu, we display old cached data, and then replace it with fresh data immediately afterwards. The vast majority of the time the data is unchanged, and so there is no visible change. When rendering HTML elements directly, Ember realizes that there is no change, and does not make any changes to the DOM. Great!
However, our `avatar` helper returns a blob of HTML. With raw HTML, Ember does not make any attempt to 'diff' the existing DOM. Instead, it replaces the old string with the new string. That can be a little wasteful, but normally it's not a big deal. But, when it comes to `<img lazy="lazy"`, re-rendering the `img` element causes a visible flicker in Safari.
To work around that, this commit replaces the `{{avatar}}` helper with an ember-rendered `<img` element. Now that Ember is responsible for rendering, it can detect there is no real change to the attributes and skip it, thereby avoiding the flicker.
If we find ourselves doing this more frequently, we may want to consider creating an `<Avatar` component. But for now, I think it's simple enough to justify building the `<img` manually in this case.
The "new topic" route can open the composer with a category preselected.
This commit ensures that the category is loaded before the composer is
opened.
Why this change?
Prior to this change, the input fields were not displaying when adding
an object to a objects typed theme setting which has a default value of
`[]`. This is because the `fields` getter was not being recomputed.
This PR improves the performance of the `most_replied_to_users` method on the `UserSummary` model.
### Old Query
```ruby
post_query
.joins(
"JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number",
)
# We are removing replies by @user, but we can simplify this by getting the using the user_id on the posts.
.where("replies.user_id <> ?", @user.id)
.group("replies.user_id")
.order("COUNT(*) DESC")
.limit(MAX_SUMMARY_RESULTS)
.pluck("replies.user_id, COUNT(*)")
.each { |r| replied_users[r[0]] = r[1] }
```
### Old Query with corrections
```ruby
post_query
.joins(
"JOIN posts replies ON posts.topic_id = replies.topic_id AND replies.reply_to_post_number = posts.post_number",
)
# Remove replies by @user but instead look on loaded posts (we do this so we don't count self replies)
.where("replies.user_id <> posts.user_id")
.group("replies.user_id")
.order("COUNT(*) DESC")
.limit(MAX_SUMMARY_RESULTS)
.pluck("replies.user_id, COUNT(*)")
.each { |r| replied_users[r[0]] = r[1] }
```
### New Query
```ruby
post_query
.joins(
"JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number",
)
# Only include regular posts in our joins, this makes sure we don't have the bloat of loading private messages
.joins(
"JOIN topics ON replies.topic_id = topics.id AND topics.archetype <> 'private_message'",
)
# Only include visible post types, so exclude posts like whispers, etc
.joins(
"AND replies.post_type IN (#{Topic.visible_post_types(@user, include_moderator_actions: false).join(",")})",
)
.where("replies.user_id <> posts.user_id")
.group("replies.user_id")
.order("COUNT(*) DESC")
.limit(MAX_SUMMARY_RESULTS)
.pluck("replies.user_id, COUNT(*)")
.each { |r| replied_users[r[0]] = r[1] }
```
# Conclusion
`most_replied_to_users` was untested, so I introduced a test for the logic, and have confirmed that it passes on both the new query **AND** the old query.
Thank you @danielwaterworth for the debugging assistance.
We will be collecting the logo URL and the site's default locale values along with existing basic details to display the site on the Discourse Discover listing page. It will be included only if the site is opted-in by enabling the "`include_in_discourse_discover`" site setting.
Also, we no longer going to use `about.json` and `site/statistics.json` endpoints retrieve these data. We will be using only the `site/basic-info.json` endpoint.
- Add a "Skip tips" button to first notification tip
- Add a "Skip tips" button to the admin guide tip
- Fixes the timeline tip showing when no timeline was present
- Fixes post menu tip showing when no "..." button is present
- Adds system tests
- Marks each tip as seen as soon as it is displayed so that refreshing,
clicking outside, etc. won't show it again
- Change just above means we no longer need a MessageBus track
Co-authored-by: Bianca Nenciu <nbianca@users.noreply.github.com>
Some of the properties, like 'categoriesById', 'parentCategory' and
'subcategories', were updated manually when categories were loaded.
This was not ideal because it required a lot of code to keep the
objects in sync and some of the properties were not updated correctly.
Why this change?
Instead of dealing with a generic object for `Theme#settings`, we want
to always be dealing with `ThemeSettings` objects.` Previously, we
converted the generic objects to `ThemeSettings` objects in the theme's
adapter `afterFindAll` function. This is not correct because updating
or saving the theme individual reverted the `Theme#settings` back to an
array of generic object.
To fix this problem, the proper way with our REST models is to overwrite
the static `munge` method and create `ThemeSettings` instances there.
When a user is manually deactivated, they should not be deleted by our background job that purges inactive users.
In addition, site settings keywords should accept an array of keywords.