After editing a post, it is refreshed by two ways. One of them is
triggered by the client side which will route the client to the edited
post and force a reload this way. The other way is via Message Bus.
This commit ignores both of the ways and tries to update the post
immediately and then refresh the post stream.
It was not clear that replace watched words can be used to replace text
with URLs. This introduces a new watched word type that makes it easier
to understand.
I merged this PR in yesterday, finally thinking this was done https://github.com/discourse/discourse/pull/12958 but then a wild performance regression occurred. These are the problem methods:
1aa20bd681/app/serializers/topic_tracking_state_serializer.rb (L13-L21)
Turns out date comparison is super expensive on the backend _as well as_ the frontend.
The fix was to just move the `treat_as_new_topic_start_date` into the SQL query rather than using the slower `UserOption#treat_as_new_topic_start_date` method in ruby. After this change, 1% of the total time is spent with the `created_in_new_period` comparison instead of ~20%.
----
History:
Original PR which had to be reverted **https://github.com/discourse/discourse/pull/12555**. See the description there for what this PR is achieving, plus below.
The issue with the original PR is addressed in 92ef54f402
If you went to the `x unread` link for a tag Chrome would freeze up and possibly crash, or eventually unfreeze after nearly 10 mins. Other routes for unread/new were similarly slow. From profiling the issue was the `sync` function of `topic-tracking-state.js`, which calls down to `isNew` which in turn calls `moment`, a change I had made in the PR above. The time it takes locally with ~1400 topics in the tracking state is 2.3 seconds.
To solve this issue, I have moved these calculations for "created in new period" and "unread not too old" into the tracking state serializer.
When I was looking at the profiler I also noticed this issue which was just compounding the problem. Every time we modify topic tracking state we recalculate the sidebar tracking/everything/tag counts. However this calls `forEachTracked` and `countTags` which can be quite expensive as they go through the whole tracking state (and were also calling the removed moment functions).
I added some logs and this was being called 30 times when navigating to a new /unread route because `sync` is being called from `build-topic-route` (one for each topic loaded due to pagination). So I just added a debounce here and it makes things even faster.
Finally, I changed topic tracking state to use a Map so our counts of the state keys is faster (Maps have .size whereas objects you have to do Object.keys(obj) which is O(n).)
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
Refactors `TrustLevel` and moves translations from server to client
Additional changes:
* "staff" and "admin" wasn't translatable in site settings
* it replaces a concatenated string with a translation
* uses translation for trust levels in users_by_trust_level report
* adds a DB migration to rename keys of translation overrides affected by this commit
In Ember CLI, the vendor bundler includes Ember/jQuery, so this brings
our app closer to that configuration.
We have a couple pages (Reset Password / Confirm New Email) where we need
`ember_jquery` without vendor so the file still exists for those cases.
Previous to this change we would switch off MessageBus updating after 20
minutes.
This ensures that when the user becomes present again we turn on long polling.
Without long polling updates can be delayed for minutes.
The widget should accept the disabled option.
In that case, CSS class "disabled".
In addition, after click dropdown will not be shown.
Also, the option to disable a specific value in a dropdown is included
…and just prioritize the current one, instead of hiding other categories.
Context: when you open the composer by clicking "New Topic" button when in a category, or by clicking "New Topic" in the share-popup, the category selector shows only the current category and its children (and "Uncategorized"). You can still find other categories, but you have to search by name.
This PR changes that, so you now can see all the categories in the dropdown, and those that are relevant (again: current, children and uncategorized) are displayed before all other categories.
tldr: don't make choosing other categories harder - make choosing relevant ones easier.
1. It defaults to `cache: true` already
2. Setting it to `false` for non-GET request doesn't do anything
3. We were correcting `cache: false` GET requests to use `cache: true`
…so setting it to anything at all, for any type of request doesn't make sense (anymore)
When the client received a new notification, it prioritized only PM
notifications instead of maintaining the priority order. Later, the
check for missing notification deleted all notifications that were
in the wrong order because it could not match the IDs.
The correct order puts high_priority AND unread notifications first.
Low priority or read notifications (including high priority, but read
notifications) come after.
Original PR which had to be reverted **https://github.com/discourse/discourse/pull/12555**. See the description there for what this PR is achieving, plus below.
The issue with the original PR is addressed in 92ef54f402
If you went to the `x unread` link for a tag Chrome would freeze up and possibly crash, or eventually unfreeze after nearly 10 mins. Other routes for unread/new were similarly slow. From profiling the issue was the `sync` function of `topic-tracking-state.js`, which calls down to `isNew` which in turn calls `moment`, a change I had made in the PR above. The time it takes locally with ~1400 topics in the tracking state is 2.3 seconds.
To solve this issue, I have moved these calculations for "created in new period" and "unread not too old" into the tracking state serializer.
When I was looking at the profiler I also noticed this issue which was just compounding the problem. Every time we modify topic tracking state we recalculate the sidebar tracking/everything/tag counts. However this calls `forEachTracked` and `countTags` which can be quite expensive as they go through the whole tracking state (and were also calling the removed moment functions).
I added some logs and this was being called 30 times when navigating to a new /unread route because `sync` is being called from `build-topic-route` (one for each topic loaded due to pagination). So I just added a debounce here and it makes things even faster.
Finally, I changed topic tracking state to use a Map so our counts of the state keys is faster (Maps have .size whereas objects you have to do Object.keys(obj) which is O(n).)
A non-staff user cannot post to a closed topic, so we should not
show them the modal asking "Which topic do you want to reply to?"
This also fixes an issue I ran into while testing the above change, in
Ember CLI an error was being raised because related messages were being
set inside a computed property.
This overhauls the user interface for the group email settings management, aiming to make it a lot easier to test the settings entered and confirm they are correct before proceeding. We do this by forcing the user to test the settings before they can be saved to the database. It also includes some quality of life improvements around setting up IMAP and SMTP for our first supported provider, GMail. This PR does not remove the old group email config, that will come in a subsequent PR. This is related to https://meta.discourse.org/t/imap-support-for-group-inboxes/160588 so read that if you would like more backstory.
### UI
Both site settings of `enable_imap` and `enable_smtp` must be true to test this. You must enable SMTP first to enable IMAP.
You can prefill the SMTP settings with GMail configuration. To proceed with saving these settings you must test them, which is handled by the EmailSettingsValidator.
If there is an issue with the configuration or credentials a meaningful error message should be shown.
IMAP settings must also be validated when IMAP is enabled, before saving.
When saving IMAP, we fetch the mailboxes for that account and populate them. This mailbox must be selected and saved for IMAP to work (the feature acts as though it is disabled until the mailbox is selected and saved):
### Database & Backend
This adds several columns to the Groups table. The purpose of this change is to make it much more explicit that SMTP/IMAP is enabled for a group, rather than relying on settings not being null. Also included is an UPDATE query to backfill these columns. These columns are automatically filled when updating the group.
For GMail, we now filter the mailboxes returned. This is so users cannot use a mailbox like Sent or Trash for syncing, which would generally be disastrous.
There is a new group endpoint for testing email settings. This may be useful in the future for other places in our UI, at which point it can be extracted to a more generic endpoint or module to be included.
* FIX: Improve GitHub folder regexp in Onebox
It used to match any GitHub URL that was not matched by the other GitHub
Oneboxes and it did not do a good job at handling those. With this
change, the generic Onebox will handle the remaining URLs.
* FEATURE: Add Onebox for GitHub Actions
* FEATURE: Add Onebox for PR check runs
* FIX: Remove image from GitHub folder Oneboxes
It is a generic, auto-generated image which does not provide any value.
* DEV: Add tests
* FIX: Strip HTML comments from PR body
* UX: alert screen readers when there is an issue saving a post
Adds a "alert" role to various popup-input-tips.
This means screen reader users can now tell why a post refuses to save.
Also ensures like icon in the "try the like button" has screen reader support
Previously auto focus would only work on modals that include buttons or
inputs.
To avoid a situation where information modals such as keyboard shortcuts
do not get focus, simply focus on the close button as a fallback.
There are two methods which the server uses to verify an invite is being redeemed with a matching email:
1) The email token, supplied via a `?t=` parameter
2) The validity of the email, as provided by the auth provider
Only one of these needs to be true for the invite to be redeemed successfully on the server. The frontend logic was previously only checking (2). This commit updates the frontend logic to match the server.
This commit does not affect the invite redemption logic. It only affects the 'show' endpoint, and the UI.
Previously we had no role set for various topic links, nor did we have any
headers.
This teaches screen readers that topic links in topic lists are to be treated
as H2. We opted for this less radical change cause a change of the element
type would probably result in many broken themes.
Confirmed on NVDA you can very quickly breeze through topic lists now. Minor
edge case is pinned topics which can be a bit annoying due to multiple links.
The previous commits removed reviewables leading to a bad user
experience. This commit updates the status, replaces actions with a
message and greys out the reviewable.
We now bundle Javascript for each theme/plugin separately, and only ship bundles for enabled plugins to the client. Therefore, these disabled_plugins checks are now redundant, and can be removed.
This PR improves the UI of bulk select so that its context is applied to the Dismiss Unread and Dismiss New buttons. Regular users (not just staff) are now able to use topic bulk selection on the /new and /unread routes to perform these dismiss actions more selectively.
For Dismiss Unread, there is a new count in the text of the button and in the modal when one or more topic is selected with the bulk select checkboxes.
For Dismiss New, there is a count in the button text, and we have added functionality to the server side to accept an array of topic ids to dismiss new for, instead of always having to dismiss all new, the same as the bulk dismiss unread functionality. To clean things up, the `DismissTopics` service has been rolled into the `TopicsBulkAction` service.
We now also show the top Dismiss/Dismiss New button based on whether the bottom one is in the viewport, not just based on the topic count.
Not all screen readers treat articles as navigable roles when moving between landmarks. To help with this, we use a `heading` role on the title, with an arbitrary depth of 2 chosen as to not conflict with the main `<h1/>`. Because ARIA roles are used, this change should be entirely non-visual.
While this introduces minor navigation challenges in posts where headers are included, the vast majority of posts don't, and as screen reader users, we're used to mixed headers in longer-form content.
NVDA does not detect HTML5 articles as regions. This explicitly sets a
region with an aria-label denoting post numbers making it much easier to
know where you are in a topic.
Note role: article which is more semantically correct is not respected by
NVDA d/D shortcut, hence the much more generic "region" role.
When slow mode is enabled it's possible to open the slow mode dialog again to disable it or to update slow mode settings. The problem is that in this case, the button for saving still has the label "Enable" which is confusing.
This changes the text on the button from "Enable" to "Update" when slow mode is already enabled.
Based on feedback from Matt Haughey, we don't need to use so many words when describing a deleted topic or post.
Co-authored-by: Martin Brennan <martin@discourse.org>
If reload a page after enabling slow mode and open the slow mode dialog again it would show a slow mode interval but wouldn't show Enabled Until value. This PR fixes it.
It used to allow adding email addresses to a group even if invites were
disabled for the site. This does not allow user to input email address
if they cannot invite.
The second thing this commit improves is the message that is displayed
to the user when they hit the invite rate limit.
Over the years we accrued many spelling mistakes in the code base.
This PR attempts to fix spelling mistakes and typos in all areas of the code that are extremely safe to change
- comments
- test descriptions
- other low risk areas
The problem was we were setting the properties then immediately calling
`refreshRoute` which was being executed before the properties were
settled via the runloop.
> Backtracking re-render refers to a scenario where, in the middle of the rendering process, you have modified something that has already been rendered.
See more details from the Ember team here https://github.com/emberjs/ember.js/issues/13948.
We call _updateInput from init. _updateInput triggers onChangeInput which mutates a date that was given to future-date-input just a moment ago and a rendering cycle wasn't finished yet.
The crash:
```
Uncaught TypeError: Ember.keys is not a function
```
Repro:
- visit home page
- click new topic
- navigate to your messages by clicking your avatar (top right), then enveloppe icon, and finally the bottom chevron
- click New Message
- click cancel in the composer, it should crash
Watched words are always regular expressions, despite watched_words_
_regular_expressions being enabled or not. Internally, wildcard
characters are replaced with a regular expression that matches any non
whitespace character.
This is two fixes:
1. Ember CLI's proxy did not support 3xx redirects so a redirect was
failing.
2. We were not passing query parameters to the `bootstrap.json` endpoint
to correctly handle previewing themes (and other occasional options.)
If you finished reviewing the initially loaded items, and there're more in the queue, load them.
Also, when fast-tracking the pending items updates, use the reviewable_count returned by the perform result. Calling "result.reviewable_count" returns undefines.
This patch remembers the last id for the `file-change` event and uses it
to initialize the client side watcher. This should help fix the issue
where styles are not reloaded client side if the browser refreshed.
Normally we'd use `ember-auto-import` for this, but it's not run on
our admin tree due to the quirky way we load it conditionally.
Instead we'll append it at the bottom like our Rails app does.
* FIX: Ensure the same email cannot be invited twice
When creating a new invite with a duplicated email, the old invite will
be updated and returned. When updating an invite with a duplicated email
address, an error will be returned.
* FIX: not Ember helper does not exist
* FIX: Sync can_invite_to_forum? and can_invite_to?
The two methods should perform the same basic set of checks, such as
check must_approve_users site setting.
Ideally, one of the methods would call the other one or be merged and
that will happen in the future.
* FIX: Show invite to group if user is group owner
Identical callbacks can pile up during tests and cause all sort of weird problems that are difficult to debug. This commit clears registered callbacks after each test.
* FIX: ember-cli proxy subfolder fix
* REFACTOR: put rootURL setup in environment, update baseURL logic for subfolder
Correctly have ember understand and parse relative_url_root and use it in
the dev server
This was needed to fix a bookmark back button issue but it
broke category topic links, causing a full reload. Now it appears
something has changed in core and this is no longer necessary for
the bookmark back button to work, so I am removing it again.
* FIX: Cache missing inline oneboxes
Some inline oneboxes were not cached when the server did not return an
answer for an URL and the queried URL and the absolute URL were
different.
For example, if user typed www.example.com, the client asked the server
for http://www.example.com and if the server returned an empty response,
then the client would keep requesting an inline onebox everytime the
composer changed.
In other words, the key used for reading (the absolute URL) and the one
used for writing (the URL as typed by the user) were not the same when
the server returned an empty response.
* DEV: Check cache before making request
There is another cache check in PrettyText, but that is not enough if
multiple requests are pending. This problem was made obvious in tests,
but can happen for users with slow connections.
* FEATURE: Allow sending a message with invite
It used to be a staff-only feature and this commit makes it available
to everyone who can invite.
* FIX: Inviting to topic uses another email template
This used to be the case, but the extra parameter was lost when we
switched to the new modal.
The user may have changed their category or tag tracking settings since a topic was tracked/watched based on those settings in the past. In that case we need to alter the reason message we show them otherwise it is very confusing for the end user to be told they are tracking a topic because of a category, when they are no longer tracking that category.
For example: "You will see a count of new replies because you are tracking this category." becomes: "You will see a count of new replies because you were tracking this category in the past."
To do this, it was necessary to add tag and category tracking info to current user serializer. I improved the serializer code so it only does 3 SQL queries instead of 9 to get the tracking information for tags and categories for the current user.
It's been awhile since we have supported IE11 so it should be safe to remove
IntersectionObserver now.
From a TODO task in this repo:
> drop when we eventually drop IE11
Announcement of when we removed IE11 support:
https://meta.discourse.org/t/137984/40?u=blake
See: https://meta.discourse.org/t/navigating-back-to-bookmarks/188912/4
Instead of taking the user back to the bookmark list after selecting
a topic and navigating back, the user was navigated back to the page
before that. This is because the topic-link component was missing
the data-auto-route attribute which tells the intercept-click library
not to use DiscourseURL.routeTo to handle the transition (so it is just
handled internally by Ember)
When editing the files for a theme in the admin dashboard, typing "cmd+s" (a common key-binding to save in most text editors) used to engage the browser's default "save page" dialogue.
This commit adds a key-binding to the ace editor that saves the file.
Now, the "cmd+s" (and "ctrl+s" for windows) key-binding does the same action as the save button.
This commit will add CSS classes like `unlisted`, `pinned`, and `unpinned` on the body tag.
* DEV: we no longer using the `categoryClass` & `tagClasses` methods.
* Update app/assets/javascripts/discourse/app/components/add-topic-status-classes.js
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
- better form
- uses d-footer
- ensure buttons have the same height
Note that to achieve same height for btn without text, I made the choice to go for a minimum height which should work in most cases.
Fixes a bug in user preferences > interface, the light scheme dropdown
was defaulting to "Theme Default" even when the user had selected a
different scheme.
This updates the preview_theme_id preservation logic to use more recent, robust, browser APIs. It also adds support for preserving the `?pp=async-flamegraph` parameter which is proposed in https://github.com/MiniProfiler/rack-mini-profiler/pull/494
This commit allows site admins to run theme tests in production via a new `/theme-qunit` route. When you visit `/theme-qunit`, you'll see a list of the themes/components installed on your site that have tests, and from there you can select a theme or component that you run its tests.
We also have a new rake task `themes:install_and_test` that can be used to install a list of themes/components on a temporary database and run the tests of the themes/components that are installed. This rake task can be useful when upgrading/deploying a Discourse instance to make sure that the installed themes/components are compatible with the new Discourse version being deployed, and if the tests fail you can abort the build/deploy process so you don't end up with a broken site.
- ensures footer buttons are aligned
- prevents focus on close button to be much larger than it should be, note that this fix could impact other modals but the current solution is not working, so better fix it differently if needed
This bug has first been seen when loading similar topics, minimum repro:
- Have a topic named "Something Foo Bar" with a category.
- Call this in console:
```
Discourse.currentUser.store.find("similar-topic", { title: "Something foo bar", raw: "" })
```
- Navigate to latest (no full refresh)
- The category from the topic should have disappeared
The aim of this PR is to improve the topic tracking state JavaScript code and test coverage so further modifications can be made in plugins and in core. This is focused on making topic tracking state changes easier to respond to with callbacks, and changing it so all state modifications go through a single method instead of modifying `this.state` all over the place. I have also tried to improve documentation, make the code clearer and easier to follow, and make it clear what are public and private methods.
The changes I have made here should not break backwards compatibility, though there is no way to tell for sure if other plugin/theme authors are using tracking state methods that are essentially private methods. Any name changes made in the tracking-state.js code have been reflected in core.
----
We now have a `_trackedTopicLimit` in the tracking state. Previously, if a topic was neither new nor unread it was removed from the tracking state; now it is only removed if we are tracking more than `_trackedTopicLimit` topics (which is set to 4000). This is so plugins/themes adding topics with `TopicTrackingState.register_refine_method` can add topics to track that aren't necessarily new or unread, e.g. for totals counts.
Anywhere where we were doing `tracker.states["t" + data.topic_id] = newObject` has now been changed to flow through central `modifyState` and `modifyStateProp` methods. This is so state objects are not modified until they need to be (e.g. sometimes properties are set based on certain conditions) and also so we can run callback functions when the state is modified.
I added `onStateChange` and `onMessageIncrement` methods to register callbacks that are called when the state is changed and when the message count is incremented, respectively. This was done so we no longer need to do things like `@observes("trackingState.states")` in other Ember classes.
I split up giant functions like `sync` and `establishChannels` into smaller functions for readability and testability, and renamed many small functions to _functionName to designate them as private functions which not be called by consumers of `topicTrackingState`. Public functions are now all documented (well...at least ones that are not immediately obvious).
----
On the backend side, I have changed the MessageBus publish events for TopicTrackingState to send back tags and tag IDs for more channels, and done some extra code cleanup and refactoring. Plugins may override `TopicTrackingState.report` so I have made its footprint as small as possible and externalised the main parts of it into other methods.
If the "use_site_small_logo_as_system_avatar" setting is enabled, the site's small logo is displayed as the selected option by the avatar-selector. Choosing a different avatar disables the setting.
When the admin creates a new custom field they can specify if that field should be searchable or not.
That setting is taken into consideration for quick search results.
This PR includes few commits that improve the new "Share Topic" modal: same
icon for notify button as the notification, advanced options are only showed
for staff, but the topic name should be visible to everyone.
This commit allows site admins to run theme tests in production via a new `/theme-qunit` route. When you visit `/theme-qunit`, you'll see a list of the themes/components installed on your site that have tests, and from there you can select a theme or component that you run its tests.
We also have a new rake task `themes:install_and_test` that can be used to install a list of themes/components on a temporary database and run the tests of the themes/components that are installed. This rake task can be useful when upgrading/deploying a Discourse instance to make sure that the installed themes/components are compatible with the new Discourse version being deployed, and if the tests fail you can abort the build/deploy process so you don't end up with a broken site.
The bulk button is normally shown only to staff, which is why we did not
do any explicit permissions check. Now we do display it on the messages
page too, where it is accessible to everyone.
Regression was introduced in c54609.
This ensures the full height composer styling only applies when (window
height - viewport height > 0). Previously it was being wrongly triggered
when that calculation returned a negative number.
This filter hides reviewables with a score lower than the "reviewable_low_priority_threshold" setting. We only use reviewables that already met this threshold to calculate the Medium and High priority filters.
The old share modal used to host both share and invite functionality,
under two tabs. The new "Share Topic" modal can be used only for
sharing, but has a link to the invite modal.
Among the sharing methods, there is also "Notify" which points out
that existing users will simply be notified (this was not clear
before). Staff members can notify as many users as they want, but
regular users are restricted to one at a time, no more than
max_topic_invitations_per_day. The user will not receive another
notification if they have been notified of the same topic in past hour.
The "Create Invite" modal also suffered some changes: the two radio
boxes for selecting the type (invite or email) have been replaced by a
single checkbox (is email?) and then the two labels about emails have
been replaced by a single one, some fields were reordered and the
advanced options toggle was moved to the bottom right of the modal.
* DEV: Give a nicer error when `--proxy` argument is missing
* DEV: Improve Ember CLI's bootstrap logic
Instead of having Ember CLI know which URLs to proxy or not, have it try
the URL with a special header `HTTP_X_DISCOURSE_EMBER_CLI`. If present,
and Discourse thinks we should bootstrap the application, it will
instead stop rendering and return a HTTP HEAD with a response header
telling Ember CLI to bootstrap.
In other words, any time Rails would otherwise serve up the HTML for the
Ember app, it stops and says "no, you do it."
* DEV: Support asset filters by path using a new options object
Without this, Ember CLI's bootstrap would not get the assets it wants
because the path it was requesting was different than the browser path.
This adds an optional request header to fix it.
So far this is only used by the styleguide.
Original bug report: https://meta.discourse.org/t/rename-tag-not-working-as-expected/184950
This bug was caused by the use of `oneWay` which can be very dangerous in this case, from the documentation:
> computed.oneWay only provides an aliased get. The set will not mutate the upstream property, rather causes the current property to become the value set. **This causes the downstream property to permanently diverge from the upstream property.**
Not all videos can be rendered everywhere because some browser may be
missing some codecs. This commit adds a notice on top of video to let
the user know about it.
When navigating from a 'discovery' topic list to a 'tags' topic list, the scroll position from the 'discovery' list was being used by the tag list. That meant the user would be taken to a random point in the list, and not scrolled to the top.
Non-tag topic lists were working fine because we only apply the 'cached' logic (and by extension, the saved scroll location) when the user clicks 'back' in the browser. In the code, this is referred to as `isPoppedState`.
This commit takes the `isPoppedState` logic from the regular topic lists, and applies it to the tag topic lists.
* FIX: Show date picker over modal
Previously, scrolling was necessary to see the whole picker.
* FEATURE: Improve validation for polls
Adds new error messages for each of the edge cases. Previously, it
failed with a simple error saying that the minimum value must be less
than the maximum value.
* UX: Copy edit
Note that this is only applied on date-input and not the old date-picker for now.
This commit is also slightly modifying admin report dates form to ensure the native picker is correctly used, as a result: it doesn’t auto refresh on date change and fixes a border bug.
Note that this commit is also fixing various mistakes in emojis.
Some of them have been fixed manually in db.json/data.js/groups.json and will need to be fixed in emoji-db gem.
The "last custom date and time" shortcut for the topic timer and
bookmarks could get into a state where it had an Invalid Date if
the user opened the topic timer modal, clicked Custom Date and then
closed the modal without making changes. This has been fixed, the
last custom date + time will no longer be set in this case and if
somehow the last custom date + time is invalid that option will not
show.
Also improve the wording from just "Last" to "Last custom datetime"
* FEATURE: Review every post using the review queue.
If the `review_every_post` setting is enabled, posts created and edited by regular uses are sent to the review queue so staff can review them. We'll skip PMs and posts created or edited by TL4 or staff users.
Staff can choose to:
- Approve the post (nothing happens)
- Approve and restore the post (if deleted)
- Approve and unhide the post (if hidden)
- Reject and delete it
- Reject and keep deleted (if deleted)
- Reject and suspend the user
- Reject and silence the user
* Update config/locales/server.en.yml
Co-authored-by: Robin Ward <robin.ward@gmail.com>
Co-authored-by: Robin Ward <robin.ward@gmail.com>
When the user has not selected any tags and minimum_required_tags
is specified for a category, they get a clientside validation error
to tell them this. We were not doing the same thing when
min_tags_from_required_group and required_tag_groups was specified.
There is a category setting that enforces 1 or more tags must be added to a topic from a specific tag group before creating it. This validation was not being run before the topic was being sent to a review queue for categories that have that setting enabled.
There was an existing validation in `TopicCreator` but it was not correct; it was only validating when the tags did _not_ exist and also only happened on `create`. I now run the validation in `TopicCreator.valid?`
I also improved the error message shown to the user when they have not added the tags required (showing the tag names from the tag group), and changed the composer tag selector to not show "optional" if there are N tags required from a certain group.
Headings with the exact same name generated exactly the same heading
names, which was invalid. This replaces the old code for generating
names for non-English headings which were using URI encode and resulted
in unreadable headings.
I noticed this while trying to debug slow performing ember tests.
Our docking mixin sometimes sets timers but never cancels them when
removed. I'm not sure of any errors this causes but we should be tidying
up whenever the component is removed.
This commit also updates github’s body onebox styles in Discourse core:
- full width
- prevents show-more btn to trigger vertical scrolling
- makes text standout less and slightly bigger
When invited by email, users will receive an invite URL which contains
a token. If that token is present when the invite is redeemed, their
account will be automatically activated.
* FIX: Use theme color for anchor icon
* FIX: Do not count anchor links
* FIX: Do not count hashtags links either
* DEV: Add tests for link_count
* FIX: Disable anchors in quotes and preview
* FIX: Try building some anchor slugs for unicode
* DEV: Fix tests
This PR adds a new category setting which is a column in the `categories` table, `allow_unlimited_owner_edits_on_first_post`.
What this does is:
* Inside the `can_edit_post?` method of `PostGuardian`, if the current user editing a post is the owner of the post, it is the first post, and the topic's category has `allow_unlimited_owner_edits_on_first_post`, then we bypass the check for `LimitedEdit#edit_time_limit_expired?` on that post.
* Also, similar to wiki topics, in `PostActionNotifier#after_create_post_revision` we send a notification to all users watching a topic when the OP is edited in a topic with the category setting `allow_unlimited_owner_edits_on_first_post` enabled.
This is useful for forums where there is a Marketplace or similar category, where topics are created and then updated indefinitely by the OP rather than the OP making new topics or additional replies. In a way this acts similar to a wiki that only one person can edit.
* Fixes the z-index of the prompt so it is behind the quick access panels
* Adds a dismiss `X` button (made sure the click target of this was quite big)
* Change structure of HTML to address template lint issues
* Fix aria-hidden not returning true/false
* Reload current page instead of navigating to / when clicking on the prompt message
Since cd24eff5d9, theme modules are now prefixed with the theme id. Therefore themes which defined raw-view classes will be broken
This commit updates the `raw` helper to use the resolver for looking up the view class. This automatically takes care of trying theme/plugin paths in addition to core paths.
This commit allows themes and theme components to have QUnit tests. To add tests to your theme/component, create a top-level directory in your theme and name it `test`, and Discourse will save all the files in that directory (and its sub-directories) as "tests files" in the database. While tests files/directories are not required to be organized in a specific way, we recommend that you follow Discourse core's tests [structure](https://github.com/discourse/discourse/tree/master/app/assets/javascripts/discourse/tests).
Writing theme tests should be identical to writing plugins or core tests; all the `import` statements and APIs that you see in core (or plugins) to define/setup tests should just work in themes.
You do need a working Discourse install to run theme tests, and you have 2 ways to run theme tests:
* In the browser at the `/qunit` route. `/qunit` will run tests of all active themes/components as well as core and plugins. The `/qunit` now accepts a `theme_name` or `theme_url` params that you can use to run tests of a specific theme/component like so: `/qunit?theme_name=<your_theme_name>`.
* In the command line using the `themes:qunit` rake task. This take is meant to run tests of a single theme/component so you need to provide it with a theme name or URL like so: `bundle exec rake themes:qunit[name=<theme_name>]` or `bundle exec rake themes:qunit[url=<theme_url>]`.
There are some refactors to how Discourse processes JavaScript that comes with themes/components, and these refactors may break your JS customizations; see https://meta.discourse.org/t/upcoming-core-changes-that-may-break-some-themes-components-april-12/186252?u=osama for details on how you can check if your themes/components are affected and what you need to do to fix them.
This commit also improves theme error handling in Discourse. We will now be able to catch errors that occur when theme initializers are run and prevent them from breaking the site and other themes/components.
The implemented helpers, are helper which might be in Ember core in the future:
- and
- or
- not
- eq
- not-eq
- lt
- lte
- gt
- gte
They follow the implementation of ember-truth-helpers: https://github.com/jmurphyau/ember-truth-helpers
Note 1: Ember rfcs are still debating going with {{not-eq}} or {{neq}}, should be easy to support in the future whatever is finally chosen.
Note 2: this commit also moves it to its own addon, and removes the {{not}} test, to simplify further updates.
You can enable this by using the `includePostAttributes` API call with
the value of `topicMap`. This will always show the topic map at the top
of a topic regardless of how many posts there are.
Currently, new topics for specific tags can be dismissed with the button at the bottom of the page.
When there is more than 15 new topics, we should display the same button at the top as well. It already works in the same manner for categories.
`isTesting` is a function, so `if(isTesting)` was only checking for the presence of the function. We need to actually evaluate it. Followup to 68a032a734
To add an extra layer of security, we sanitize settings before shipping them to the client. We don't sanitize those that have the "html" type.
The CookedPostProcessor already uses Loofah for sanitization, so I chose to also use it for this. I added it to our gemfile since we installed it as a transitive dependency.
Clock manipulation seems not reliable in component tests. This blog post does a great job of explaining it: https://dockyard.com/blog/2018/04/18/bending-time-in-ember-tests
Sadly, we don't have all the "recent" ember test helpers and can't use things like `getSettledState()`.
For now this pattern seems the most reliable and easy to apply, albeit not great.
Note if you wish to reproduce the current timeout, the following command should do it: `QUNIT_SEED=215263717493121190480103670124734840282 rake qunit:test`
This commit allows themes and theme components to have QUnit tests. To add tests to your theme/component, create a top-level directory in your theme and name it `test`, and Discourse will save all the files in that directory (and its sub-directories) as "tests files" in the database. While tests files/directories are not required to be organized in a specific way, we recommend that you follow Discourse core's tests [structure](https://github.com/discourse/discourse/tree/master/app/assets/javascripts/discourse/tests).
Writing theme tests should be identical to writing plugins or core tests; all the `import` statements and APIs that you see in core (or plugins) to define/setup tests should just work in themes.
You do need a working Discourse install to run theme tests, and you have 2 ways to run theme tests:
* In the browser at the `/qunit` route. `/qunit` will run tests of all active themes/components as well as core and plugins. The `/qunit` now accepts a `theme_name` or `theme_url` params that you can use to run tests of a specific theme/component like so: `/qunit?theme_name=<your_theme_name>`.
* In the command line using the `themes:qunit` rake task. This take is meant to run tests of a single theme/component so you need to provide it with a theme name or URL like so: `bundle exec rake themes:qunit[name=<theme_name>]` or `bundle exec rake themes:qunit[url=<theme_url>]`.
There are some refactors to internal code that's responsible for processing themes/components in Discourse, most notably:
* `<script type="text/discourse-plugin">` tags are automatically converted to modules.
* The `theme-settings` service is removed in favor of a simple `lib` file responsible for managing theme settings. This was done to allow us to register/lookup theme settings very early in our Ember app lifecycle and because there was no reason for it to be an Ember service.
These refactors should 100% backward compatible and invisible to theme developers.
This moves the "This site was just updated" modal asking the user if they want to refresh into a subtle prompt that slides down from the header.
Also in this PR I've added a helper to publish message bus messages in JS tests. So instead of this:
```javascript
// Mimic a messagebus message
MessageBus.callbacks
.filterBy("channel", "/global/asset-version")
.map((c) => c.func("somenewversion"));
```
We can have:
```javascript
publishToMessageBus("/global/asset-version", "somenewversion");
```
With a link having an empty href: `<a href>foo</a>` doing
`element.href` will give you the URL of the document, to get the same behavior than `$(element).attr("href")` and get "" you need to do `element.getAttribute("href")`
Changing the invite type from link to email and then copying it was
confusing because it gave user the impression that the invite was
updated and the invite link will reflect the latest changes, but it
did not.
If the user has not been sent any messages, show a message in the quick access menu with an educational message. If the user can send private messages, also show a link to open the "new message" composer:
This also adds a general improvement to the quick-access-panel, to be able to show an `emptyStateWidget` instead of just a message if there is nothing to show in the panel, as well as initial general styles for empty state.
After clicking the message button on the group page, the composer shouldn't display the "official warning" checkbox. The discourse-bcc plugin also relies on this attribute to display an option in the composer.
This change makes is so that when a time-picking modal (e.g. "Add bookmark" modal) is visible, **all** global key bindings are paused.
1. Fixes an issue where opening and closing a time-picking modal would break global single-key keybinds, so for example, <kbd>L</kbd> would no longer like posts, but <kbd>L</kbd> <kbd>L</kbd> would
2. Fixes a related issue, where doing the above would also override custom keybinds provided by plugins (e.g. <kbd>L</kbd> shortcut that discourse-reactions uses)
Included:
* DEV: Reset Mousetraps instead of unbinding
* FIX: Make unbind use unbind
* DEV: Don't check for keyTrapper twice
* DEV: Use an instance of Mousetrap
* DEV: Remove an invalid `for` attribute (`set_reminder` doesn't exist)
* DEV: Add ability to pause all KeyboardShortcuts
* FIX: Pause all keybinds when in a time-picking modal
* DEV: Move bookmark keybind resets to willDestroyElement
* DEV: Fix shortcuts-related tests
Admins can use bulk invites to pre-populate user fields. The imported
CSV file must have a header with "email" column (first position) and
names of the user fields (exact match).
Under the hood, the bulk invite will create staged users and populate
the user fields of those.
This PR improves the code structure of the topic-timer-info component while retaining all the functionality and making it extensible for theme/plugin devs.
The diff is confusing but the gist is that there are some topic acceptance tests that were incorrectly placed in "Topic featured links" group. This moves them into "Topic".
Moved tests:
* Converting to a public topic
* Unpinning unlisted topic
* selecting posts
* select below
* View Hidden Replies
* Quoting a quote keeps the original poster name
* Quoting a quote of a different topic keeps the original topic title
* Quoting a quote with the Reply button keeps the original poster name
* Quoting a quote with replyAsNewTopic keeps the original poster name
* Quoting by selecting text can mark the quote as full
Applying oneboxes and replacing censored watched words does not happen
in a strict order which often lead to inconsistencies. This commit
fixes the behavior and will never censor oneboxes.
To make it always censor oneboxes implies significant changes to the
PrettyText pipeline.
This form does not need to show if discourse connect is enabled
because generally the fields that would be filled in here are
filled in by the SSO provider. There is also an issue right now
where enable_local_logins and enable_discourse_connect can be
true at the same time which is not right.
Find & Replace and Autotag watched words were not completely exported
and import did not work with these either. This commit changes the
input and output format to CSV, which allows for a secondary column.
This change is backwards compatible because a CSV file with only one
column has one value per line.
There are a lot of little fixes to tests here, but the biggest issue was
too much recursion because we kept replacing the helpers over and over
again. I assume Chrome has tail recursion or something to speed this up
but Firefox hated it.
Otherwise, we can't rely on the order of attributes in rendered HTML so
I simplified most of those tests to just look for key strings in the
HTML that are rendered.
Fixes an issue where the "Keep editing" button in the discard draft
modal wouldn't work when switching to a new topic with an open composer
and clicking Reply.
Followup to d470e4f
Users can now pin bookmarks from their bookmark list. This will anchor the bookmark to the top of the list, and show a pin icon next to it. This also applies in the nav bookmarks panel. If there are multiple pinned bookmarks they sort by last updated order.
We currently make an AJAX request every time someone opens the hamburger menu, resulting in a forbidden response when a user can't see the review queue.
This commit ensures that email validation is skipped when the email is
obfuscated, that the email is no longer send when it is not an invite
link and no username is suggested if the email is hidden as it may
reveal the first part of the email.
Follow up to commit 033d6b6437.
* DEV: Use custom tags rather than handlebars server side
These will be skipped if they are ever rendered in a document. The
handlebars really messes stuff up.
* DEV: Build our own locale file for testing purposes
We can't practically proxy everything in test mode, but we can
approximate the logic and build our own locale file for testing purposes
that works quite well. This allows us to run tests without a proxy.
* DEV: Support for testem runner for ember cli tests
We previously included this option conditionally when users were replying
or creating a new topic while they had content already in the composer.
This makes the dialog always include three buttons:
- Close and discard
- Close and save draft for later
- Keed editing
This also changes how the backend notifies the frontend when there is
a current draft topic. This is now sent via the `has_topic_draft`
property in the current user serializer.
This PR allows invitations to be used when the DiscourseConnect SSO is enabled for a site (`enable_discourse_connect`) and local logins are disabled. Previously invites could not be accepted with SSO enabled simply because we did not have the code paths to handle that logic.
The invitation methods that are supported include:
* Inviting people to groups via email address
* Inviting people to topics via email address
* Using invitation links generated by the Invite Users UI in the /my/invited/pending route
The flow works like this:
1. User visits an invite URL
2. The normal invitation validations (redemptions/expiry) happen at that point
3. We store the invite key in a secure session
4. The user clicks "Accept Invitation and Continue" (see below)
5. The user is redirected to /session/sso then to the SSO provider URL then back to /session/sso_login
6. We retrieve the invite based on the invite key in secure session. We revalidate the invitation. We show an error to the user if it is not valid. An additional check here for invites with an email specified is to check the SSO email matches the invite email
7. If the invite is OK we create the user via the normal SSO methods
8. We redeem the invite and activate the user. We clear the invite key in secure session.
9. If the invite had a topic we redirect the user there, otherwise we redirect to /
Note that we decided for SSO-based invites the `must_approve_users` site setting is ignored, because the invite is a form of pre-approval, and because regular non-staff users cannot send out email invites or generally invite to the forum in this case.
Also deletes some group invite checks as per https://github.com/discourse/discourse/pull/12353
Highlight.js changed their default branch from master to main. This switches to the @highlightjs/cdn-assets package, thus sidestepping the problem. It's a slightly cleaner integration though (no need to build locally anymore).
We override the default replacements rule to no longer replace "(c)", "(p)", and "(p)". Additionally, we merged the custom arrows rule into the replacement function.
When syncing code elements, the inner text used to be escaped, which
rendered the actual HTML code instead. This commit overwrites default
parser settings to fix the way code tags are handled.
* UX: Move modal footer into better container
This commit moves the modal footer under the sign-up form for a more cohesive feel between the login + create account modals.
This is not a security issue because regular users are not allowed to insert FA icons anywhere in the app. Admins can insert icons via custom badges, but they do have the ability to create themes with JS.
Currently the process of adding a custom image to badge is quite clunky; you have to upload your image to a topic, and then copy the image URL and pasting it in a text field. Besides being clucky, if the topic or post that contains the image is deleted, the image will be garbage-collected in a few days and the badge will lose the image because the application is not that the image is referenced by a badge.
This commit improves that by adding a proper image uploader widget for badge images.
This commit extends functionality of the expired invites tab, making
it more similar to the pending tab. It also implements a different
layout for mobile.
Some git repos have a different ssh url scheme than github and we should
support them.
This change updates our regex format to account for repos that don't
start with "git", but are still valid ssh urls.
Also I added some tests to account for the various formats and to ensure
we don't show the public key when using https urls.
See: https://meta.discourse.org/t/182668
* FIX: Invite acceptance tests were broken in Ember CLI
They relied on old Ember behavior where the app does not boot until
`visit` is called and this is no longer true.
This refactors the test to DRY stuff up a bit, and modify the DOM where
necessary in `needs.hooks.beforeEach`.
* Update app/assets/javascripts/discourse/tests/acceptance/invite-accept-test.js
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
* UX: Add class to body on first unread notification
This commit adds `first-notification` class to the body element when there is a first unread notification. This will fix any issues with certain themes who use custom headers where z-index issues sometimes cause those custom headers to not be hidden by the transparent shadow over the page.
This commit ensures that "prioritize username in ux" setting is
respected in following places:
- user directory
- user summary
- badge detail
- group detail
Staff can send a post to the review queue by clicking the "Flag Post" button next to "Take Action...". Clicking it flags the post using the "Notify moderators" score type and hides it. A custom message will be sent to the user.
The recalculation of the `forceActive` function for the nav items was being run _before_ the querystring parameters are getting updated. For example for the Unassigned link:
```javascript
i.addNavigationBarItem({
name: "unassigned",
customFilter: (category) => {
return category && category.enable_unassigned_filter;
},
customHref: (category) => {
if (category) {
return getURL(category.url) + "/l/latest?status=open&assigned=nobody";
}
},
forceActive: (category, args, router) => {
const queryParams = router.currentRoute.queryParams;
return (
queryParams &&
Object.keys(queryParams).length === 2 &&
queryParams["assigned"] === "nobody" &&
queryParams["status"] === "open"
);
},
before: "top",
});
```
When forceActive is hit going from e.g.`http://localhost:3000/c/some-category/5/l/top` to `http://localhost:3000/c/some-category/5/l/latest?assigned=nobody&status=open` the `queryParams` are empty and the URL does not seem to change until after the transition and so `active` ends up being false in this `navigation-item` function which controls whether or not to do the highlight:
```javascript
@discourseComputed("content.filterType", "filterType", "content.active")
active(contentFilterType, filterType, active) {
if (active !== undefined) {
return active;
}
return contentFilterType === filterType;
},
```
Also sometimes this is not even recalculated, for example going from `http://localhost:3000/c/some-category/5/l/latest?status=open` to `http://localhost:3000/c/some-category/5/l/latest?assigned=nobody&status=open`. This PR fixes the issue where the query parameters changing was not forcing this recalculation. This was especially noticable in conjunction with https://github.com/discourse/discourse-loading-slider.
The title of Twitter oneboxes is always the name of the Twitter user,
which is not a descriptive topic title. Leave the title field blank so
that users must enter their own title.
By default our QUnit test runner starts automatically. This is normally
fine but for our `run-qunit.js` script we add a bunch of QUnit events
using `eval` and sometimes those events were added after the tests
already started/finished resulting in a hang.
This adds a new parameter that will cause QUnit not to run
automatically, which the runner uses, then triggers a `start()` when it
knows it's ready.
The signup boolean was being passed in the third _autoLogin argument, when it should have been the fourth. The third parameter to _autoLogin was optional, which is confusing. This commit cleans things up so both optional arguments are supplied via keywords.
Followup to cbef2ba151