Version bump

This commit is contained in:
Alan Guo Xiang Tan 2023-01-05 09:47:19 +08:00
commit 21252f9a4d
No known key found for this signature in database
GPG Key ID: 3F656E28E3AADEF1
65 changed files with 444 additions and 3903 deletions

View File

@ -30,6 +30,7 @@ jobs:
PGUSER: discourse
PGPASSWORD: discourse
USES_PARALLEL_DATABASES: ${{ matrix.build_type == 'backend' }}
CAPBYARA_DEFAULT_MAX_WAIT_TIME: 4
strategy:
fail-fast: false

View File

@ -92,7 +92,7 @@ GEM
bootsnap (1.15.0)
msgpack (~> 1.2)
builder (3.2.4)
bullet (7.0.5)
bullet (7.0.7)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
byebug (11.1.3)
@ -138,7 +138,7 @@ GEM
regexp_parser (~> 2.2)
email_reply_trimmer (0.1.13)
erubi (1.11.0)
excon (0.95.0)
excon (0.96.0)
execjs (2.8.1)
exifr (1.3.10)
fabrication (2.30.0)
@ -298,7 +298,7 @@ GEM
parallel (1.22.1)
parallel_tests (4.0.0)
parallel
parser (3.1.3.0)
parser (3.2.0.0)
ast (~> 2.4.1)
pg (1.4.5)
progress (3.6.0)
@ -314,7 +314,7 @@ GEM
puma (6.0.2)
nio4r (~> 2.0)
r2 (0.2.7)
racc (1.6.1)
racc (1.6.2)
rack (2.2.5)
rack-mini-profiler (3.0.0)
rack (>= 1.2.0)
@ -442,7 +442,7 @@ GEM
connection_pool (>= 2.2.5, < 3)
rack (~> 2.0)
redis (>= 4.5.0, < 5)
simplecov (0.21.2)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
@ -471,7 +471,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.3.0)
unicode-display_width (2.4.2)
unicorn (6.1.0)
kgio (~> 2.6)
raindrops (~> 0.7)

View File

@ -91,7 +91,7 @@ The original Discourse code contributors can be found in [**AUTHORS.MD**](docs/A
## Copyright / License
Copyright 2014 - 2022 Civilized Discourse Construction Kit, Inc.
Copyright 2014 - 2023 Civilized Discourse Construction Kit, Inc.
Licensed under the GNU General Public License Version 2.0 (or later);
you may not use this work except in compliance with the License.

View File

@ -106,7 +106,7 @@
}}
@action={{action "revert" c}}
@title="admin.customize.colors.revert_title"
@label="revert"
@label="admin.customize.colors.revert"
/>
<DButton
@class={{concat
@ -115,7 +115,7 @@
}}
@action={{action "undo" c}}
@title="admin.customize.colors.undo_title"
@label="undo"
@label="admin.customize.colors.undo"
/>
{{/unless}}
</td>
@ -127,4 +127,4 @@
<p>{{i18n "search.no_results"}}</p>
{{/if}}
</div>
</div>
</div>

View File

@ -22,7 +22,7 @@
"xss": "^1.0.14"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
"webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -22,7 +22,7 @@
"webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -17,7 +17,7 @@
"webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.20.7"
"@babel/core": "^7.20.12"
},
"engines": {
"node": "16.* || >= 18",

View File

@ -22,7 +22,7 @@
"webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -60,7 +60,9 @@ export default Component.extend({
userTimezone: this.currentUser.user_option.timezone,
showOptions: false,
_itsatrap: new ItsATrap(),
autoDeletePreference: this.model.autoDeletePreference || 0,
autoDeletePreference:
this.model.autoDeletePreference ||
AUTO_DELETE_PREFERENCES.CLEAR_REMINDER,
});
this.registerOnCloseHandler(this._onModalClose);

View File

@ -2,7 +2,10 @@
@sectionName="messages"
@headerActionIcon="plus"
@headerActions={{array
(hash action=(fn (route-action "composePrivateMessage") null null))
(hash
action=(fn (route-action "composePrivateMessage") null null)
title=(i18n "sidebar.sections.messages.header_action_title")
)
}}
@headerActionsIcon="plus"
@headerLinkText={{i18n "sidebar.sections.messages.header_link_text"}}

View File

@ -836,12 +836,7 @@ export default Controller.extend(bufferedProperty("model"), {
);
return this._modifyPostBookmark(
bookmarkForPost ||
Bookmark.create({
bookmarkable_id: post.id,
bookmarkable_type: "Post",
auto_delete_preference:
this.currentUser.user_option.bookmark_auto_delete_preference,
}),
Bookmark.createFor(this.currentUser, "Post", post.id),
post
);
} else {
@ -1349,12 +1344,7 @@ export default Controller.extend(bufferedProperty("model"), {
if (this.model.bookmarkCount === 0) {
return this._modifyTopicBookmark(
Bookmark.create({
bookmarkable_id: this.model.id,
bookmarkable_type: "Topic",
auto_delete_preference:
this.currentUser.user_option.bookmark_auto_delete_preference,
})
Bookmark.createFor(this.currentUser, "Topic", this.model.id)
);
}
},

View File

@ -12,12 +12,23 @@ export default {
initialize(container) {
this.messageBus = container.lookup("service:message-bus");
this.dialog = container.lookup("service:dialog");
this.currentUser = container.lookup("service:current-user");
this.messageBus.subscribe("/logout", this.onMessage);
if (this.currentUser) {
this.messageBus.subscribe(
`/logout/${this.currentUser.id}`,
this.onMessage
);
}
},
teardown() {
this.messageBus.unsubscribe("/logout", this.onMessage);
if (this.currentUser) {
this.messageBus.unsubscribe(
`/logout/${this.currentUser.id}`,
this.onMessage
);
}
},
@bind

View File

@ -94,7 +94,7 @@ export default function (options) {
let completeEnd = null;
let me = this;
let div = null;
let fadeoutDiv = null;
let scrollElement = null;
let prevTerm = null;
// By default, when the autocomplete popup is rendered it has the
@ -119,28 +119,29 @@ export default function (options) {
}
function scrollAutocomplete() {
if (!fadeoutDiv && !div) {
if (!scrollElement && !div) {
return;
}
const scrollingDivElement = fadeoutDiv?.length > 0 ? fadeoutDiv[0] : div[0];
const scrollingElement =
scrollElement?.length > 0 ? scrollElement[0] : div[0];
const selectedElement = getSelectedOptionElement();
const selectedElementTop = selectedElement.offsetTop;
const selectedElementBottom =
selectedElementTop + selectedElement.clientHeight;
// the top of the item is above the top of the fadeoutDiv, so scroll UP
if (selectedElementTop <= scrollingDivElement.scrollTop) {
scrollingDivElement.scrollTo(0, selectedElementTop);
// the top of the item is above the top of the scrollElement, so scroll UP
if (selectedElementTop <= scrollingElement.scrollTop) {
scrollingElement.scrollTo(0, selectedElementTop);
// the bottom of the item is below the bottom of the div, so scroll DOWN
} else if (
selectedElementBottom >=
scrollingDivElement.scrollTop + scrollingDivElement.clientHeight
scrollingElement.scrollTop + scrollingElement.clientHeight
) {
scrollingDivElement.scrollTo(
scrollingElement.scrollTo(
0,
scrollingDivElement.scrollTop + selectedElement.clientHeight
scrollingElement.scrollTop + selectedElement.clientHeight
);
}
}
@ -152,7 +153,7 @@ export default function (options) {
div.hide().remove();
}
div = null;
fadeoutDiv = null;
scrollElement = null;
completeStart = null;
autocompleteOptions = null;
prevTerm = null;
@ -377,7 +378,9 @@ export default function (options) {
me.parent().append(div);
}
fadeoutDiv = div.find(".hashtag-autocomplete__fadeout");
if (options.scrollElementSelector) {
scrollElement = div.find(options.scrollElementSelector);
}
if (isInput || options.treatAsTextarea) {
_autoCompletePopper && _autoCompletePopper.destroy();

View File

@ -123,6 +123,7 @@ function _setupExperimental(
key: "#",
afterComplete: autocompleteOptions.afterComplete,
treatAsTextarea: autocompleteOptions.treatAsTextarea,
scrollElementSelector: ".hashtag-autocomplete__fadeout",
autoSelectFirstSuggestion: true,
transformComplete: (obj) => obj.ref,
dataSource: (term) => {

View File

@ -12,12 +12,13 @@ export default class AboutSectionLink extends BaseSectionLink {
}
get title() {
return I18n.t("sidebar.sections.community.links.about.content");
return I18n.t("sidebar.sections.community.links.about.title");
}
get text() {
return I18n.t("sidebar.sections.community.links.about.content");
}
get prefixValue() {
return "info-circle";
}

View File

@ -12,7 +12,7 @@ export default class BadgesSectionLink extends BaseSectionLink {
}
get title() {
return I18n.t("sidebar.sections.community.links.badges.content");
return I18n.t("sidebar.sections.community.links.badges.title");
}
get text() {

View File

@ -16,7 +16,7 @@ export default class FAQSectionLink extends BaseSectionLink {
}
get title() {
return I18n.t("sidebar.sections.community.links.faq.content");
return I18n.t("sidebar.sections.community.links.faq.title");
}
get text() {

View File

@ -166,6 +166,15 @@ Bookmark.reopenClass({
return this._super(args);
},
createFor(user, bookmarkableType, bookmarkableId) {
return Bookmark.create({
bookmarkable_type: bookmarkableType,
bookmarkable_id: bookmarkableId,
user_id: user.id,
auto_delete_preference: user.user_option.bookmark_auto_delete_preference,
});
},
async applyTransformations(bookmarks) {
await applyModelTransformations("bookmark", bookmarks);
},

View File

@ -49,7 +49,7 @@
<DButton
@action={{action "undoAcceptRequest"}}
@actionParam={{m}}
@label="undo"
@label="groups.requests.undo"
/>
{{else if m.request_denied}}
{{i18n "groups.requests.denied"}}
@ -80,4 +80,4 @@
<div>{{i18n "groups.empty.requests"}}</div>
{{/if}}
</section>
</section>

View File

@ -16,8 +16,8 @@
"test": "ember test"
},
"dependencies": {
"@babel/core": "^7.20.7",
"@babel/standalone": "^7.20.11",
"@babel/core": "^7.20.12",
"@babel/standalone": "^7.20.12",
"@discourse/backburner.js": "^2.7.1-0",
"@discourse/itsatrap": "^2.0.10",
"@ember-compat/tracked-built-ins": "^0.9.1",

View File

@ -8,7 +8,10 @@ import { test } from "qunit";
acceptance("Category and Tag Hashtags", function (needs) {
needs.user();
needs.settings({ tagging_enabled: true });
needs.settings({
tagging_enabled: true,
enable_experimental_hashtag_autocomplete: false,
});
needs.pretender((server, helper) => {
server.get("/hashtags", () => {
return helper.response({

View File

@ -31,7 +31,8 @@ acceptance("Password Reset", function (needs) {
} else {
return helper.response({
success: "OK",
message: I18n.t("password_reset.success"),
message:
"You successfully changed your password and are now logged in.",
});
}
});
@ -44,7 +45,8 @@ acceptance("Password Reset", function (needs) {
) {
return helper.response({
success: "OK",
message: I18n.t("password_reset.success"),
message:
"You successfully changed your password and are now logged in.",
});
} else if (body.second_factor_token === "123123") {
return helper.response({

View File

@ -335,7 +335,7 @@ acceptance("User - Logout", function (needs) {
test("Dialog works", async function (assert) {
sinon.stub(logout, "default");
await visit("/u/eviltrout");
await publishToMessageBus("/logout");
await publishToMessageBus("/logout/19");
assert.ok(exists(".dialog-body"));
assert.ok(

View File

@ -22,7 +22,7 @@
"xss": "^1.0.14"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -21,7 +21,7 @@
"webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -21,7 +21,7 @@
"webpack": "^5.75.0"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -22,7 +22,7 @@
"xss": "^1.0.14"
},
"devDependencies": {
"@babel/core": "^7.20.7",
"@babel/core": "^7.20.12",
"@ember/optional-features": "^2.0.0",
"@embroider/test-setup": "^2.0.2",
"@glimmer/component": "^1.1.2",

View File

@ -17,35 +17,30 @@
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8":
version "7.20.1"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==
"@babel/compat-data@^7.20.5":
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.20.5":
version "7.20.10"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.10.tgz#9d92fa81b87542fff50e848ed585b4212c1d34ec"
integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==
"@babel/core@^7.12.0", "@babel/core@^7.13.8", "@babel/core@^7.16.7", "@babel/core@^7.20.7", "@babel/core@^7.3.4":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.7.tgz#37072f951bd4d28315445f66e0ec9f6ae0c8c35f"
integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==
"@babel/core@^7.12.0", "@babel/core@^7.13.8", "@babel/core@^7.16.7", "@babel/core@^7.20.12", "@babel/core@^7.3.4":
version "7.20.12"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.12.tgz#7930db57443c6714ad216953d1356dac0eb8496d"
integrity sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==
dependencies:
"@ampproject/remapping" "^2.1.0"
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.20.7"
"@babel/helper-compilation-targets" "^7.20.7"
"@babel/helper-module-transforms" "^7.20.7"
"@babel/helper-module-transforms" "^7.20.11"
"@babel/helpers" "^7.20.7"
"@babel/parser" "^7.20.7"
"@babel/template" "^7.20.7"
"@babel/traverse" "^7.20.7"
"@babel/traverse" "^7.20.12"
"@babel/types" "^7.20.7"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.1"
json5 "^2.2.2"
semver "^6.3.0"
"@babel/generator@^7.20.7":
@ -173,7 +168,7 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.20.7":
"@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.20.11":
version "7.20.11"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz#df4c7af713c557938c50ea3ad0117a7944b2f1b0"
integrity sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==
@ -961,10 +956,10 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/standalone@^7.20.11":
version "7.20.11"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.20.11.tgz#8baf940746546e312f39539bdeefa3240108f3ec"
integrity sha512-WUPlwwXFk3iViGE7QFVVp423eVtT+eoXu1940Xu4QJgqgHBF6WWtlwO1Ip5rIWQnp7OHrGdwrwKLtLhUVfOZbA==
"@babel/standalone@^7.20.12":
version "7.20.12"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.20.12.tgz#ae882b8642b4efb1ddd80c8a64a929e028095562"
integrity sha512-hK/X+m1il3w1tYS4H8LDaGCEdiT47SVqEXY8RiEAgou26BystipSU8ZL6EvBR6t5l7lTv0ilBiChXWblKJ5iUA==
"@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7":
version "7.20.7"
@ -975,10 +970,10 @@
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.20.10", "@babel/traverse@^7.20.7", "@babel/traverse@^7.4.5":
version "7.20.10"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.10.tgz#2bf98239597fcec12f842756f186a9dde6d09230"
integrity sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.20.10", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.7", "@babel/traverse@^7.4.5":
version "7.20.12"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.12.tgz#7f0f787b3a67ca4475adef1f56cb94f6abd4a4b5"
integrity sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.20.7"
@ -6358,10 +6353,10 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
json5@^2.1.2, json5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
json5@^2.1.2, json5@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
jsonfile@^2.1.0:
version "2.4.0"

View File

@ -439,6 +439,7 @@ html.composer-open {
}
.name {
display: contents;
font-size: var(--font-down-1);
color: var(--primary-high);
}

View File

@ -150,7 +150,8 @@ $topic-progress-height: 42px;
&.docked {
position: initial;
.topic-admin-popup-menu.right-side {
bottom: -150px; // Prevents menu from being too high when a topic is very short
bottom: unset;
right: 10px;
}
}

View File

@ -1497,7 +1497,7 @@ class User < ActiveRecord::Base
end
def logged_out
MessageBus.publish "/logout", self.id, user_ids: [self.id]
MessageBus.publish "/logout/#{self.id}", self.id, user_ids: [self.id]
DiscourseEvent.trigger(:user_logged_out, self)
end

View File

@ -248,7 +248,7 @@ class SiteSerializer < ApplicationSerializer
end
def whispers_allowed_groups_names
SiteSetting.whispers_allowed_groups_map&.map { |id| Group.where(id: id).pluck_first(:name) }
Group.where(id: SiteSetting.whispers_allowed_groups_map).pluck(:name)
end
def include_whispers_allowed_groups_names?

View File

@ -103,7 +103,7 @@ class UserDestroyer
StaffActionLogger.new(deleted_by).log_user_deletion(user, opts.slice(:context))
Rails.logger.warn("User destroyed without context from: #{caller_locations(14, 1)[0]}") if opts.slice(:context).blank?
end
MessageBus.publish "/logout", result.id, user_ids: [result.id]
MessageBus.publish "/logout/#{result.id}", result.id, user_ids: [result.id]
end
end

View File

@ -429,7 +429,6 @@ en:
enable: "Enable"
disable: "Disable"
continue: "Continue"
undo: "Undo"
switch_to_anon: "Enter Anonymous Mode"
switch_from_anon: "Exit Anonymous Mode"
@ -747,6 +746,7 @@ en:
denied: "denied"
undone: "request undone"
handle: "handle membership request"
undo: "Undo"
manage:
title: "Manage"
name: "Name"
@ -3581,7 +3581,6 @@ en:
create_for_topic: "Create bookmark for topic"
edit: "Edit bookmark"
edit_for_topic: "Edit bookmark for topic"
created: "Created"
updated: "Updated"
name: "Name"
name_placeholder: "What is this bookmark for?"
@ -3907,7 +3906,6 @@ en:
category_title: "Category"
history_capped_revisions: "History, last 100 revisions"
history: "History"
changed_by: "by %{author}"
raw_email:
title: "Incoming Email"
@ -4355,7 +4353,7 @@ en:
new_count:
one: "%{count} new"
other: "%{count} new"
toggle_section: "toggle section"
toggle_section: "Toggle section"
more: "More"
all_categories: "All categories"
all_tags: "All tags"
@ -4364,7 +4362,7 @@ en:
header_link_text: "About"
messages:
header_link_text: "Messages"
header_action_title: "create a personal message"
header_action_title: "Create a personal message"
links:
inbox: "Inbox"
sent: "Sent"
@ -4381,7 +4379,7 @@ en:
none: "You have not added any tags."
click_to_get_started: "Click here to get started."
header_link_text: "Tags"
header_action_title: "edit your sidebar tags"
header_action_title: "Edit your sidebar tags"
configure_defaults: "Configure defaults"
categories:
links:
@ -4391,29 +4389,33 @@ en:
none: "You have not added any categories."
click_to_get_started: "Click here to get started."
header_link_text: "Categories"
header_action_title: "edit your sidebar categories"
header_action_title: "Edit your sidebar categories"
configure_defaults: "Configure defaults"
community:
header_link_text: "Community"
header_action_title: "create a new topic"
header_action_title: "Create a topic"
links:
about:
content: "About"
title: "More details about this site"
admin:
content: "Admin"
title: "Site settings and reports"
badges:
content: "Badges"
title: "All the badges available to earn"
everything:
content: "Everything"
title: "All topics"
faq:
content: "FAQ"
title: "Guidelines for using this site"
groups:
content: "Groups"
title: "All groups"
title: "List of available user groups"
users:
content: "Users"
title: "All users"
title: "List of all users"
my_posts:
content: "My Posts"
title: "My recent topic activity"
@ -4423,7 +4425,7 @@ en:
other: "%{count} drafts"
review:
content: "Review"
title: "review"
title: "Flagged posts and other queued items"
pending_count: "%{count} pending"
welcome_topic_banner:
@ -5107,9 +5109,9 @@ en:
new_name: "New Color Palette"
copy_name_prefix: "Copy of"
delete_confirm: "Delete this color palette?"
undo: "undo"
undo: "Undo"
undo_title: "Undo your changes to this color since the last time it was saved."
revert: "revert"
revert: "Revert"
revert_title: "Reset this color to Discourse's default color palette."
primary:
name: "primary"

View File

@ -833,10 +833,6 @@ en:
password_reset:
no_token: 'Oops! The link you used no longer works. You can <a href="%{base_url}/login">Log In</a> now. If you forgot your password, you can <a href="%{base_url}/password-reset">request a link</a> to reset it.'
choose_new: "Choose a new password"
choose: "Choose a password"
update: "Update Password"
save: "Set Password"
title: "Reset Password"
success: "You successfully changed your password and are now logged in."
success_unapproved: "You successfully changed your password."
@ -1049,7 +1045,7 @@ en:
mailing_list_mode: "Turn off mailing list mode"
all: "Dont send me any mail from %{sitename}"
different_user_description: "You are currently logged in as a different user than the one we emailed. Please log out, or enter anonymous mode, and try again."
not_found_description: Sorry, we couldn't find that subscription. It's possible the link in your email is too old and has expired?"
not_found_description: "Sorry, we couldn't find that subscription. It's possible the link in your email is too old and has expired?"
user_not_found_description: "Sorry, we couldn't find a user for this subscription. You are probably attempting to unsubscribe an account that no longer exists."
log_out: "Log Out"
submit: "Save preferences"

View File

@ -901,7 +901,7 @@ ru:
linux: "Linux"
macos: "macOS"
windows: "Microsoft Windows"
unknown: "неизвестная операционная система"
unknown: "Неизвестная операционная система"
change_email:
wrong_account_error: "Вы вошли не в тот аккаунт — выйдите и повторите попытку."
confirmed: "Адрес электронной почты обновлён."
@ -929,11 +929,11 @@ ru:
connected: "(связанный)"
activation:
action: "Нажмите сюда, чтобы активировать аккаунт"
already_done: "Ссылка на подтверждение аккаунта устарела. Возможно, ваш аккаунт уже активирован?"
please_continue: "Ваш новый аккаунт подтвержден; вы будете перенаправлены на главную страницу."
already_done: "Ссылка на подтверждение аккаунта устарела. Возможно, аккаунт уже активирован?"
please_continue: "Новый аккаунт подтвержден; вы будете перенаправлены на главную страницу."
continue_button: "Перейти на сайт %{site_name}"
welcome_to: "Добро пожаловать на сайт %{site_name}!"
approval_required: "Ваш аккаунт должен быть вручную подтвержден модератором, чтобы вы смогли зайти на форум. Когда аккаунт будет одобрен, вы получите письмо!"
approval_required: "Чтобы вы смогли зайти на форум, ваш аккаунт должен быть вручную подтвержден модератором. Когда аккаунт будет одобрен, вы получите письмо!"
missing_session: "Мы не можем определить, был ли создан аккаунт. Убедитесь, что в браузере включены файлы cookie."
activated: "Этот аккаунт уже активирован."
admin_confirm:
@ -947,7 +947,7 @@ ru:
title: "Требуется одобрение"
post_action_types:
off_topic:
title: "Оффтопик (не по теме)"
title: "Офтопик (не по теме)"
description: "Эта запись не имеет отношения к обсуждению, судя по названию и содержанию первой записи. Возможно, ее стоит перенести."
short_description: "Не относится к обсуждению"
spam:
@ -978,13 +978,13 @@ ru:
like:
title: "Лайк"
description: "Поставить лайк записи"
short_description: "Мне нравится"
short_description: "Поставить лайк записи"
draft:
sequence_conflict_error:
title: "Ошибка черновика"
title: "ошибка черновика"
description: "Черновик редактируется в другом окне. Перезагрузите эту страницу."
draft_backup:
pm_title: "Резервное копирование черновиков из текущих тем"
pm_title: "Резервные копии черновиков из текущих тем"
pm_body: "Тема, содержащая резервные копии черновиков"
user_activity:
no_log_search_queries: "Поиск запросов журнала в настоящее время отключен (администратор может включить их в настройках сайта)."
@ -996,7 +996,7 @@ ru:
authentication_error_gmail_app_password: 'Требуется пароль для конкретного приложения. Дополнительные сведения см. в <a target="_blank" href="https://support.google.com/accounts/answer/185833">этой статье</a>.'
smtp_server_busy_error: "SMTP-сервер сейчас занят, повторите попытку позже."
smtp_unhandled_error: "Произошла необработанная ошибка при подключении к SMTP-серверу. %{message}"
imap_unhandled_error: "Произошла неизвестная ошибка при подключении к IMAP-серверу. %{message}"
imap_unhandled_error: "Произошла необработанная ошибка при подключении к IMAP-серверу. %{message}"
connection_error: "При подключении к серверу возникла проблема, проверьте имя сервера, порт и повторите попытку."
timeout_error: "Время подключения к серверу истекло, проверьте имя сервера, порт и повторите попытку."
unhandled_error: "Необработанная ошибка при тестировании настроек электронной почты. %{message}"
@ -1033,7 +1033,7 @@ ru:
email_title: 'Тема «%{title}» требует внимания модератора'
email_body: "%{link}\n\n%{message}"
flagging:
you_must_edit: '<p>На вашу запись поступила жалоба от сообщества. <a href="%{path}">Проверьте личные сообщения</a>.</p>'
you_must_edit: '<p>На вашу запись поступила жалоба от сообщества. <a href="%{path}">Проверьте сообщения</a>.</p>'
user_must_edit: "<p>На эту запись поступили жалобы от сообщества, поэтому она временно скрыта.</p>"
ignored:
hidden_content: "<p>Проигнорированный контент</p>"
@ -1043,8 +1043,8 @@ ru:
banner:
title: "Тема для баннера"
message:
make: "Это тема для баннера. Он будет отображаться у каждого пользователя сверху на всех страницах, пока он скроет ее."
remove: "Это тема больше не является баннером Он не будет отображаться вверху каждой страницы."
make: "Это тема для баннера, который будет отображаться у каждого пользователя сверху на всех страницах, пока он скроет ее."
remove: "Это тема больше не является баннером и не будет отображаться вверху каждой страницы."
unsubscribed:
title: "Настройки эл. писем обновлены!"
description: "Настройки электронной почты для <b>%{email}</b> были обновлены. Чтобы изменить настройки электронной почты, зайдите в <a href='%{url}'>настройки пользователя</a>."
@ -1064,20 +1064,20 @@ ru:
submit: "Сохранить настройки"
digest_frequency:
title: "Вы получаете письма со сводками %{frequency}"
never_title: "Вы не получаете Email-дайджест"
never_title: "Вы не получаете письма со сводками"
select_title: "Частота писем со сводками:"
never: "Никогда"
every_30_minutes: "Каждые 30 минут"
every_hour: "Каждый час"
daily: "Ежедневно"
weekly: "Еженедельно"
every_month: "Каждый месяц"
every_six_months: "Каждые шесть месяцев"
never: "никогда"
every_30_minutes: "каждые 30 минут"
every_hour: "каждый час"
daily: "ежедневно"
weekly: "еженедельно"
every_month: "каждый месяц"
every_six_months: "каждые шесть месяцев"
user_api_key:
title: "Разрешить доступ для приложения"
authorize: "Разрешить"
read: "чтение"
read_write: "чтение/запись"
read_write: "чтение и запись"
description: 'Приложение «%{application_name}» запрашивает доступ к вашему аккаунту:'
instructions: 'Мы сгенерировали новый API-ключ пользователя для приложения «%{application_name}». Вставьте этот ключ в приложение:'
otp_description: 'Разрешить приложению «%{application_name}» доступ к этому сайту?'

View File

@ -2035,7 +2035,7 @@ developer:
default: true
client: true
enable_experimental_hashtag_autocomplete:
default: false
default: true
client: true
experimental_hashtag_search_result_limit:
default: 20

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class MakeExperimentalHashtagFeatureDefaultForNewSites < ActiveRecord::Migration[7.0]
def up
execute(<<~SQL)
INSERT INTO site_settings (name, data_type, value, created_at, updated_at)
VALUES ('enable_experimental_hashtag_autocomplete', 5, 'f', now(), now())
ON CONFLICT DO NOTHING
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -32,7 +32,7 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
def primary_email_verified?(auth_token)
# Omniauth providers should only provide verified emails in the :info hash.
# This method allows additional checks to be added
true
false
end
def can_revoke?

View File

@ -41,18 +41,24 @@ class BookmarkManager
# automatically.
def create_for(bookmarkable_id:, bookmarkable_type:, name: nil, reminder_at: nil, options: {})
registered_bookmarkable = Bookmark.registered_bookmarkable_from_type(bookmarkable_type)
if registered_bookmarkable.blank?
return add_error(I18n.t("bookmarks.errors.invalid_bookmarkable", type: bookmarkable_type))
end
bookmarkable = registered_bookmarkable.model.find_by(id: bookmarkable_id)
registered_bookmarkable.validate_before_create(@guardian, bookmarkable)
bookmark = Bookmark.create(
{
user_id: @user.id,
bookmarkable: bookmarkable,
name: name,
reminder_at: reminder_at,
reminder_set_at: Time.zone.now
}.merge(bookmark_model_options_with_defaults(options))
)
bookmark =
Bookmark.create(
{
user_id: @user.id,
bookmarkable: bookmarkable,
name: name,
reminder_at: reminder_at,
reminder_set_at: Time.zone.now,
}.merge(bookmark_model_options_with_defaults(options)),
)
return add_errors_from(bookmark) if bookmark.errors.any?
@ -97,16 +103,14 @@ class BookmarkManager
bookmark.reminder_last_sent_at = nil
end
success = bookmark.update(
{
name: name,
reminder_set_at: Time.zone.now,
}.merge(bookmark_model_options_with_defaults(options))
)
success =
bookmark.update(
{ name: name, reminder_set_at: Time.zone.now }.merge(
bookmark_model_options_with_defaults(options),
),
)
if bookmark.errors.any?
return add_errors_from(bookmark)
end
return add_errors_from(bookmark) if bookmark.errors.any?
success
end
@ -116,9 +120,7 @@ class BookmarkManager
bookmark.pinned = !bookmark.pinned
success = bookmark.save
if bookmark.errors.any?
return add_errors_from(bookmark)
end
return add_errors_from(bookmark) if bookmark.errors.any?
success
end
@ -136,20 +138,30 @@ class BookmarkManager
# PostCreator can specify whether auto_track is enabled or not, don't want to
# create a TopicUser in that case
return if opts.key?(:auto_track) && !opts[:auto_track]
TopicUser.change(@user.id, topic, bookmarked: Bookmark.for_user_in_topic(@user.id, topic.id).exists?)
TopicUser.change(
@user.id,
topic,
bookmarked: Bookmark.for_user_in_topic(@user.id, topic.id).exists?,
)
end
def bookmark_model_options_with_defaults(options)
model_options = {
pinned: options[:pinned]
}
model_options = { pinned: options[:pinned] }
if options[:auto_delete_preference].blank?
model_options[:auto_delete_preference] = Bookmark.auto_delete_preferences[:never]
model_options[:auto_delete_preference] = if user_auto_delete_preference.present?
user_auto_delete_preference
else
Bookmark.auto_delete_preferences[:clear_reminder]
end
else
model_options[:auto_delete_preference] = options[:auto_delete_preference]
end
model_options
end
def user_auto_delete_preference
@guardian.user.user_option&.bookmark_auto_delete_preference
end
end

View File

@ -149,7 +149,7 @@ module CookedProcessorMixin
return unless image_sizes.present?
image_sizes.each do |image_size|
url, size = image_size[0], image_size[1]
if url && url.include?(src) &&
if url && src && url.include?(src) &&
size && size["width"].to_i > 0 && size["height"].to_i > 0
return [size["width"], size["height"]]
end

View File

@ -10,7 +10,7 @@ module Discourse
MAJOR = 3
MINOR = 0
TINY = 0
PRE = 'beta15'
PRE = 'beta16'
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end

View File

@ -723,11 +723,7 @@ export default Component.extend({
toggleBookmark() {
return openBookmarkModal(
this.message.bookmark ||
Bookmark.create({
bookmarkable_type: "ChatMessage",
bookmarkable_id: this.message.id,
user_id: this.currentUser.id,
}),
Bookmark.createFor(this.currentUser, "ChatMessage", this.message.id),
{
onAfterSave: (savedData) => {
const bookmark = Bookmark.create(savedData);

View File

@ -345,7 +345,7 @@ en:
direct_messages:
title: "Personal chat"
new: "New personal chat"
new: "Create a personal chat"
create: "Go"
leave: "Leave this personal chat"
cannot_create: "Sorry, you cannot send direct messages."

View File

@ -69,7 +69,7 @@ module Chat::UserNotificationsExtension
# Prioritize messages from regular channels over direct messages
if channels.any?
channel_notification_text(channels, dm_users)
channel_notification_text(channels.sort_by(&:last_message_sent_at), dm_users)
else
direct_message_notification_text(dm_users)
end

View File

@ -53,9 +53,9 @@ RSpec.describe "Archive channel", type: :system, js: true do
end
context "when archiving" do
# before { Jobs.run_immediately! }
it "works" do
Jobs.run_immediately!
xit "works" do
chat.visit_channel_settings(channel_1)
click_button(I18n.t("js.chat.channel_settings.archive_channel"))
find("#split-topic-name").fill_in(with: "An interesting topic for cats")
@ -66,18 +66,19 @@ RSpec.describe "Archive channel", type: :system, js: true do
end
context "when archived channels had unreads" do
before do
before { channel_1.add(current_user) }
it "clears unread indicators" do
Jobs.run_immediately!
other_user = Fabricate(:user)
channel_1.add(other_user)
channel_1.add(current_user)
Chat::ChatMessageCreator.create(
chat_channel: channel_1,
user: other_user,
content: "this is fine @#{current_user.username}",
)
end
xit "clears unread indicators" do
visit("/")
expect(page.find(".chat-channel-unread-indicator")).to have_content(1)
@ -92,10 +93,7 @@ RSpec.describe "Archive channel", type: :system, js: true do
end
context "when archiving failed" do
before do
# Jobs.run_immediately!
channel_1.update!(status: :read_only)
end
before { channel_1.update!(status: :read_only) }
fab!(:archive) do
ChatChannelArchive.create!(
@ -108,7 +106,9 @@ RSpec.describe "Archive channel", type: :system, js: true do
)
end
xit "can be retried" do
it "can be retried" do
Jobs.run_immediately!
chat.visit_channel(channel_1)
click_button(I18n.t("js.chat.channel_archive.retry"))

View File

@ -5,6 +5,8 @@ RSpec.describe "Bookmark message", type: :system, js: true do
let(:chat) { PageObjects::Pages::Chat.new }
let(:channel) { PageObjects::Pages::ChatChannel.new }
let(:bookmark_modal) { PageObjects::Modals::Bookmark.new }
fab!(:category_channel_1) { Fabricate(:category_channel) }
fab!(:message_1) { Fabricate(:chat_message, chat_channel: category_channel_1) }
@ -19,13 +21,32 @@ RSpec.describe "Bookmark message", type: :system, js: true do
chat.visit_channel(category_channel_1)
channel.bookmark_message(message_1)
expect(page).to have_css("#bookmark-reminder-modal")
find("#bookmark-name").fill_in(with: "Check this out later")
find("#tap_tile_next_month").click
bookmark_modal.fill_name("Check this out later")
bookmark_modal.select_preset_reminder(:next_month)
expect(channel).to have_bookmarked_message(message_1)
end
context "when the user has a bookmark auto_delete_preference" do
before do
current_user.user_option.update!(
bookmark_auto_delete_preference: Bookmark.auto_delete_preferences[:on_owner_reply],
)
end
it "is respected when the user creates a new bookmark" do
chat.visit_channel(category_channel_1)
channel.bookmark_message(message_1)
bookmark_modal.save
expect(channel).to have_bookmarked_message(message_1)
bookmark = Bookmark.find_by(bookmarkable: message_1, user: current_user)
expect(bookmark.auto_delete_preference).to eq(
Bookmark.auto_delete_preferences[:on_owner_reply],
)
end
end
end
context "when mobile", mobile: true do
@ -34,10 +55,9 @@ RSpec.describe "Bookmark message", type: :system, js: true do
channel.message_by_id(message_1.id).click(delay: 0.5)
find(".bookmark-btn").click
expect(page).to have_css("#bookmark-reminder-modal")
find("#bookmark-name").fill_in(with: "Check this out later")
find("#tap_tile_next_month").click
bookmark_modal.fill_name("Check this out later")
bookmark_modal.select_preset_reminder(:next_month)
expect(channel).to have_bookmarked_message(message_1)
end

View File

@ -37,13 +37,13 @@ RSpec.describe "Channel - Info - Members page", type: :system, js: true do
channel_1.add(current_user)
channel_1.add(Fabricate(:user, username: "cat"))
98.times { channel_1.add(Fabricate(:user)) }
channel_1.update!(user_count_stale: true)
# Jobs.run_immediately!
Jobs::UpdateChannelUserCount.new.execute(chat_channel_id: channel_1.id)
end
xit "shows all members" do
it "shows all members" do
Jobs.run_immediately!
channel_1.update!(user_count_stale: true)
Jobs::UpdateChannelUserCount.new.execute(chat_channel_id: channel_1.id)
chat_page.visit_channel_members(channel_1)
expect(page).to have_selector(".channel-members-view__list-item", count: 50)
@ -58,7 +58,11 @@ RSpec.describe "Channel - Info - Members page", type: :system, js: true do
end
context "with filter" do
xit "filters members" do
it "filters members" do
Jobs.run_immediately!
channel_1.update!(user_count_stale: true)
Jobs::UpdateChannelUserCount.new.execute(chat_channel_id: channel_1.id)
chat_page.visit_channel_members(channel_1)
find(".channel-members-view__search-input").fill_in(with: "cat")

View File

@ -15,7 +15,7 @@ RSpec.describe "JIT messages", type: :system, js: true do
end
context "when mentioning a user not on the channel" do
xit "displays a mention warning" do
it "displays a mention warning" do
Jobs.run_immediately!
chat.visit_channel(channel_1)
@ -23,6 +23,7 @@ RSpec.describe "JIT messages", type: :system, js: true do
expect(page).to have_content(
I18n.t("js.chat.mention_warning.without_membership.one", username: other_user.username),
wait: 5,
)
end
end
@ -36,7 +37,7 @@ RSpec.describe "JIT messages", type: :system, js: true do
private_channel_1.add(current_user)
end
xit "displays a mention warning" do
it "displays a mention warning" do
Jobs.run_immediately!
chat.visit_channel(private_channel_1)
@ -44,6 +45,7 @@ RSpec.describe "JIT messages", type: :system, js: true do
expect(page).to have_content(
I18n.t("js.chat.mention_warning.cannot_see.one", username: other_user.username),
wait: 5,
)
end
end
@ -52,7 +54,7 @@ RSpec.describe "JIT messages", type: :system, js: true do
context "when group can't be mentioned" do
fab!(:group_1) { Fabricate(:group, mentionable_level: Group::ALIAS_LEVELS[:nobody]) }
xit "displays a mention warning" do
it "displays a mention warning" do
Jobs.run_immediately!
chat.visit_channel(channel_1)
@ -60,6 +62,7 @@ RSpec.describe "JIT messages", type: :system, js: true do
expect(page).to have_content(
I18n.t("js.chat.mention_warning.group_mentions_disabled.one", group_name: group_1.name),
wait: 5,
)
end
end

View File

@ -32,6 +32,8 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
context "when not member of the channel" do
context "when a message is created" do
it "doesn't show anything" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
@ -48,7 +50,6 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
context "when user is in DnD" do
before do
# Jobs.run_immediately!
Fabricate(
:do_not_disturb_timing,
user: current_user,
@ -57,7 +58,9 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
)
end
xit "doesnt show indicator in header" do
it "doesnt show indicator in header" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
@ -70,7 +73,9 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
before { channel_1.membership_for(current_user).update!(muted: true) }
context "when a message is created" do
xit "doesn't show anything" do
it "doesn't show anything" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
@ -84,6 +89,8 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
context "when a message is created" do
it "correctly renders notifications" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
@ -97,6 +104,8 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
context "when a message with mentions is created" do
it "correctly renders notifications" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) do
create_message(
@ -126,6 +135,8 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
context "when a message is created" do
it "correctly renders notifications" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) { create_message(channel: dm_channel_1, creator: user_1) }
@ -134,12 +145,14 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
".chat-channel-row[data-chat-channel-id=\"#{dm_channel_1.id}\"] .chat-channel-unread-indicator",
)
using_session(:user_1) { create_message(channel: dm_channel_1, creator: user_1) }
using_session(:user_1) { create_message(channel: dm_channel_1, creator: user_1) }
expect(page).to have_css(".chat-header-icon .chat-channel-unread-indicator", text: "2")
end
it "reorders channels" do
Jobs.run_immediately!
visit("/chat")
expect(page).to have_css(
@ -174,6 +187,8 @@ RSpec.describe "Message notifications - mobile", type: :system, js: true, mobile
context "when messages are created" do
it "correctly renders notifications" do
Jobs.run_immediately!
visit("/chat")
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }

View File

@ -46,7 +46,6 @@ RSpec.describe "Message notifications - with sidebar", type: :system, js: true d
context "when user is in DnD" do
before do
# Jobs.run_immediately!
Fabricate(
:do_not_disturb_timing,
user: current_user,
@ -55,7 +54,9 @@ RSpec.describe "Message notifications - with sidebar", type: :system, js: true d
)
end
xit "doesnt show indicator in header" do
it "doesnt show indicator in header" do
Jobs.run_immediately!
visit("/")
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
@ -89,9 +90,9 @@ RSpec.describe "Message notifications - with sidebar", type: :system, js: true d
end
context "when a message with mentions is created" do
# before { Jobs.run_immediately! }
it "correctly renders notifications" do
Jobs.run_immediately!
xit "correctly renders notifications" do
visit("/")
using_session(:user_1) do
create_message(

View File

@ -34,6 +34,22 @@ describe "Uploading files in chat messages", type: :system, js: true do
expect(ChatMessage.last.uploads.count).to eq(1)
end
it "allows uploading multiple files" do
chat.visit_channel(channel_1)
file_path_1 = file_from_fixtures("logo.png", "images").path
file_path_2 = file_from_fixtures("logo.jpg", "images").path
attach_file([file_path_1, file_path_2]) do
channel.open_action_menu
channel.click_action_button("chat-upload-btn")
end
expect(page).to have_css(".chat-composer-upload .preview .preview-img", count: 2)
channel.send_message("upload testing")
expect(page).not_to have_css(".chat-composer-upload")
expect(channel).to have_message(text: "upload testing")
expect(ChatMessage.last.uploads.count).to eq(2)
end
it "allows uploading a huge image file with preprocessing" do
SiteSetting.composer_media_optimization_image_bytes_optimization_threshold = 200.kilobytes
chat.visit_channel(channel_1)

View File

@ -39,10 +39,10 @@ RSpec.describe "User menu notifications | sidebar", type: :system, js: true do
context "when dm channel" do
fab!(:dm_channel_1) { Fabricate(:direct_message_channel, users: [current_user, other_user]) }
# before { Jobs.run_immediately! }
context "when @username" do
xit "shows a mention notification" do
it "shows a mention notification" do
Jobs.run_immediately!
message =
Chat::ChatMessageCreator.create(
chat_channel: dm_channel_1,
@ -106,7 +106,9 @@ RSpec.describe "User menu notifications | sidebar", type: :system, js: true do
end
context "when @username" do
xit "shows a mention notification" do
it "shows a mention notification" do
Jobs.run_immediately!
message =
Chat::ChatMessageCreator.create(
chat_channel: channel_1,

View File

@ -13,10 +13,11 @@ RSpec.describe "User status | sidebar", type: :system, js: true do
chat_system_bootstrap
current_user.set_status!("online", "heart")
sign_in(current_user)
# Jobs.run_immediately!
end
xit "shows user status" do
it "shows user status" do
Jobs.run_immediately!
visit("/")
expect(find(".user-status .emoji")["title"]).to eq("online")
@ -24,7 +25,9 @@ RSpec.describe "User status | sidebar", type: :system, js: true do
end
context "when changing status" do
xit "updates status" do
it "updates status" do
Jobs.run_immediately!
visit("/")
current_user.set_status!("offline", "tooth")
@ -34,7 +37,9 @@ RSpec.describe "User status | sidebar", type: :system, js: true do
end
context "when removing status" do
xit "removes status" do
it "removes status" do
Jobs.run_immediately!
visit("/")
current_user.clear_status!

View File

@ -6,6 +6,10 @@ RSpec.describe Auth::ManagedAuthenticator do
def name
"myauth"
end
def primary_email_verified?(auth_token)
auth_token[:info][:email_verified]
end
end.new
}
@ -16,7 +20,8 @@ RSpec.describe Auth::ManagedAuthenticator do
info: {
name: "Best Display Name",
email: "awesome@example.com",
nickname: "IAmGroot"
nickname: "IAmGroot",
email_verified: true
},
credentials: {
token: "supersecrettoken"
@ -59,16 +64,21 @@ RSpec.describe Auth::ManagedAuthenticator do
it 'only sets email valid for present strings' do
# (Twitter sometimes sends empty email strings)
result = authenticator.after_authenticate(create_hash.merge(info: { email: "email@example.com" }))
result = authenticator.after_authenticate(create_hash.merge(info: { email: "email@example.com", email_verified: true }))
expect(result.email_valid).to eq(true)
result = authenticator.after_authenticate(create_hash.merge(info: { email: "" }))
result = authenticator.after_authenticate(create_hash.merge(info: { email: "", email_verified: true }))
expect(result.email_valid).to be_falsey
result = authenticator.after_authenticate(create_hash.merge(info: { email: nil }))
result = authenticator.after_authenticate(create_hash.merge(info: { email: nil, email_verified: true }))
expect(result.email_valid).to be_falsey
end
it 'does not set email valid if email_verified is false' do
result = authenticator.after_authenticate(create_hash.merge(info: { email: "email@example.com", email_verified: false }))
expect(result.email_valid).to eq(false)
end
describe 'connecting to another user account' do
fab!(:user1) { Fabricate(:user) }
fab!(:user2) { Fabricate(:user) }

View File

@ -213,7 +213,14 @@ RSpec.describe BookmarkManager do
it "when post is deleted it raises invalid access from guardian check" do
post.trash!
expect { subject.create_for(bookmarkable_id: post.id, bookmarkable_type: "Post", name: name) }.to raise_error(Discourse::InvalidAccess)
expect do
subject.create_for(bookmarkable_id: post.id, bookmarkable_type: "Post", name: name)
end.to raise_error(Discourse::InvalidAccess)
end
it "adds a validation error when the bookmarkable_type is not registered" do
subject.create_for(bookmarkable_id: post.id, bookmarkable_type: "BlahFactory", name: name)
expect(subject.errors.full_messages).to include(I18n.t("bookmarks.errors.invalid_bookmarkable", type: "BlahFactory"))
end
it "updates the topic user bookmarked column to true if any post is bookmarked" do
@ -227,9 +234,31 @@ RSpec.describe BookmarkManager do
expect(tu.bookmarked).to eq(true)
end
it "sets auto_delete_preference to never by default" do
it "sets auto_delete_preference to clear_reminder by default" do
bookmark = subject.create_for(bookmarkable_id: post.id, bookmarkable_type: "Post", name: name, reminder_at: reminder_at)
expect(bookmark.auto_delete_preference).to eq(Bookmark.auto_delete_preferences[:never])
expect(bookmark.auto_delete_preference).to eq(Bookmark.auto_delete_preferences[:clear_reminder])
end
context "when the user has set their bookmark_auto_delete_preference" do
before do
user.user_option.update!(bookmark_auto_delete_preference: Bookmark.auto_delete_preferences[:on_owner_reply])
end
it "sets auto_delete_preferences to the user's user_option.bookmark_auto_delete_preference" do
bookmark = subject.create_for(bookmarkable_id: post.id, bookmarkable_type: "Post", name: name, reminder_at: reminder_at)
expect(bookmark.auto_delete_preference).to eq(Bookmark.auto_delete_preferences[:on_owner_reply])
end
it "uses the passed in auto_delete_preference option instead of the user's one" do
bookmark = subject.create_for(
bookmarkable_id: post.id,
bookmarkable_type: "Post",
name: name,
reminder_at: reminder_at,
options: { auto_delete_preference: Bookmark.auto_delete_preferences[:when_reminder_sent] }
)
expect(bookmark.auto_delete_preference).to eq(Bookmark.auto_delete_preferences[:when_reminder_sent])
end
end
context "when a reminder time is provided" do

View File

@ -870,10 +870,17 @@ RSpec.describe CookedPostProcessor do
let(:post) { build(:post) }
let(:cpp) { CookedPostProcessor.new(post) }
let(:image_sizes) do
{ "http://my.discourse.org/image.png" => { "width" => 111, "height" => 222 } }
end
it "returns the size" do
image_sizes = { "http://my.discourse.org/image.png" => { "width" => 111, "height" => 222 } }
expect(cpp.get_size_from_image_sizes("/image.png", image_sizes)).to eq([111, 222])
end
it "returns nil whe img node has no src" do
expect(cpp.get_size_from_image_sizes(nil, image_sizes)).to eq(nil)
end
end
describe "#get_size" do

View File

@ -2020,7 +2020,7 @@ RSpec.describe User do
fab!(:user) { Fabricate(:user) }
it 'should publish the right message' do
message = MessageBus.track_publish('/logout') { user.logged_out }.first
message = MessageBus.track_publish("/logout/#{user.id}") { user.logged_out }.first
expect(message.data).to eq(user.id)
end

View File

@ -245,6 +245,10 @@ RSpec.configure do |config|
allow: [Webdrivers::Chromedriver.base_url]
)
if ENV["CAPBYARA_DEFAULT_MAX_WAIT_TIME"].present?
Capybara.default_max_wait_time = ENV["CAPBYARA_DEFAULT_MAX_WAIT_TIME"].to_i
end
Capybara.threadsafe = true
Capybara.disable_animation = true

View File

@ -247,7 +247,7 @@ RSpec.describe SiteSerializer do
SiteSetting.whispers_allowed_groups = "#{group1.id}|#{group2.id}"
serialized = described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to eq(["whisperers1", "whisperers2"])
expect(serialized[:whispers_allowed_groups_names]).to contain_exactly("whisperers1", "whisperers2")
end
it "returns correct group names for automatic groups" do
@ -255,7 +255,7 @@ RSpec.describe SiteSerializer do
SiteSetting.whispers_allowed_groups = "#{Group::AUTO_GROUPS[:staff]}|#{Group::AUTO_GROUPS[:trust_level_4]}"
serialized = described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to eq(["staff", "trust_level_4"])
expect(serialized[:whispers_allowed_groups_names]).to contain_exactly("trust_level_4", "staff")
end
it "returns group names when user is allowed to whisper" do
@ -263,7 +263,7 @@ RSpec.describe SiteSerializer do
SiteSetting.whispers_allowed_groups = "#{group1.id}|#{group2.id}"
serialized = described_class.new(Site.new(user_guardian), scope: user_guardian, root: false).as_json
expect(serialized[:whispers_allowed_groups_names]).to eq(["whisperers1", "whisperers2"])
expect(serialized[:whispers_allowed_groups_names]).to contain_exactly("whisperers1", "whisperers2")
end
it "returns nil when user is not allowed to whisper" do

View File

@ -2,30 +2,34 @@
describe "Bookmarking posts and topics", type: :system, js: true do
fab!(:topic) { Fabricate(:topic) }
fab!(:user) { Fabricate(:user, username: "bookmarkguy") }
fab!(:user) { Fabricate(:user) }
fab!(:post) { Fabricate(:post, topic: topic, raw: "This is some post to bookmark") }
fab!(:post2) { Fabricate(:post, topic: topic, raw: "Some interesting post content") }
it "allows logged in user to create bookmarks with and without reminders" do
sign_in user
visit "/t/#{topic.id}"
topic_page = PageObjects::Pages::Topic.new
expect(topic_page).to have_post_content(post)
let(:topic_page) { PageObjects::Pages::Topic.new }
let(:bookmark_modal) { PageObjects::Modals::Bookmark.new }
before { sign_in user }
def visit_topic_and_open_bookmark_modal(post)
topic_page.visit_topic(topic)
topic_page.expand_post_actions(post)
topic_page.click_post_action_button(post, :bookmark)
end
it "allows the user to create bookmarks with and without reminders" do
visit_topic_and_open_bookmark_modal(post)
bookmark_modal = PageObjects::Modals::Bookmark.new
bookmark_modal.fill_name("something important")
bookmark_modal.save
expect(topic_page).to have_post_bookmarked(post)
bookmark = Bookmark.find_by(bookmarkable: post, user: user)
expect(bookmark.name).to eq("something important")
expect(bookmark.reminder_at).to eq(nil)
topic_page.expand_post_actions(post2)
topic_page.click_post_action_button(post2, :bookmark)
visit_topic_and_open_bookmark_modal(post2)
bookmark_modal = PageObjects::Modals::Bookmark.new
bookmark_modal.select_preset_reminder(:tomorrow)
expect(topic_page).to have_post_bookmarked(post2)
bookmark = Bookmark.find_by(bookmarkable: post2, user: user)
@ -34,13 +38,8 @@ describe "Bookmarking posts and topics", type: :system, js: true do
end
it "does not create a bookmark if the modal is closed with the cancel button" do
sign_in user
visit "/t/#{topic.id}"
topic_page = PageObjects::Pages::Topic.new
topic_page.expand_post_actions(post)
topic_page.click_post_action_button(post, :bookmark)
visit_topic_and_open_bookmark_modal(post)
bookmark_modal = PageObjects::Modals::Bookmark.new
bookmark_modal.fill_name("something important")
bookmark_modal.cancel
@ -48,20 +47,57 @@ describe "Bookmarking posts and topics", type: :system, js: true do
expect(Bookmark.exists?(bookmarkable: post, user: user)).to eq(false)
end
it "creates a bookmark if the modal is closed by clicking outside the modal window" do
visit_topic_and_open_bookmark_modal(post)
bookmark_modal.fill_name("something important")
bookmark_modal.click_outside
expect(topic_page).to have_post_bookmarked(post)
end
it "allows the topic to be bookmarked" do
sign_in user
visit "/t/#{topic.id}"
topic_page = PageObjects::Pages::Topic.new
topic_page.visit_topic(topic)
topic_page.click_topic_footer_button(:bookmark)
bookmark_modal = PageObjects::Modals::Bookmark.new
bookmark_modal.fill_name("something important")
bookmark_modal.save
expect(topic_page).to have_topic_bookmarked
bookmark = try_until_success do
expect(Bookmark.exists?(bookmarkable: topic, user: user)).to eq(true)
end
bookmark =
try_until_success { expect(Bookmark.exists?(bookmarkable: topic, user: user)).to eq(true) }
expect(bookmark).not_to eq(nil)
end
context "when the user has a bookmark auto_delete_preference" do
before do
user.user_option.update!(
bookmark_auto_delete_preference: Bookmark.auto_delete_preferences[:on_owner_reply],
)
end
it "is respected when the user creates a new bookmark" do
visit_topic_and_open_bookmark_modal(post)
bookmark_modal.save
expect(topic_page).to have_post_bookmarked(post)
bookmark = Bookmark.find_by(bookmarkable: post, user: user)
expect(bookmark.auto_delete_preference).to eq(
Bookmark.auto_delete_preferences[:on_owner_reply],
)
end
it "allows the user to choose a different auto delete preference for a bookmark" do
visit_topic_and_open_bookmark_modal(post)
bookmark_modal.save
expect(topic_page).to have_post_bookmarked(post)
bookmark = Bookmark.find_by(bookmarkable: post, user: user)
expect(bookmark.auto_delete_preference).to eq(
Bookmark.auto_delete_preferences[:on_owner_reply],
)
end
end
end

View File

@ -13,6 +13,10 @@ module PageObjects
def cancel
find(".d-modal-cancel").click
end
def click_outside
find(".modal-outer-container").click(x: 0, y: 0)
end
end
end
end

View File

@ -1605,9 +1605,9 @@ json-stable-stringify-without-jsonify@^1.0.1:
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
json5@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab"
integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
jsonfile@^6.0.1:
version "6.1.0"