diff --git a/.changeset/brown-singers-appear.md b/.changeset/brown-singers-appear.md new file mode 100644 index 000000000000..8a9a69f225ac --- /dev/null +++ b/.changeset/brown-singers-appear.md @@ -0,0 +1,7 @@ +--- +'@rocket.chat/ui-client': minor +'@rocket.chat/i18n': minor +'@rocket.chat/meteor': minor +--- + +added `sidepanelNavigation` to feature preview list diff --git a/.changeset/bump-patch-1724712948901.md b/.changeset/bump-patch-1724712948901.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1724712948901.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/bump-patch-1724977971712.md b/.changeset/bump-patch-1724977971712.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1724977971712.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/bump-patch-1725326060827.md b/.changeset/bump-patch-1725326060827.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1725326060827.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/bump-patch-1725387211812.md b/.changeset/bump-patch-1725387211812.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1725387211812.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/cool-actors-sin.md b/.changeset/cool-actors-sin.md new file mode 100644 index 000000000000..e53b8f136ebb --- /dev/null +++ b/.changeset/cool-actors-sin.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Improves Omnichannel queue page performance diff --git a/.changeset/heavy-snails-help.md b/.changeset/heavy-snails-help.md new file mode 100644 index 000000000000..fb10bac9ea8f --- /dev/null +++ b/.changeset/heavy-snails-help.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/rest-typings": minor +--- + +Implemented "omnichannel/contacts.update" endpoint to update contacts diff --git a/.changeset/orange-clocks-wait.md b/.changeset/orange-clocks-wait.md new file mode 100644 index 000000000000..eacb88108a0f --- /dev/null +++ b/.changeset/orange-clocks-wait.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000000..6aa4b3dd5bf9 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,110 @@ +{ + "mode": "pre", + "tag": "rc", + "initialVersions": { + "@rocket.chat/meteor": "6.12.0-develop", + "rocketchat-services": "1.3.0", + "@rocket.chat/account-service": "0.4.3", + "@rocket.chat/authorization-service": "0.4.3", + "@rocket.chat/ddp-streamer": "0.3.3", + "@rocket.chat/omnichannel-transcript": "0.4.3", + "@rocket.chat/presence-service": "0.4.3", + "@rocket.chat/queue-worker": "0.4.3", + "@rocket.chat/stream-hub-service": "0.4.3", + "@rocket.chat/license": "0.2.3", + "@rocket.chat/omnichannel-services": "0.3.0", + "@rocket.chat/pdf-worker": "0.2.0", + "@rocket.chat/presence": "0.2.3", + "@rocket.chat/ui-theming": "0.2.0", + "@rocket.chat/account-utils": "0.0.2", + "@rocket.chat/agenda": "0.1.0", + "@rocket.chat/api-client": "0.2.3", + "@rocket.chat/apps": "0.1.3", + "@rocket.chat/base64": "1.0.13", + "@rocket.chat/cas-validate": "0.0.2", + "@rocket.chat/core-services": "0.5.0", + "@rocket.chat/core-typings": "6.12.0-develop", + "@rocket.chat/cron": "0.1.3", + "@rocket.chat/ddp-client": "0.3.3", + "@rocket.chat/eslint-config": "0.7.0", + "@rocket.chat/favicon": "0.0.2", + "@rocket.chat/fuselage-ui-kit": "9.0.0", + "@rocket.chat/gazzodown": "9.0.0", + "@rocket.chat/i18n": "0.6.0", + "@rocket.chat/instance-status": "0.1.3", + "@rocket.chat/jest-presets": "0.0.1", + "@rocket.chat/jwt": "0.1.1", + "@rocket.chat/livechat": "1.19.0", + "@rocket.chat/log-format": "0.0.2", + "@rocket.chat/logger": "0.0.2", + "@rocket.chat/message-parser": "0.31.29", + "@rocket.chat/mock-providers": "0.1.1", + "@rocket.chat/model-typings": "0.6.0", + "@rocket.chat/models": "0.2.0", + "@rocket.chat/poplib": "0.0.2", + "@rocket.chat/password-policies": "0.0.2", + "@rocket.chat/patch-injection": "0.0.1", + "@rocket.chat/peggy-loader": "0.31.25", + "@rocket.chat/random": "1.2.2", + "@rocket.chat/release-action": "2.2.3", + "@rocket.chat/release-changelog": "0.1.0", + "@rocket.chat/rest-typings": "6.12.0-develop", + "@rocket.chat/server-cloud-communication": "0.0.2", + "@rocket.chat/server-fetch": "0.0.3", + "@rocket.chat/sha256": "1.0.10", + "@rocket.chat/tools": "0.2.2", + "@rocket.chat/ui-avatar": "5.0.0", + "@rocket.chat/ui-client": "9.0.0", + "@rocket.chat/ui-composer": "0.2.0", + "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-kit": "0.36.0", + "@rocket.chat/ui-video-conf": "9.0.0", + "@rocket.chat/uikit-playground": "0.3.3", + "@rocket.chat/web-ui-registration": "9.0.0" + }, + "changesets": [ + "bright-humans-cross", + "brown-crabs-chew", + "bump-patch-1724712948901", + "bump-patch-1724977971712", + "bump-patch-1725326060827", + "bump-patch-1725387211812", + "calm-tigers-peel", + "cool-actors-sin", + "cool-rocks-remember", + "empty-toys-smell", + "fast-lobsters-turn", + "funny-boats-guess", + "gentle-bugs-think", + "gentle-news-wonder", + "giant-spiders-pay", + "gorgeous-hotels-attend", + "large-geese-ring", + "lemon-steaks-provide", + "nasty-windows-smile", + "new-mayflies-wait", + "ninety-hounds-exist", + "orange-clocks-wait", + "popular-bottles-visit", + "proud-years-buy", + "purple-dolls-serve", + "rich-pillows-hang", + "rooms-table-ts", + "rotten-camels-pretend", + "rude-dogs-burn", + "six-beers-fry", + "smart-baboons-allow", + "smart-mice-attack", + "spicy-kings-think", + "strong-rings-rush", + "strong-swans-double", + "strong-terms-love", + "stupid-fishes-relate", + "swift-maps-tickle", + "ten-bulldogs-clap", + "thirty-dryers-help", + "twelve-windows-train", + "two-bikes-crash", + "violet-radios-begin" + ] +} diff --git a/.changeset/smart-baboons-allow.md b/.changeset/smart-baboons-allow.md new file mode 100644 index 000000000000..0c593e4ed2c5 --- /dev/null +++ b/.changeset/smart-baboons-allow.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed issue that prevented sending encrypted filed from the mobile app diff --git a/.changeset/strong-rings-rush.md b/.changeset/strong-rings-rush.md new file mode 100644 index 000000000000..5125f47dcb3b --- /dev/null +++ b/.changeset/strong-rings-rush.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Restored tooltips to the unit edit department field selected options diff --git a/.changeset/tame-mayflies-press.md b/.changeset/tame-mayflies-press.md new file mode 100644 index 000000000000..e470306cbc25 --- /dev/null +++ b/.changeset/tame-mayflies-press.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": minor +--- + +Implemented sending email via apps diff --git a/.changeset/wise-avocados-taste.md b/.changeset/wise-avocados-taste.md new file mode 100644 index 000000000000..c4c9bce010b8 --- /dev/null +++ b/.changeset/wise-avocados-taste.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue where multi-step modals were closing unexpectedly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 514dd6d1c518..40260f71d21f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -824,7 +824,7 @@ jobs: with: token: ${{ secrets.DISTRIBUTION_TOKEN }} event-type: new_release - repository: RocketChat/Release.Distributions + repository: RocketChat/public-releases client-payload: '{"tag": "${{ github.ref_name }}"}' docs-update: diff --git a/.yarn/patches/typia-npm-5.3.3-21d3e18463.patch b/.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch similarity index 64% rename from .yarn/patches/typia-npm-5.3.3-21d3e18463.patch rename to .yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch index 1487a9f4712d..22a02fa15957 100644 --- a/.yarn/patches/typia-npm-5.3.3-21d3e18463.patch +++ b/.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch @@ -1,22 +1,22 @@ diff --git a/lib/factories/internal/metadata/iterate_metadata_intersection.js b/lib/factories/internal/metadata/iterate_metadata_intersection.js -index 260670b8ea37b63dcacadeffa26450f81087c90e..f07b44b16099d896ab40c46f03df86ee2f2c1a90 100644 +index da05ef3ac6f397d68b8fa10285f62d1794c57579..0f2b9b26e01cebd0b9c04a2db8857f911cfbaf57 100644 --- a/lib/factories/internal/metadata/iterate_metadata_intersection.js +++ b/lib/factories/internal/metadata/iterate_metadata_intersection.js -@@ -247,7 +247,7 @@ var iterate_metadata_intersection = function (checker) { +@@ -181,7 +181,7 @@ var iterate_metadata_intersection = function (checker) { var tags = MetadataTypeTagFactory_1.MetadataTypeTagFactory.analyze(errors)(target)(objects.map(function (om) { return om.objects; }).flat(), explore); if (tags.length) if (target === "array") - meta.arrays.at(-1).tags.push(tags); + meta.arrays.slice(-1)[0].tags.push(tags); - else if (booleanLiteral === null) + else if (atomics.size) meta.atomics.find(function (a) { return a.type === target; }).tags.push(tags); - else { + else if (constants.length) { diff --git a/lib/programmers/CheckerProgrammer.js b/lib/programmers/CheckerProgrammer.js -index bbec09f22798d144b96f59bb946e7e32e3438c05..dc13cb47b72358b8e6165b768cff2360db2bd617 100644 +index 662e6ff51c91598229c88f691b7ce07200957167..4028a50cc92ee293e98b13822293d0fb35c64c1f 100644 --- a/lib/programmers/CheckerProgrammer.js +++ b/lib/programmers/CheckerProgrammer.js -@@ -458,8 +458,8 @@ var CheckerProgrammer; - ? "".concat(explore.postfix.slice(0, -1), "[").concat(index, "]\"") +@@ -529,8 +529,8 @@ var CheckerProgrammer; + ? "".concat((0, postfix_of_tuple_1.postfix_of_tuple)(explore.postfix), "[").concat(index, "]\"") : "\"[".concat(index, "]\"") })); }); - var rest = tuple.elements.length && tuple.elements.at(-1).rest !== null @@ -27,7 +27,7 @@ index bbec09f22798d144b96f59bb946e7e32e3438c05..dc13cb47b72358b8e6165b768cff2360 var arrayLength = typescript_1.default.factory.createPropertyAccessExpression(input, "length"); return config.combiner(explore)("and")(input, __spreadArray(__spreadArray(__spreadArray([], __read((rest === null diff --git a/lib/programmers/TypiaProgrammer.js b/lib/programmers/TypiaProgrammer.js -index c75ab1bc077b788e36c32834ea4916c22df34500..99452220e2dd090d4d562296e26fb266faa617f9 100644 +index db244cb5e40fd68e15b7a06936b0f92802e5e4c9..c2f64885f67cc543c62b0b09e141c88684f99253 100644 --- a/lib/programmers/TypiaProgrammer.js +++ b/lib/programmers/TypiaProgrammer.js @@ -165,7 +165,7 @@ var TypiaProgrammer; @@ -39,34 +39,53 @@ index c75ab1bc077b788e36c32834ea4916c22df34500..99452220e2dd090d4d562296e26fb266 })() : [0, 0], 2), line = _k[0], pos = _k[1]; console.error("".concat(file, ":").concat(line, ":").concat(pos, " - ").concat(category, " TS").concat(diag.code, ": ").concat(diag.messageText)); -diff --git a/lib/programmers/internal/application_tuple.js b/lib/programmers/internal/application_tuple.js -index 5c1853a3a1692f95fe702bdae9813e958f54ac4c..04ca996c2ffe72d1cd5969e45a38e91937b975b1 100644 ---- a/lib/programmers/internal/application_tuple.js -+++ b/lib/programmers/internal/application_tuple.js -@@ -22,15 +22,15 @@ var application_tuple = function (options) { - var schema = __assign(__assign({ type: "array", items: tuple.type.elements.map(function (meta, i) { - var _a; - return (0, application_schema_1.application_schema)(options)(false)(components)((_a = meta.rest) !== null && _a !== void 0 ? _a : meta)(__assign(__assign({}, attribute), { "x-typia-rest": i === tuple.type.elements.length - 1 && meta.rest !== null, "x-typia-required": meta.required, "x-typia-optional": meta.optional })); -- }) }, attribute), { minItems: !!((_a = tuple.type.elements.at(-1)) === null || _a === void 0 ? void 0 : _a.rest) -+ }) }, attribute), { minItems: !!((_a = tuple.type.elements.slice(-1)[0]) === null || _a === void 0 ? void 0 : _a.rest) - ? tuple.type.elements.length - 1 -- : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.at(-1)) === null || _b === void 0 ? void 0 : _b.rest) -+ : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.slice(-1)[0]) === null || _b === void 0 ? void 0 : _b.rest) - ? undefined - : tuple.type.elements.length }); - if (options.purpose === "ajv") - if (tuple.type.elements.length === 0) - return schema; -- else if (!((_c = tuple.type.elements.at(-1)) === null || _c === void 0 ? void 0 : _c.rest)) -+ else if (!((_c = tuple.type.elements.slice(-1)[0]) === null || _c === void 0 ? void 0 : _c.rest)) - return schema; - var wrapper = __assign(__assign({}, schema), { items: (0, application_schema_1.application_schema)(options)(false)(components)(tuple.type.elements.reduce(function (x, y) { var _a, _b; return Metadata_1.Metadata.merge((_a = x.rest) !== null && _a !== void 0 ? _a : x, (_b = y.rest) !== null && _b !== void 0 ? _b : y); }, Metadata_1.Metadata.initialize()))(tuple.type.recursive ? {} : attribute), "x-typia-tuple": schema, minItems: schema.minItems, maxItems: schema.maxItems }); - return wrapper; +diff --git a/lib/programmers/internal/application_v30_tuple.js b/lib/programmers/internal/application_v30_tuple.js +index 94e8827fd94df3792c1d7b2cdacac604175ba8ca..c9a3a1bcdd978b97a080ed2c467188d808d10c8f 100644 +--- a/lib/programmers/internal/application_v30_tuple.js ++++ b/lib/programmers/internal/application_v30_tuple.js +@@ -21,9 +21,9 @@ var application_v30_tuple = function (components) { + return function (tuple) { + return function (attribute) { + var _a, _b; +- return (__assign(__assign({}, attribute), { type: "array", items: (0, application_v30_schema_1.application_v30_schema)(false)(components)(tuple.type.recursive ? {} : attribute)(tuple.type.elements.reduce(function (x, y) { var _a, _b; return Metadata_1.Metadata.merge((_a = x.rest) !== null && _a !== void 0 ? _a : x, (_b = y.rest) !== null && _b !== void 0 ? _b : y); }, Metadata_1.Metadata.initialize())), minItems: !!((_a = tuple.type.elements.at(-1)) === null || _a === void 0 ? void 0 : _a.rest) ++ return (__assign(__assign({}, attribute), { type: "array", items: (0, application_v30_schema_1.application_v30_schema)(false)(components)(tuple.type.recursive ? {} : attribute)(tuple.type.elements.reduce(function (x, y) { var _a, _b; return Metadata_1.Metadata.merge((_a = x.rest) !== null && _a !== void 0 ? _a : x, (_b = y.rest) !== null && _b !== void 0 ? _b : y); }, Metadata_1.Metadata.initialize())), minItems: !!((_a = tuple.type.elements.slice(-1)[0]) === null || _a === void 0 ? void 0 : _a.rest) + ? tuple.type.elements.length - 1 +- : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.at(-1)) === null || _b === void 0 ? void 0 : _b.rest) ++ : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.slice(-1)[0]) === null || _b === void 0 ? void 0 : _b.rest) + ? undefined + : tuple.type.elements.length })); + }; +diff --git a/lib/programmers/internal/application_v31_tuple.js b/lib/programmers/internal/application_v31_tuple.js +index af7bbbe1536244eec93d7311e289fc8b34245c0f..e7f126b72a3480f761f57e4d43826a26b8b06e3f 100644 +--- a/lib/programmers/internal/application_v31_tuple.js ++++ b/lib/programmers/internal/application_v31_tuple.js +@@ -7,7 +7,7 @@ exports.application_v31_tuple = void 0; + var application_v31_tuple = function (generator) { + return function (tuple) { + var _a, _b; +- var tail = (_b = (_a = tuple.type.elements.at(-1)) === null || _a === void 0 ? void 0 : _a.rest) !== null && _b !== void 0 ? _b : null; ++ var tail = (_b = (_a = tuple.type.elements.slice(-1)[0]) === null || _a === void 0 ? void 0 : _a.rest) !== null && _b !== void 0 ? _b : null; + var prefixItems = tuple.type.isRest() + ? tuple.type.elements.slice(0, -1) + : tuple.type.elements; +diff --git a/lib/programmers/internal/decode_union_object.js b/lib/programmers/internal/decode_union_object.js +index c283bdfdcfb99f26954e6d76d35ccef4f78ddcee..7cdef1aeec80238014cf9457ca4351f02e99b638 100644 +--- a/lib/programmers/internal/decode_union_object.js ++++ b/lib/programmers/internal/decode_union_object.js +@@ -72,7 +72,7 @@ var iterate = function (escaper) { + ? typescript_1.default.factory.createIfStatement(b.condition, typescript_1.default.factory.createReturnStatement(b.value), undefined) + : typescript_1.default.factory.createReturnStatement(b.value); + }); +- if (branches.at(-1).condition !== null) ++ if (branches.slice(-1)[0].condition !== null) + statements.push(escaper(input, expected)); + return typescript_1.default.factory.createBlock(statements, true); + }; diff --git a/lib/programmers/json/JsonStringifyProgrammer.js b/lib/programmers/json/JsonStringifyProgrammer.js -index ce0ae787164f7eba68ef35b05232b4b94ad8e7d7..8f70cfc8c8e9d82cd1ec5004ca5637487f57b3bc 100644 +index 77f2812cb509f5b9093dc311f8ae8558e4469a74..54a6c4e22f9cfa87cd30f8ade50e6cb8ccda9957 100644 --- a/lib/programmers/json/JsonStringifyProgrammer.js +++ b/lib/programmers/json/JsonStringifyProgrammer.js -@@ -424,10 +424,10 @@ var JsonStringifyProgrammer; +@@ -469,10 +469,10 @@ var JsonStringifyProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -80,10 +99,10 @@ index ce0ae787164f7eba68ef35b05232b4b94ad8e7d7..8f70cfc8c8e9d82cd1ec5004ca563748 })(); return StringifyJoinder_1.StringifyJoiner.tuple(children, rest); diff --git a/lib/programmers/misc/MiscCloneProgrammer.js b/lib/programmers/misc/MiscCloneProgrammer.js -index 3db6bc92637284468c5fe47ef59f51a9b41d06eb..0b3fa9deaaadf28d4f348225c0d44f49700c1bca 100644 +index 38bec89fba26db7a9c3ee71abd49086692c7e78b..9b9d7a9b0606da78224ce083bcbd7e07cd6ce82e 100644 --- a/lib/programmers/misc/MiscCloneProgrammer.js +++ b/lib/programmers/misc/MiscCloneProgrammer.js -@@ -291,11 +291,11 @@ var MiscCloneProgrammer; +@@ -318,11 +318,11 @@ var MiscCloneProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -98,10 +117,10 @@ index 3db6bc92637284468c5fe47ef59f51a9b41d06eb..0b3fa9deaaadf28d4f348225c0d44f49 return CloneJoiner_1.CloneJoiner.tuple(children, rest); }; diff --git a/lib/programmers/misc/MiscPruneProgrammer.js b/lib/programmers/misc/MiscPruneProgrammer.js -index 8440aaba9e449dae2468e96dfd7035ac7e170cfc..e97ceec78427b7eed08db23cc4775fdb10c6b2ff 100644 +index d4a9c66c0b5508b4ffdc4b7684364a9d748f6508..33f9356bab69faffadb8c2b49997d2c3ca429810 100644 --- a/lib/programmers/misc/MiscPruneProgrammer.js +++ b/lib/programmers/misc/MiscPruneProgrammer.js -@@ -272,11 +272,11 @@ var MiscPruneProgrammer; +@@ -305,11 +305,11 @@ var MiscPruneProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -116,10 +135,10 @@ index 8440aaba9e449dae2468e96dfd7035ac7e170cfc..e97ceec78427b7eed08db23cc4775fdb return PruneJoiner_1.PruneJoiner.tuple(children, rest); }; diff --git a/lib/programmers/notations/NotationGeneralProgrammer.js b/lib/programmers/notations/NotationGeneralProgrammer.js -index 6e0b582a802180d7671c00b999469e7e59193b30..f11cc1d523875a040d3e27ce9a850b083c5d0275 100644 +index dfe64a21a5a81a7e887ab5ae02d73e6d3bdddb03..aa4b6070ed6a83c49018384e3a0c1dbd4a7c540b 100644 --- a/lib/programmers/notations/NotationGeneralProgrammer.js +++ b/lib/programmers/notations/NotationGeneralProgrammer.js -@@ -301,11 +301,11 @@ var NotationGeneralProgrammer; +@@ -328,11 +328,11 @@ var NotationGeneralProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -134,36 +153,36 @@ index 6e0b582a802180d7671c00b999469e7e59193b30..f11cc1d523875a040d3e27ce9a850b08 return NotationJoiner_1.NotationJoiner.tuple(children, rest); }; diff --git a/lib/transformers/CallExpressionTransformer.js b/lib/transformers/CallExpressionTransformer.js -index 2c5a23879d171ee271ebf6857dc9c65ec29c0ea7..96a40845614f6c54fe8e4ebc48a7d8efeba52a41 100644 +index f7be23d98552526d8c2348ba0f3d32b8d31e522b..133af0caa37ffcf7330811ef7bda79e75b9ecd89 100644 --- a/lib/transformers/CallExpressionTransformer.js +++ b/lib/transformers/CallExpressionTransformer.js -@@ -101,7 +101,7 @@ var CallExpressionTransformer; - var location = path_1.default.resolve(declaration.getSourceFile().fileName); - if (isTarget(location) === false) - return expression; +@@ -129,7 +129,7 @@ var CallExpressionTransformer; + // TRANSFORMATION + //---- + // FUNCTION NAME - var module = location.split(path_1.default.sep).at(-1).split(".")[0]; + var module = location.split(path_1.default.sep).slice(-1)[0].split(".")[0]; var name = project.checker.getTypeAtLocation(declaration).symbol.name; + // FIND TRANSFORMER var functor = (_b = FUNCTORS[module]) === null || _b === void 0 ? void 0 : _b[name]; - if (functor === undefined) diff --git a/src/factories/internal/metadata/iterate_metadata_intersection.ts b/src/factories/internal/metadata/iterate_metadata_intersection.ts -index f46caa25c987092597073e046ae3b9e8130bd994..1eedd727c74f173a5b98a9572b865e058885811d 100644 +index c4d93a961385c09abb6f448896ad4636b648703b..99b1547e6a501caf28a452390fe721cd47dc2ca1 100644 --- a/src/factories/internal/metadata/iterate_metadata_intersection.ts +++ b/src/factories/internal/metadata/iterate_metadata_intersection.ts -@@ -214,7 +214,7 @@ export const iterate_metadata_intersection = +@@ -188,7 +188,7 @@ export const iterate_metadata_intersection = target, )(objects.map((om) => om.objects).flat(), explore); if (tags.length) - if (target === "array") meta.arrays.at(-1)!.tags.push(tags); + if (target === "array") meta.arrays.slice(-1)[0]!.tags.push(tags); - else if (booleanLiteral === null) + else if (atomics.size) meta.atomics.find((a) => a.type === target)!.tags.push(tags); - else { + else if (constants.length) { diff --git a/src/programmers/CheckerProgrammer.ts b/src/programmers/CheckerProgrammer.ts -index 892748b80755b89d1449f4d515aa3166534c6b19..8cb5ce35fe6f918545c82066f0583dead2661c89 100644 +index 40f46e8212a5173e19e0214422086655de908933..18a1a2371cac697e1b621a8fbc6b090b691e3072 100644 --- a/src/programmers/CheckerProgrammer.ts +++ b/src/programmers/CheckerProgrammer.ts -@@ -702,14 +702,14 @@ export namespace CheckerProgrammer { +@@ -785,14 +785,14 @@ export namespace CheckerProgrammer { ), ); const rest: ts.Expression | null = @@ -181,47 +200,66 @@ index 892748b80755b89d1449f4d515aa3166534c6b19..8cb5ce35fe6f918545c82066f0583dea ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/TypiaProgrammer.ts b/src/programmers/TypiaProgrammer.ts -index e01eccf62eccd73e1f0720db897f539256a6bbc1..cae5eb6fc702d359d4886acefdb68d42691edf97 100644 +index 67d9fc138483832aae43574fd2753bbe40a27d14..4397517aa620a8733c51917eebfa467f2922bf6d 100644 --- a/src/programmers/TypiaProgrammer.ts +++ b/src/programmers/TypiaProgrammer.ts @@ -101,7 +101,7 @@ export namespace TypiaProgrammer { - .file!.text.substring(0, diag.start) - .split("\n"); - if (lines.length === 0) return [0, 0]; -- return [lines.length, lines.at(-1)!.length + 1]; -+ return [lines.length, lines.slice(-1)[0]!.length + 1]; - })() - : [0, 0]; - console.error( -diff --git a/src/programmers/internal/application_tuple.ts b/src/programmers/internal/application_tuple.ts -index 5e10b9051e4a846f298aa8f086109e8d6bb38bf9..a8e24d5c2a2a4a4d5d1dc49eb45b4784654a4b66 100644 ---- a/src/programmers/internal/application_tuple.ts -+++ b/src/programmers/internal/application_tuple.ts -@@ -28,16 +28,16 @@ export const application_tuple = - }), + .file!.text.substring(0, diag.start) + .split("\n"); + if (lines.length === 0) return [0, 0]; +- return [lines.length, lines.at(-1)!.length + 1]; ++ return [lines.length, lines.slice(-1)[0]!.length + 1]; + })() + : [0, 0]; + console.error( +diff --git a/src/programmers/internal/application_v30_tuple.ts b/src/programmers/internal/application_v30_tuple.ts +index 0431273d439c6069a1bb5fbfd7808c5e8d0ea255..4b27cfc3ebde7ce9dcdb5161d34e70004a327b1e 100644 +--- a/src/programmers/internal/application_v30_tuple.ts ++++ b/src/programmers/internal/application_v30_tuple.ts +@@ -24,10 +24,10 @@ export const application_v30_tuple = + Metadata.initialize(), ), - ...attribute, -- minItems: !!tuple.type.elements.at(-1)?.rest -+ minItems: !!tuple.type.elements.slice(-1)[0]?.rest - ? tuple.type.elements.length - 1 - : tuple.type.elements.filter((x) => !x.optional).length, -- maxItems: !!tuple.type.elements.at(-1)?.rest -+ maxItems: !!tuple.type.elements.slice(-1)[0]?.rest - ? undefined - : tuple.type.elements.length, - }; - if (options.purpose === "ajv") - if (tuple.type.elements.length === 0) return schema; -- else if (!tuple.type.elements.at(-1)?.rest) return schema; -+ else if (!tuple.type.elements.slice(-1)[0]?.rest) return schema; - - const wrapper: IJsonSchema.IArray = { - ...schema, + ), +- minItems: !!tuple.type.elements.at(-1)?.rest ++ minItems: !!tuple.type.elements.slice(-1)[0]?.rest + ? tuple.type.elements.length - 1 + : tuple.type.elements.filter((x) => !x.optional).length, +- maxItems: !!tuple.type.elements.at(-1)?.rest ++ maxItems: !!tuple.type.elements.slice(-1)[0]?.rest + ? undefined! + : tuple.type.elements.length, + }); +diff --git a/src/programmers/internal/application_v31_tuple.ts b/src/programmers/internal/application_v31_tuple.ts +index 426abad3423de706c368b35b2cf6b4845f6f3d91..be15ec0fda1725bf1ea882c9901e0f837c052fde 100644 +--- a/src/programmers/internal/application_v31_tuple.ts ++++ b/src/programmers/internal/application_v31_tuple.ts +@@ -9,7 +9,7 @@ import { MetadataTuple } from "../../schemas/metadata/MetadataTuple"; + export const application_v31_tuple = + (generator: (meta: Metadata) => OpenApi.IJsonSchema) => + (tuple: MetadataTuple): OpenApi.IJsonSchema.ITuple => { +- const tail: Metadata | null = tuple.type.elements.at(-1)?.rest ?? null; ++ const tail: Metadata | null = tuple.type.elements.slice(-1)[0]?.rest ?? null; + const prefixItems: Metadata[] = tuple.type.isRest() + ? tuple.type.elements.slice(0, -1) + : tuple.type.elements; +diff --git a/src/programmers/internal/decode_union_object.ts b/src/programmers/internal/decode_union_object.ts +index f60bf69f91f35dee2efc807475fd6eca71aab052..ef8d51160f7eb9853ec0c827827aaa6c65db1587 100644 +--- a/src/programmers/internal/decode_union_object.ts ++++ b/src/programmers/internal/decode_union_object.ts +@@ -87,7 +87,7 @@ const iterate = + ) + : ts.factory.createReturnStatement(b.value), + ); +- if (branches.at(-1)!.condition !== null) ++ if (branches.slice(-1)[0]!.condition !== null) + statements.push(escaper(input, expected)); + return ts.factory.createBlock(statements, true); + }; diff --git a/src/programmers/json/JsonStringifyProgrammer.ts b/src/programmers/json/JsonStringifyProgrammer.ts -index c317cec2c78e984a6e64c7bf287d0c67e530e309..5974830c62dbd2b865aa2e64e2e757283258d872 100644 +index 558e5bf4b79f5cc28791ba0f5e40ebe6599361ce..c43d77b5d15343af90f7362d1757fc758659d5c9 100644 --- a/src/programmers/json/JsonStringifyProgrammer.ts +++ b/src/programmers/json/JsonStringifyProgrammer.ts -@@ -543,7 +543,7 @@ export namespace JsonStringifyProgrammer { +@@ -560,7 +560,7 @@ export namespace JsonStringifyProgrammer { ); const rest = (() => { if (tuple.elements.length === 0) return null; @@ -230,7 +268,7 @@ index c317cec2c78e984a6e64c7bf287d0c67e530e309..5974830c62dbd2b865aa2e64e2e75728 if (last.rest === null) return null; const code = decode(project)(config)(importer)( -@@ -552,7 +552,7 @@ export namespace JsonStringifyProgrammer { +@@ -569,7 +569,7 @@ export namespace JsonStringifyProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -240,10 +278,10 @@ index c317cec2c78e984a6e64c7bf287d0c67e530e309..5974830c62dbd2b865aa2e64e2e75728 ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/misc/MiscCloneProgrammer.ts b/src/programmers/misc/MiscCloneProgrammer.ts -index 94d768b0a0738c0caccd711671351d1f22fa3848..739fd5f2baf4d2eb8e9dd65d73179242a0244707 100644 +index c8c9cb90085eff7dd68ac332a362674ca33d93d8..76a810816bc4ad57ff5e1787a33cd7f01471ffbe 100644 --- a/src/programmers/misc/MiscCloneProgrammer.ts +++ b/src/programmers/misc/MiscCloneProgrammer.ts -@@ -343,7 +343,7 @@ export namespace MiscCloneProgrammer { +@@ -395,7 +395,7 @@ export namespace MiscCloneProgrammer { const rest = (() => { if (tuple.elements.length === 0) return null; @@ -252,7 +290,7 @@ index 94d768b0a0738c0caccd711671351d1f22fa3848..739fd5f2baf4d2eb8e9dd65d73179242 const rest: Metadata | null = last.rest; if (rest === null) return null; -@@ -353,7 +353,7 @@ export namespace MiscCloneProgrammer { +@@ -405,7 +405,7 @@ export namespace MiscCloneProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -262,10 +300,10 @@ index 94d768b0a0738c0caccd711671351d1f22fa3848..739fd5f2baf4d2eb8e9dd65d73179242 ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/misc/MiscPruneProgrammer.ts b/src/programmers/misc/MiscPruneProgrammer.ts -index ed1465267066e382ae6696a25a806c2489597593..661f3cd93ae66070c978bd3e8d2b8db07189fe47 100644 +index 1051204a00041ddfb39da9de77b35ab8b44b75ee..73db30fdc06955f43dc2f563cbfc174e50a1bc6f 100644 --- a/src/programmers/misc/MiscPruneProgrammer.ts +++ b/src/programmers/misc/MiscPruneProgrammer.ts -@@ -310,7 +310,7 @@ export namespace MiscPruneProgrammer { +@@ -347,7 +347,7 @@ export namespace MiscPruneProgrammer { const rest = (() => { if (tuple.elements.length === 0) return null; @@ -274,7 +312,7 @@ index ed1465267066e382ae6696a25a806c2489597593..661f3cd93ae66070c978bd3e8d2b8db0 const rest: Metadata | null = last.rest; if (rest === null || filter(rest) === false) return null; -@@ -320,7 +320,7 @@ export namespace MiscPruneProgrammer { +@@ -357,7 +357,7 @@ export namespace MiscPruneProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -284,10 +322,10 @@ index ed1465267066e382ae6696a25a806c2489597593..661f3cd93ae66070c978bd3e8d2b8db0 ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/notations/NotationGeneralProgrammer.ts b/src/programmers/notations/NotationGeneralProgrammer.ts -index bd49b1e34002b1a1ec4f5444a8f91fa0ab794360..71d676de290986045910602ab10c6ef09a19c07d 100644 +index d8b2e22a8f9f3bfcb8f3e7987edaa7bf19a48720..96632214cb02b1534dc1987a0f892a3bf41e892f 100644 --- a/src/programmers/notations/NotationGeneralProgrammer.ts +++ b/src/programmers/notations/NotationGeneralProgrammer.ts -@@ -353,7 +353,7 @@ export namespace NotationGeneralProgrammer { +@@ -411,7 +411,7 @@ export namespace NotationGeneralProgrammer { const rest = (() => { if (tuple.elements.length === 0) return null; @@ -296,7 +334,7 @@ index bd49b1e34002b1a1ec4f5444a8f91fa0ab794360..71d676de290986045910602ab10c6ef0 const rest: Metadata | null = last.rest; if (rest === null) return null; -@@ -363,7 +363,7 @@ export namespace NotationGeneralProgrammer { +@@ -421,7 +421,7 @@ export namespace NotationGeneralProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -306,15 +344,15 @@ index bd49b1e34002b1a1ec4f5444a8f91fa0ab794360..71d676de290986045910602ab10c6ef0 ...explore, start: tuple.elements.length - 1, diff --git a/src/transformers/CallExpressionTransformer.ts b/src/transformers/CallExpressionTransformer.ts -index c58a1b143ce4f204bb249a4858c9d16a26f97408..9e9ffcf73e4c01aa6ac8c213669fdcd50e0181b9 100644 +index 99a4604f1a1944336b4d93dc61390269c346c243..c31ba72f1d206c441d6c237314a1c4d5c808dd09 100644 --- a/src/transformers/CallExpressionTransformer.ts +++ b/src/transformers/CallExpressionTransformer.ts -@@ -111,7 +111,7 @@ export namespace CallExpressionTransformer { - // TRANSFORMATION - //---- - // FUNCTION NAME -- const module: string = location.split(path.sep).at(-1)!.split(".")[0]!; -+ const module: string = location.split(path.sep).slice(-1)[0]!.split(".")[0]!; - const { name } = project.checker.getTypeAtLocation(declaration).symbol; - - // FIND TRANSFORMER +@@ -131,7 +131,7 @@ export namespace CallExpressionTransformer { + // TRANSFORMATION + //---- + // FUNCTION NAME +- const module: string = location.split(path.sep).at(-1)!.split(".")[0]!; ++ const module: string = location.split(path.sep).slice(-1)[0]!.split(".")[0]!; + const { name } = project.checker.getTypeAtLocation(declaration).symbol; + + // FIND TRANSFORMER diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index f466c34da838..a3c6f38176ac 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,334 @@ # @rocket.chat/meteor +## 6.12.0-rc.4 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/license@0.2.6-rc.4 + - @rocket.chat/omnichannel-services@0.3.3-rc.4 + - @rocket.chat/pdf-worker@0.2.3-rc.4 + - @rocket.chat/presence@0.2.6-rc.4 + - @rocket.chat/api-client@0.2.6-rc.4 + - @rocket.chat/apps@0.1.6-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/cron@0.1.6-rc.4 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.4 + - @rocket.chat/gazzodown@10.0.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/ui-contexts@10.0.0-rc.4 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.3-rc.4 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.4 + - @rocket.chat/ui-client@10.0.0-rc.4 + - @rocket.chat/ui-video-conf@10.0.0-rc.4 + - @rocket.chat/web-ui-registration@10.0.0-rc.4 + - @rocket.chat/instance-status@0.1.6-rc.4 +
+ +## 6.11.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +## 6.12.0-rc.3 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#33159](https://github.com/RocketChat/Rocket.Chat/pull/33159)) Improves Omnichannel queue page performance + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/license@0.2.5-rc.3 + - @rocket.chat/omnichannel-services@0.3.2-rc.3 + - @rocket.chat/pdf-worker@0.2.2-rc.3 + - @rocket.chat/presence@0.2.5-rc.3 + - @rocket.chat/api-client@0.2.5-rc.3 + - @rocket.chat/apps@0.1.5-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/cron@0.1.5-rc.3 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.3 + - @rocket.chat/gazzodown@10.0.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/ui-contexts@10.0.0-rc.3 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2-rc.3 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.3 + - @rocket.chat/ui-client@10.0.0-rc.3 + - @rocket.chat/ui-video-conf@10.0.0-rc.3 + - @rocket.chat/web-ui-registration@10.0.0-rc.3 + - @rocket.chat/instance-status@0.1.5-rc.3 +
+ +## 6.12.0-rc.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#33169](https://github.com/RocketChat/Rocket.Chat/pull/33169)) Fixed issue that prevented sending encrypted filed from the mobile app + +- ([#33174](https://github.com/RocketChat/Rocket.Chat/pull/33174)) Restored tooltips to the unit edit department field selected options + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/license@0.2.5-rc.2 + - @rocket.chat/omnichannel-services@0.3.2-rc.2 + - @rocket.chat/pdf-worker@0.2.2-rc.2 + - @rocket.chat/presence@0.2.5-rc.2 + - @rocket.chat/api-client@0.2.5-rc.2 + - @rocket.chat/apps@0.1.5-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/cron@0.1.5-rc.2 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.2 + - @rocket.chat/gazzodown@10.0.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/ui-contexts@10.0.0-rc.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2-rc.2 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.2 + - @rocket.chat/ui-client@10.0.0-rc.2 + - @rocket.chat/ui-video-conf@10.0.0-rc.2 + - @rocket.chat/web-ui-registration@10.0.0-rc.2 + - @rocket.chat/instance-status@0.1.5-rc.2 +
+ +## 6.12.0-rc.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#33136](https://github.com/RocketChat/Rocket.Chat/pull/33136)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/license@0.2.5-rc.1 + - @rocket.chat/omnichannel-services@0.3.2-rc.1 + - @rocket.chat/pdf-worker@0.2.2-rc.1 + - @rocket.chat/presence@0.2.5-rc.1 + - @rocket.chat/api-client@0.2.5-rc.1 + - @rocket.chat/apps@0.1.5-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/cron@0.1.5-rc.1 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.1 + - @rocket.chat/gazzodown@10.0.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/ui-contexts@10.0.0-rc.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2-rc.1 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.1 + - @rocket.chat/ui-client@10.0.0-rc.1 + - @rocket.chat/ui-video-conf@10.0.0-rc.1 + - @rocket.chat/web-ui-registration@10.0.0-rc.1 + - @rocket.chat/instance-status@0.1.5-rc.1 +
+ +## 6.12.0-rc.0 + +### Minor Changes + +- ([#32535](https://github.com/RocketChat/Rocket.Chat/pull/32535)) Federation actions like sending message in a federated DM, reacting in a federated chat, etc, will no longer work if the configuration is invalid. + +- ([#32916](https://github.com/RocketChat/Rocket.Chat/pull/32916)) Added a new Audit endpoint `audit/rooms.members` that allows users with `view-members-list-all-rooms` to fetch a list of the members of any room even if the user is not part of it. + +- ([#32032](https://github.com/RocketChat/Rocket.Chat/pull/32032)) Added a new 'Deactivated' tab to the users page, this tab lists users who have logged in for the first time but have been deactivated for any reason. Also added the UI code for the Active tab; + +- ([#33044](https://github.com/RocketChat/Rocket.Chat/pull/33044)) Replaces an outdated banner with the Bubble component in order to display retention policy warning + +- ([#32867](https://github.com/RocketChat/Rocket.Chat/pull/32867)) Added an accordion for advanced settings on Create teams and channels + +- ([#32709](https://github.com/RocketChat/Rocket.Chat/pull/32709) by [@heet434](https://github.com/heet434)) Add "Created at" column to admin rooms table + +- ([#32535](https://github.com/RocketChat/Rocket.Chat/pull/32535)) New button added to validate Matrix Federation configuration. A new field inside admin settings will reflect the configuration status being either 'Valid' or 'Invalid'. + +- ([#32969](https://github.com/RocketChat/Rocket.Chat/pull/32969)) Upgrades fuselage-toastbar version in order to add pause on hover functionality + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Added a new setting to enable/disable file encryption in an end to end encrypted room. + +- ([#32868](https://github.com/RocketChat/Rocket.Chat/pull/32868)) Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Fixed a bug related to uploading end to end encrypted file. + + E2EE files and uploads are uploaded as files of mime type `application/octet-stream` as we can't reveal the mime type of actual content since it is encrypted and has to be kept confidential. + + The server resolves the mime type of encrypted file as `application/octet-stream` but it wasn't playing nicely with existing settings related to whitelisted and blacklisted media types. + + E2EE files upload was getting blocked if `application/octet-stream` is not a whitelisted media type. + + Now this PR solves this issue by always accepting E2EE uploads even if `application/octet-stream` is not whitelisted but it will block the upload if `application/octet-stream` is black listed. + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +- ([#32986](https://github.com/RocketChat/Rocket.Chat/pull/32986)) Fixed login with third-party apps not working without the "Manage OAuth Apps" permission + +- ([#32852](https://github.com/RocketChat/Rocket.Chat/pull/32852)) Federated users can no longer be deleted. + +- ([#33033](https://github.com/RocketChat/Rocket.Chat/pull/33033)) Fixed an issue due to an endpoint pagination that was causing that when an agent have assigned more than 50 departments, the departments have a blank space instead of the name. + +- ([#33058](https://github.com/RocketChat/Rocket.Chat/pull/33058)) Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. + +- ([#24889](https://github.com/RocketChat/Rocket.Chat/pull/24889) by [@Shivansh2287](https://github.com/Shivansh2287)) Fixes an issue where the Announcement modal with long words was adding a horizontal scrollbar + +- ([#32940](https://github.com/RocketChat/Rocket.Chat/pull/32940)) Stopped non channel members from dragging and dropping files in a channel they do not belong + +- ([#33001](https://github.com/RocketChat/Rocket.Chat/pull/33001)) Allow apps to react/unreact to messages via bridge + +- ([#32809](https://github.com/RocketChat/Rocket.Chat/pull/32809)) Deactivating users who federated will now be permanent. + +- ([#31525](https://github.com/RocketChat/Rocket.Chat/pull/31525)) Fix: Show correct user info actions for non-members in channels. + +- ([#32931](https://github.com/RocketChat/Rocket.Chat/pull/32931)) Fixed an issue that caused UI to show an error when the call to get the Business Hour type from settings returned `undefined`. + +- ([#32743](https://github.com/RocketChat/Rocket.Chat/pull/32743)) Fixes an issue where creating a new user with an invalid username (containing special characters) resulted in an error message, but the user was still created. The user creation process now properly aborts when an invalid username is provided. + +- ([#33109](https://github.com/RocketChat/Rocket.Chat/pull/33109)) Fixes the `expanded` prop being accidentally forwarded to `ContextualbarHeader` + +- ([#32846](https://github.com/RocketChat/Rocket.Chat/pull/32846)) Fixed issue with system messages being counted as agents' first responses in livechat rooms (which caused the "best first response time" and "average first response time" metrics to be unreliable for all agents) + +- ([#32791](https://github.com/RocketChat/Rocket.Chat/pull/32791)) Fixed a behavior when updating messages that prevented the `customFields` prop from being updated if there were no changes to the `msg` property. Now, `customFields` will be always updated on message update even if `msg` doesn't change + +- ([#33101](https://github.com/RocketChat/Rocket.Chat/pull/33101)) Fixed an issue where teams were being created with no room associated with it. + +- ([#33036](https://github.com/RocketChat/Rocket.Chat/pull/33036)) Fixes multiple problems with the `processRoomAbandonment` hook. This hook is in charge of calculating the time a room has been abandoned (this means, the time that elapsed since a room was last answered by an agent until it was closed). However, when business hours were enabled and the user didn't open on one day, if an abandoned room happened to be abandoned _over_ the day there was no business hour configuration, then the process will error out. + Additionally, the values the code was calculating were not right. When business hours are enabled, this code should only count the abandonment time _while a business hour was open_. When rooms were left abandoned for days or weeks, this will also throw an error or output an invalid count. +- ([#33054](https://github.com/RocketChat/Rocket.Chat/pull/33054)) Fixed issue with livechat analytics in a given date range considering conversation data from the following day + +- ([#32981](https://github.com/RocketChat/Rocket.Chat/pull/32981)) fixed an issue with the "follow message" button not changing state after click + +- ([#32928](https://github.com/RocketChat/Rocket.Chat/pull/32928)) Fixed issue where `after-registration-triggers` would show up in a page when the user was not yet registered + +- ([#33047](https://github.com/RocketChat/Rocket.Chat/pull/33047)) Fixed: Custom fields in extraData now correctly added to extraRoomInfo by livechat.beforeRoom callback during livechat room creation. + +- ([#33040](https://github.com/RocketChat/Rocket.Chat/pull/33040)) Fixed an issue related to setting Accounts_ForgetUserSessionOnWindowClose, this setting was not working as expected. + + The new meteor 2.16 release introduced a new option to configure the Accounts package and choose between the local storage or session storage. They also changed how Meteor.\_localstorage works internally. Due to these changes in Meteor, our setting to use session storage wasn't working as expected. This PR fixes this issue and configures the Accounts package according to the workspace settings. + +-
Updated dependencies [8ea6517c4e, c11f3722df, 7f88158036, 127866ce97, 0c919db7b4, b764c415dc, 1f061a1aa5, dd37ea1b35, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.0 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-video-conf@10.0.0-rc.0 + - @rocket.chat/ui-composer@0.2.1-rc.0 + - @rocket.chat/gazzodown@10.0.0-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.0 + - @rocket.chat/ui-client@10.0.0-rc.0 + - @rocket.chat/ui-kit@0.36.1-rc.0 + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/i18n@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/web-ui-registration@10.0.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.1-rc.0 + - @rocket.chat/apps@0.1.4-rc.0 + - @rocket.chat/models@0.2.1-rc.0 + - @rocket.chat/ui-contexts@10.0.0-rc.0 + - @rocket.chat/presence@0.2.4-rc.0 + - @rocket.chat/api-client@0.2.4-rc.0 + - @rocket.chat/license@0.2.4-rc.0 + - @rocket.chat/pdf-worker@0.2.1-rc.0 + - @rocket.chat/cron@0.1.4-rc.0 + - @rocket.chat/instance-status@0.1.4-rc.0 + - @rocket.chat/server-cloud-communication@0.0.2 +
+ +- Bump @rocket.chat/meteor version. + +- ([#33084](https://github.com/RocketChat/Rocket.Chat/pull/33084) by [@dionisio-bot](https://github.com/dionisio-bot)) Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. + +- ([#33153](https://github.com/RocketChat/Rocket.Chat/pull/33153) by [@dionisio-bot](https://github.com/dionisio-bot)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +- ([#33185](https://github.com/RocketChat/Rocket.Chat/pull/33185) by [@dionisio-bot](https://github.com/dionisio-bot)) Restored tooltips to the unit edit department field selected options + +- ([#33129](https://github.com/RocketChat/Rocket.Chat/pull/33129) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixed an issue related to setting Accounts_ForgetUserSessionOnWindowClose, this setting was not working as expected. + + The new meteor 2.16 release introduced a new option to configure the Accounts package and choose between the local storage or session storage. They also changed how Meteor.\_localstorage works internally. Due to these changes in Meteor, our setting to use session storage wasn't working as expected. This PR fixes this issue and configures the Accounts package according to the workspace settings. + +- ([#33178](https://github.com/RocketChat/Rocket.Chat/pull/33178) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes an issue where multi-step modals were closing unexpectedly + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/api-client@0.2.5 + - @rocket.chat/license@0.2.5 + - @rocket.chat/omnichannel-services@0.3.2 + - @rocket.chat/pdf-worker@0.2.2 + - @rocket.chat/presence@0.2.5 + - @rocket.chat/apps@0.1.5 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/cron@0.1.5 + - @rocket.chat/fuselage-ui-kit@9.0.2 + - @rocket.chat/gazzodown@9.0.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@5.0.2 + - @rocket.chat/ui-client@9.0.2 + - @rocket.chat/ui-video-conf@9.0.2 + - @rocket.chat/web-ui-registration@9.0.2 + - @rocket.chat/instance-status@0.1.5 +
+ +## 6.11.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#33062](https://github.com/RocketChat/Rocket.Chat/pull/33062)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/api-client@0.2.4 + - @rocket.chat/license@0.2.4 + - @rocket.chat/omnichannel-services@0.3.1 + - @rocket.chat/pdf-worker@0.2.1 + - @rocket.chat/presence@0.2.4 + - @rocket.chat/apps@0.1.4 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/cron@0.1.4 + - @rocket.chat/fuselage-ui-kit@9.0.1 + - @rocket.chat/gazzodown@9.0.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.1 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@5.0.1 + - @rocket.chat/ui-client@9.0.1 + - @rocket.chat/ui-video-conf@9.0.1 + - @rocket.chat/web-ui-registration@9.0.1 + - @rocket.chat/instance-status@0.1.4 +
+ ## 6.11.0 ### Minor Changes diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index ad297a38656b..2b573160ebdb 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -8,6 +8,7 @@ import { isRoomsMuteUnmuteUserProps, isRoomsExportProps, isRoomsIsMemberProps, + isRoomsCleanHistoryProps, } from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; @@ -361,7 +362,7 @@ API.v1.addRoute( API.v1.addRoute( 'rooms.cleanHistory', - { authRequired: true }, + { authRequired: true, validateParams: isRoomsCleanHistoryProps }, { async post() { const { _id } = await findRoomByIdOrName({ params: this.bodyParams }); diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts index 9c56ecac01cb..530e3dc0770c 100644 --- a/apps/meteor/app/api/server/v1/users.ts +++ b/apps/meteor/app/api/server/v1/users.ts @@ -755,6 +755,12 @@ API.v1.addRoute( { authRequired: false }, { async post() { + const isPasswordResetEnabled = settings.get('Accounts_PasswordReset'); + + if (!isPasswordResetEnabled) { + return API.v1.failure('Password reset is not enabled'); + } + const { email } = this.bodyParams; if (!email) { return API.v1.failure("The 'email' param is required"); diff --git a/apps/meteor/app/apps/server/bridges/bridges.js b/apps/meteor/app/apps/server/bridges/bridges.js index 6d52a1d8e56d..aeab9f191039 100644 --- a/apps/meteor/app/apps/server/bridges/bridges.js +++ b/apps/meteor/app/apps/server/bridges/bridges.js @@ -5,6 +5,7 @@ import { AppApisBridge } from './api'; import { AppCloudBridge } from './cloud'; import { AppCommandsBridge } from './commands'; import { AppDetailChangesBridge } from './details'; +import { AppEmailBridge } from './email'; import { AppEnvironmentalVariableBridge } from './environmental'; import { AppHttpBridge } from './http'; import { AppInternalBridge } from './internal'; @@ -53,6 +54,7 @@ export class RealAppBridges extends AppBridges { this._moderationBridge = new AppModerationBridge(orch); this._threadBridge = new AppThreadBridge(orch); this._roleBridge = new AppRoleBridge(orch); + this._emailBridge = new AppEmailBridge(orch); } getCommandBridge() { @@ -150,4 +152,8 @@ export class RealAppBridges extends AppBridges { getRoleBridge() { return this._roleBridge; } + + getEmailBridge() { + return this._emailBridge; + } } diff --git a/apps/meteor/app/apps/server/bridges/email.ts b/apps/meteor/app/apps/server/bridges/email.ts new file mode 100644 index 000000000000..4c9cb9a93ed6 --- /dev/null +++ b/apps/meteor/app/apps/server/bridges/email.ts @@ -0,0 +1,16 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; +import type { IEmail } from '@rocket.chat/apps-engine/definition/email'; +import { EmailBridge } from '@rocket.chat/apps-engine/server/bridges'; + +import * as Mailer from '../../../mailer/server/api'; + +export class AppEmailBridge extends EmailBridge { + constructor(private readonly orch: IAppServerOrchestrator) { + super(); + } + + protected async sendEmail(email: IEmail, appId: string): Promise { + this.orch.debugLog(`The app ${appId} is sending an email.`); + await Mailer.send(email); + } +} diff --git a/apps/meteor/app/authorization/server/constant/permissions.ts b/apps/meteor/app/authorization/server/constant/permissions.ts index d9ae4133e49e..e5e8f7fb05dd 100644 --- a/apps/meteor/app/authorization/server/constant/permissions.ts +++ b/apps/meteor/app/authorization/server/constant/permissions.ts @@ -97,6 +97,10 @@ export const permissions = [ _id: 'create-livechat-contact', roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'], }, + { + _id: 'update-livechat-contact', + roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'], + }, { _id: 'view-livechat-manager', roles: ['livechat-manager', 'livechat-monitor', 'admin'] }, { _id: 'view-omnichannel-contact-center', diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.ts b/apps/meteor/app/file-upload/server/lib/FileUpload.ts index 8714c71f20d6..ac97923be41e 100644 --- a/apps/meteor/app/file-upload/server/lib/FileUpload.ts +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.ts @@ -175,7 +175,12 @@ export const FileUpload = { throw new Meteor.Error('error-invalid-file-type', reason); } - // E2EE files are of type - application/octet-stream, application/octet-stream is whitelisted for E2EE files. + // E2EE files should be of type application/octet-stream. no information about them should be disclosed on upload if they are encrypted + if (isE2EEUpload(file)) { + file.type = 'application/octet-stream'; + } + + // E2EE files are of type application/octet-stream, which is whitelisted for E2EE files if (!fileUploadIsValidContentType(file?.type, isE2EEUpload(file) ? 'application/octet-stream' : undefined)) { const reason = i18n.t('File_type_is_not_accepted', { lng: language }); throw new Meteor.Error('error-invalid-file-type', reason); diff --git a/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts b/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts new file mode 100644 index 000000000000..e62727814de3 --- /dev/null +++ b/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts @@ -0,0 +1,20 @@ +export const getModifiedHttpHeaders = (httpHeaders: Record) => { + const modifiedHttpHeaders = { ...httpHeaders }; + + if ('x-auth-token' in modifiedHttpHeaders) { + modifiedHttpHeaders['x-auth-token'] = '[redacted]'; + } + + if (modifiedHttpHeaders.cookie) { + const cookies = modifiedHttpHeaders.cookie.split('; '); + const modifiedCookies = cookies.map((cookie: string) => { + if (cookie.startsWith('rc_token=')) { + return 'rc_token=[redacted]'; + } + return cookie; + }); + modifiedHttpHeaders.cookie = modifiedCookies.join('; '); + } + + return modifiedHttpHeaders; +}; diff --git a/apps/meteor/app/lib/server/lib/debug.js b/apps/meteor/app/lib/server/lib/debug.js index aaa492e80337..cbf38528579f 100644 --- a/apps/meteor/app/lib/server/lib/debug.js +++ b/apps/meteor/app/lib/server/lib/debug.js @@ -7,6 +7,7 @@ import _ from 'underscore'; import { getMethodArgs } from '../../../../server/lib/logger/logPayloads'; import { metrics } from '../../../metrics/server'; import { settings } from '../../../settings/server'; +import { getModifiedHttpHeaders } from '../functions/getModifiedHttpHeaders'; const logger = new Logger('Meteor'); @@ -41,7 +42,7 @@ const traceConnection = (enable, filter, prefix, name, connection, userId) => { console.log(name, { id: connection.id, clientAddress: connection.clientAddress, - httpHeaders: connection.httpHeaders, + httpHeaders: getModifiedHttpHeaders(connection.httpHeaders), userId, }); } else { diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts index 7551cabb6e63..fdb99c83207c 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts @@ -111,7 +111,7 @@ async function updateUsersSubscriptions(message: IMessage, room: IRoom): Promise roomId: room._id, uidsExclude: [message.u._id], uidsInclude: userIds, - onlyRead: !toAll && !toHere, + onlyRead: !toAll && !toHere && unreadCount !== 'all_messages', }).forEach((sub) => { const hasUserMention = userIds.includes(sub.u._id); const shouldIncUnread = hasUserMention || toAll || toHere || unreadCount === 'all_messages'; @@ -168,8 +168,6 @@ export async function updateThreadUsersSubscriptions(message: IMessage, replies: } export async function notifyUsersOnMessage(message: IMessage, room: IRoom, roomUpdater: Updater): Promise { - console.log('notifyUsersOnMessage function'); - // Skips this callback if the message was edited and increments it if the edit was way in the past (aka imported) if (isEditedMessage(message)) { if (Math.abs(moment(message.editedAt).diff(Date.now())) > 60000) { diff --git a/apps/meteor/app/livechat/imports/server/rest/sms.ts b/apps/meteor/app/livechat/imports/server/rest/sms.ts index 6f8ce64bc635..6b2411cf8e3d 100644 --- a/apps/meteor/app/livechat/imports/server/rest/sms.ts +++ b/apps/meteor/app/livechat/imports/server/rest/sms.ts @@ -97,12 +97,18 @@ const normalizeLocationSharing = (payload: ServiceData) => { // @ts-expect-error - this is an special endpoint that requires the return to not be wrapped as regular returns API.v1.addRoute('livechat/sms-incoming/:service', { async post() { - if (!(await OmnichannelIntegration.isConfiguredSmsService(this.urlParams.service))) { + const { service } = this.urlParams; + if (!(await OmnichannelIntegration.isConfiguredSmsService(service))) { return API.v1.failure('Invalid service'); } const smsDepartment = settings.get('SMS_Default_Omnichannel_Department'); - const SMSService = await OmnichannelIntegration.getSmsService(this.urlParams.service); + const SMSService = await OmnichannelIntegration.getSmsService(service); + + if (!SMSService.validateRequest(this.request)) { + return API.v1.failure('Invalid request'); + } + const sms = SMSService.parse(this.bodyParams); const { department } = this.queryParams; let targetDepartment = await defineDepartment(department || smsDepartment); @@ -121,7 +127,7 @@ API.v1.addRoute('livechat/sms-incoming/:service', { }, source: { type: OmnichannelSourceType.SMS, - alias: this.urlParams.service, + alias: service, }, }; diff --git a/apps/meteor/app/livechat/server/api/v1/contact.ts b/apps/meteor/app/livechat/server/api/v1/contact.ts index 91b18a6b21af..94bd5ed3e11c 100644 --- a/apps/meteor/app/livechat/server/api/v1/contact.ts +++ b/apps/meteor/app/livechat/server/api/v1/contact.ts @@ -1,11 +1,11 @@ import { LivechatCustomField, LivechatVisitors } from '@rocket.chat/models'; -import { isPOSTOmnichannelContactsProps } from '@rocket.chat/rest-typings'; +import { isPOSTOmnichannelContactsProps, isPOSTUpdateOmnichannelContactsProps } from '@rocket.chat/rest-typings'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import { API } from '../../../../api/server'; -import { Contacts, createContact } from '../../lib/Contacts'; +import { Contacts, createContact, updateContact } from '../../lib/Contacts'; API.v1.addRoute( 'omnichannel/contact', @@ -101,3 +101,18 @@ API.v1.addRoute( }, }, ); +API.v1.addRoute( + 'omnichannel/contacts.update', + { authRequired: true, permissionsRequired: ['update-livechat-contact'], validateParams: isPOSTUpdateOmnichannelContactsProps }, + { + async post() { + if (!process.env.TEST_MODE) { + throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); + } + + const contact = await updateContact({ ...this.bodyParams }); + + return API.v1.success({ contact }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts index b0f45a63ff87..565f8e0bb3f4 100644 --- a/apps/meteor/app/livechat/server/api/v1/room.ts +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -31,63 +31,72 @@ import { findVisitorInfo } from '../lib/visitors'; const isAgentWithInfo = (agentObj: ILivechatAgent | { hiddenInfo: boolean }): agentObj is ILivechatAgent => !('hiddenInfo' in agentObj); -API.v1.addRoute('livechat/room', { - async get() { - // I'll temporary use check for validation, as validateParams doesnt support what's being done here - const extraCheckParams = await onCheckRoomParams({ - token: String, - rid: Match.Maybe(String), - agentId: Match.Maybe(String), - }); - - check(this.queryParams, extraCheckParams as any); - - const { token, rid, agentId, ...extraParams } = this.queryParams; - - const guest = token && (await findGuest(token)); - if (!guest) { - throw new Error('invalid-token'); - } - - if (!rid) { - const room = await LivechatRooms.findOneOpenByVisitorToken(token, {}); - if (room) { - return API.v1.success({ room, newRoom: false }); - } - - let agent: SelectedAgent | undefined; - const agentObj = agentId && (await findAgent(agentId)); - if (agentObj) { - if (isAgentWithInfo(agentObj)) { - const { username = undefined } = agentObj; - agent = { agentId, username }; - } else { - agent = { agentId }; - } +API.v1.addRoute( + 'livechat/room', + { + rateLimiterOptions: { + numRequestsAllowed: 5, + intervalTimeInMS: 60000, + }, + }, + { + async get() { + // I'll temporary use check for validation, as validateParams doesnt support what's being done here + const extraCheckParams = await onCheckRoomParams({ + token: String, + rid: Match.Maybe(String), + agentId: Match.Maybe(String), + }); + + check(this.queryParams, extraCheckParams as any); + + const { token, rid, agentId, ...extraParams } = this.queryParams; + + const guest = token && (await findGuest(token)); + if (!guest) { + throw new Error('invalid-token'); } - const roomInfo = { - source: { - type: isWidget(this.request.headers) ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, - }, - }; + if (!rid) { + const room = await LivechatRooms.findOneOpenByVisitorToken(token, {}); + if (room) { + return API.v1.success({ room, newRoom: false }); + } - const newRoom = await LivechatTyped.createRoom({ visitor: guest, roomInfo, agent, extraData: extraParams }); + let agent: SelectedAgent | undefined; + const agentObj = agentId && (await findAgent(agentId)); + if (agentObj) { + if (isAgentWithInfo(agentObj)) { + const { username = undefined } = agentObj; + agent = { agentId, username }; + } else { + agent = { agentId }; + } + } - return API.v1.success({ - room: newRoom, - newRoom: true, - }); - } + const roomInfo = { + source: { + type: isWidget(this.request.headers) ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, + }, + }; + + const newRoom = await LivechatTyped.createRoom({ visitor: guest, roomInfo, agent, extraData: extraParams }); - const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}); - if (!froom) { - throw new Error('invalid-room'); - } + return API.v1.success({ + room: newRoom, + newRoom: true, + }); + } + + const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}); + if (!froom) { + throw new Error('invalid-room'); + } - return API.v1.success({ room: froom, newRoom: false }); + return API.v1.success({ room: froom, newRoom: false }); + }, }, -}); +); // Note: use this route if a visitor is closing a room // If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route diff --git a/apps/meteor/app/livechat/server/api/v1/visitor.ts b/apps/meteor/app/livechat/server/api/v1/visitor.ts index a5b3f2de35b1..ed32f0e2d279 100644 --- a/apps/meteor/app/livechat/server/api/v1/visitor.ts +++ b/apps/meteor/app/livechat/server/api/v1/visitor.ts @@ -9,119 +9,128 @@ import { settings } from '../../../../settings/server'; import { Livechat as LivechatTyped } from '../../lib/LivechatTyped'; import { findGuest, normalizeHttpHeaderData } from '../lib/livechat'; -API.v1.addRoute('livechat/visitor', { - async post() { - check(this.bodyParams, { - visitor: Match.ObjectIncluding({ - token: String, - name: Match.Maybe(String), - email: Match.Maybe(String), - department: Match.Maybe(String), - phone: Match.Maybe(String), - username: Match.Maybe(String), - customFields: Match.Maybe([ - Match.ObjectIncluding({ - key: String, - value: String, - overwrite: Boolean, - }), - ]), - }), - }); - - const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor; - - if (!token?.trim()) { - throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' }); - } - - const guest = { - token, - ...(id && { id }), - ...(name && { name }), - ...(email && { email }), - ...(department && { department }), - ...(username && { username }), - ...(connectionData && { connectionData }), - ...(phone && typeof phone === 'string' && { phone: { number: phone as string } }), - connectionData: normalizeHttpHeaderData(this.request.headers), - }; - - const visitor = await LivechatTyped.registerGuest(guest); - if (!visitor) { - throw new Meteor.Error('error-livechat-visitor-registration', 'Error registering visitor', { - method: 'livechat/visitor', +API.v1.addRoute( + 'livechat/visitor', + { + rateLimiterOptions: { + numRequestsAllowed: 5, + intervalTimeInMS: 60000, + }, + }, + { + async post() { + check(this.bodyParams, { + visitor: Match.ObjectIncluding({ + token: String, + name: Match.Maybe(String), + email: Match.Maybe(String), + department: Match.Maybe(String), + phone: Match.Maybe(String), + username: Match.Maybe(String), + customFields: Match.Maybe([ + Match.ObjectIncluding({ + key: String, + value: String, + overwrite: Boolean, + }), + ]), + }), }); - } - const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}); - // If it's updating an existing visitor, it must also update the roomInfo - const rooms = await LivechatRooms.findOpenByVisitorToken(visitor?.token, {}, extraQuery).toArray(); - await Promise.all( - rooms.map( - (room: IRoom) => - visitor && - LivechatTyped.saveRoomInfo(room, { - _id: visitor._id, - name: visitor.name, - phone: visitor.phone?.[0]?.phoneNumber, - livechatData: visitor.livechatData as { [k: string]: string }, - }), - ), - ); - - if (customFields && Array.isArray(customFields) && customFields.length > 0) { - const keys = customFields.map((field) => field.key); - const errors: string[] = []; - - const processedKeys = await Promise.all( - await LivechatCustomField.findByIdsAndScope>(keys, 'visitor', { - projection: { _id: 1 }, - }) - .map(async (field) => { - const customField = customFields.find((f) => f.key === field._id); - if (!customField) { - return; - } - - const { key, value, overwrite } = customField; - // TODO: Change this to Bulk update - if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) { - errors.push(key); - } - - return key; - }) - .toArray(), - ); + const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor; - if (processedKeys.length !== keys.length) { - LivechatTyped.logger.warn({ - msg: 'Some custom fields were not processed', - visitorId: visitor._id, - missingKeys: keys.filter((key) => !processedKeys.includes(key)), - }); + if (!token?.trim()) { + throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' }); } - if (errors.length > 0) { - LivechatTyped.logger.error({ - msg: 'Error updating custom fields', - visitorId: visitor._id, - errors, + const guest = { + token, + ...(id && { id }), + ...(name && { name }), + ...(email && { email }), + ...(department && { department }), + ...(username && { username }), + ...(connectionData && { connectionData }), + ...(phone && typeof phone === 'string' && { phone: { number: phone as string } }), + connectionData: normalizeHttpHeaderData(this.request.headers), + }; + + const visitor = await LivechatTyped.registerGuest(guest); + if (!visitor) { + throw new Meteor.Error('error-livechat-visitor-registration', 'Error registering visitor', { + method: 'livechat/visitor', }); - throw new Error('error-updating-custom-fields'); } - return API.v1.success({ visitor: await VisitorsRaw.findOneEnabledById(visitor._id) }); - } + const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}); + // If it's updating an existing visitor, it must also update the roomInfo + const rooms = await LivechatRooms.findOpenByVisitorToken(visitor?.token, {}, extraQuery).toArray(); + await Promise.all( + rooms.map( + (room: IRoom) => + visitor && + LivechatTyped.saveRoomInfo(room, { + _id: visitor._id, + name: visitor.name, + phone: visitor.phone?.[0]?.phoneNumber, + livechatData: visitor.livechatData as { [k: string]: string }, + }), + ), + ); - if (!visitor) { - throw new Meteor.Error('error-saving-visitor', 'An error ocurred while saving visitor'); - } + if (customFields && Array.isArray(customFields) && customFields.length > 0) { + const keys = customFields.map((field) => field.key); + const errors: string[] = []; - return API.v1.success({ visitor }); + const processedKeys = await Promise.all( + await LivechatCustomField.findByIdsAndScope>(keys, 'visitor', { + projection: { _id: 1 }, + }) + .map(async (field) => { + const customField = customFields.find((f) => f.key === field._id); + if (!customField) { + return; + } + + const { key, value, overwrite } = customField; + // TODO: Change this to Bulk update + if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) { + errors.push(key); + } + + return key; + }) + .toArray(), + ); + + if (processedKeys.length !== keys.length) { + LivechatTyped.logger.warn({ + msg: 'Some custom fields were not processed', + visitorId: visitor._id, + missingKeys: keys.filter((key) => !processedKeys.includes(key)), + }); + } + + if (errors.length > 0) { + LivechatTyped.logger.error({ + msg: 'Error updating custom fields', + visitorId: visitor._id, + errors, + }); + throw new Error('error-updating-custom-fields'); + } + + return API.v1.success({ visitor: await VisitorsRaw.findOneEnabledById(visitor._id) }); + } + + if (!visitor) { + throw new Meteor.Error('error-saving-visitor', 'An error ocurred while saving visitor'); + } + + return API.v1.success({ visitor }); + }, }, -}); +); API.v1.addRoute('livechat/visitor/:token', { async get() { diff --git a/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts b/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts index a6031bd42efa..2c718c058b00 100644 --- a/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts +++ b/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts @@ -58,14 +58,17 @@ export const getSecondsSinceLastAgentResponse = async (room: IOmnichannelRoom, a for (let index = 0; index <= daysOfInactivity; index++) { const today = inactivityDay.clone().format('dddd'); const officeDay = officeDays[today]; + if (!officeDay) { inactivityDay.add(1, 'days'); continue; } + if (!officeDay.open) { inactivityDay.add(1, 'days'); continue; } + if (!officeDay?.start?.time || !officeDay?.finish?.time) { inactivityDay.add(1, 'days'); continue; diff --git a/apps/meteor/app/livechat/server/lib/Contacts.ts b/apps/meteor/app/livechat/server/lib/Contacts.ts index 4f4a33ee61b2..58404ce27584 100644 --- a/apps/meteor/app/livechat/server/lib/Contacts.ts +++ b/apps/meteor/app/livechat/server/lib/Contacts.ts @@ -1,4 +1,11 @@ -import type { ILivechatContactChannel, ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom, IUser } from '@rocket.chat/core-typings'; +import type { + ILivechatContact, + ILivechatContactChannel, + ILivechatCustomField, + ILivechatVisitor, + IOmnichannelRoom, + IUser, +} from '@rocket.chat/core-typings'; import { LivechatVisitors, Users, @@ -45,6 +52,16 @@ type CreateContactParams = { channels?: ILivechatContactChannel[]; }; +type UpdateContactParams = { + contactId: string; + name?: string; + emails?: string[]; + phones?: string[]; + customFields?: Record; + contactManager?: string; + channels?: ILivechatContactChannel[]; +}; + export const Contacts = { async registerContact({ token, @@ -189,10 +206,7 @@ export async function createContact(params: CreateContactParams): Promise>(contactManager, { projection: { roles: 1 } }); - if (!contactManagerUser) { - throw new Error('error-contact-manager-not-found'); - } + await validateContactManager(contactManager); } const allowedCustomFields = await getAllowedCustomFields(); @@ -211,6 +225,29 @@ export async function createContact(params: CreateContactParams): Promise { + const { contactId, name, emails, phones, customFields, contactManager, channels } = params; + + const contact = await LivechatContacts.findOneById>(contactId, { projection: { _id: 1 } }); + + if (!contact) { + throw new Error('error-contact-not-found'); + } + + if (contactManager) { + await validateContactManager(contactManager); + } + + if (customFields) { + const allowedCustomFields = await getAllowedCustomFields(); + validateCustomFields(allowedCustomFields, customFields); + } + + const updatedContact = await LivechatContacts.updateContact(contactId, { name, emails, phones, contactManager, channels, customFields }); + + return updatedContact; +} + async function getAllowedCustomFields(): Promise { return LivechatCustomField.findByScope( 'visitor', @@ -245,4 +282,18 @@ export function validateCustomFields(allowedCustomFields: ILivechatCustomField[] } } } + + const allowedCustomFieldIds = new Set(allowedCustomFields.map((cf) => cf._id)); + for (const key in customFields) { + if (!allowedCustomFieldIds.has(key)) { + throw new Error(i18n.t('error-custom-field-not-allowed', { key })); + } + } +} + +export async function validateContactManager(contactManagerUserId: string) { + const contactManagerUser = await Users.findOneAgentById>(contactManagerUserId, { projection: { _id: 1 } }); + if (!contactManagerUser) { + throw new Error('error-contact-manager-not-found'); + } } diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index faf0e8f47de6..77fdbe3d6942 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-develop" + "version": "6.12.0-rc.4" } diff --git a/apps/meteor/client/components/GenericModal/GenericModal.tsx b/apps/meteor/client/components/GenericModal/GenericModal.tsx index d371e1ff4ef2..5d025e05827d 100644 --- a/apps/meteor/client/components/GenericModal/GenericModal.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModal.tsx @@ -111,7 +111,7 @@ const GenericModal = ({ {tagline && {tagline}} {title ?? t('Are_you_sure')} - + {onClose && } {children} diff --git a/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx b/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx index d56cbdd26a67..2dcdf3b3578c 100644 --- a/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx @@ -1,25 +1,13 @@ import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React from 'react'; import GenericModal from './GenericModal'; -const GenericModalSkeleton = ({ onClose, ...props }: ComponentProps) => { - const t = useTranslation(); - - return ( - } - confirmText={t('Cancel')} - onConfirm={onClose} - > - - - ); -}; +const GenericModalSkeleton = (props: ComponentProps) => ( + }> + + +); export default GenericModalSkeleton; diff --git a/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelAppSourceRoomIcon.tsx b/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelAppSourceRoomIcon.tsx index 60f3af65eb9d..6a841c30491b 100644 --- a/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelAppSourceRoomIcon.tsx +++ b/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelAppSourceRoomIcon.tsx @@ -1,53 +1,29 @@ -import { UserStatus, type IOmnichannelRoomFromAppSource } from '@rocket.chat/core-typings'; +import { type IOmnichannelSourceFromApp } from '@rocket.chat/core-typings'; import { Icon, Box } from '@rocket.chat/fuselage'; -import type { ComponentProps, ReactElement } from 'react'; +import type { ComponentProps } from 'react'; import React from 'react'; import { AsyncStatePhase } from '../../../lib/asyncState/AsyncStatePhase'; import { useOmnichannelRoomIcon } from './context/OmnichannelRoomIconContext'; -const colors = { - busy: 'status-font-on-danger', - away: 'status-font-on-warning', - online: 'status-font-on-success', - offline: 'annotation', - disabled: 'annotation', +type OmnichannelAppSourceRoomIconProps = { + source: IOmnichannelSourceFromApp; + color: ComponentProps['color']; + size: ComponentProps['size']; + placement: 'sidebar' | 'default'; }; -const convertBoxSizeToNumber = (boxSize: ComponentProps['size']): number => { - switch (boxSize) { - case 'x20': { - return 20; - } - case 'x24': { - return 24; - } - case 'x16': - default: { - return 16; - } - } -}; +export const OmnichannelAppSourceRoomIcon = ({ source, color, size, placement }: OmnichannelAppSourceRoomIconProps) => { + const icon = (placement === 'sidebar' && source.sidebarIcon) || source.defaultIcon; + const { phase, value } = useOmnichannelRoomIcon(source.id, icon || ''); -export const OmnichannelAppSourceRoomIcon = ({ - room, - size = 16, - placement = 'default', -}: { - room: IOmnichannelRoomFromAppSource; - size: ComponentProps['size']; - placement: 'sidebar' | 'default'; -}): ReactElement => { - const color = colors[room.v.status || UserStatus.OFFLINE]; - const icon = (placement === 'sidebar' && room.source.sidebarIcon) || room.source.defaultIcon; - const { phase, value } = useOmnichannelRoomIcon(room.source.id, icon || ''); - const fontSize = convertBoxSizeToNumber(size); if ([AsyncStatePhase.REJECTED, AsyncStatePhase.LOADING].includes(phase)) { return ; } + return ( - - - + { - const t = useTranslation(); const query = useMemo(() => ({ teamId }), [teamId]); const getTeamsListRooms = useEndpoint('GET', '/v1/teams.listRooms'); const { data, isLoading } = useQuery(['getTeamsListRooms', query], async () => getTeamsListRooms(query)); if (isLoading) { - return ( - } confirmText={t('Cancel')}> - - - ); + return ; } return ; }; diff --git a/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx b/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx index 9bab0acc3d86..58f98705d2bb 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx @@ -1,11 +1,10 @@ import type { ITeam } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; -import { useUserId, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts'; +import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import LeaveTeamModal from './LeaveTeamModal/LeaveTeamModal'; type LeaveTeamWithDataProps = { @@ -15,7 +14,6 @@ type LeaveTeamWithDataProps = { }; const LeaveTeamWithData = ({ teamId, onCancel, onConfirm }: LeaveTeamWithDataProps): ReactElement => { - const t = useTranslation(); const userId = useUserId(); if (!userId) { @@ -26,11 +24,7 @@ const LeaveTeamWithData = ({ teamId, onCancel, onConfirm }: LeaveTeamWithDataPro const { data, isLoading } = useQuery(['teams.listRoomsOfUser'], () => getRoomsOfUser({ teamId, userId })); if (isLoading) { - return ( - } confirmText={t('Cancel')}> - - - ); + return ; } return ; diff --git a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx index fc1b2905478e..f28f4c8b5742 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx @@ -109,12 +109,13 @@ const TeamsInfo = ({ flexGrow={0} key='menu' maxHeight='initial' + title={t('More')} secondary renderItem={({ label: { label, icon }, ...props }): ReactElement =>