diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index db905f2f947a..b7ce1a785259 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,11 +1,46 @@
-
+
+
-
-Closes #ISSUE_NUMBER
+## Proposed changes
+
-
+## Issue(s)
+
+
+## How to test or reproduce
+
+
+## Screenshots
+
+## Types of changes
+
+
+
+- [ ] Bugfix (non-breaking change which fixes an issue)
+- [ ] Improvement (non-breaking change which improves a current function)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
+- [ ] Hotfix (a major bugfix that has to be merged asap)
+- [ ] Documentation Update (if none of the other choices apply)
+
+## Checklist
+
+
+- [ ] I have read the [CONTRIBUTING](https://github.com/RocketChat/Rocket.Chat/blob/develop/.github/CONTRIBUTING.md#contributing-to-rocketchat) doc
+- [ ] I have signed the [CLA](https://cla-assistant.io/RocketChat/Rocket.Chat)
+- [ ] Lint and unit tests pass locally with my changes
+- [ ] I have added tests that prove my fix is effective or that my feature works (if applicable)
+- [ ] I have added necessary documentation (if applicable)
+- [ ] Any dependent changes have been merged and published in downstream modules
+
+## Changelog
+
+
+
+
+## Further comments
+
-
diff --git a/.scripts/houstonMetadata.js b/.houston/metadata.js
similarity index 100%
rename from .scripts/houstonMetadata.js
rename to .houston/metadata.js
diff --git a/.houston/templates/prs.hbs b/.houston/templates/prs.hbs
new file mode 100644
index 000000000000..34a9666df2ba
--- /dev/null
+++ b/.houston/templates/prs.hbs
@@ -0,0 +1,2 @@
+{{> versions}}
+{{> _prs}}
diff --git a/.houston/templates/versions.hbs b/.houston/templates/versions.hbs
new file mode 100644
index 000000000000..8ee2a4f98551
--- /dev/null
+++ b/.houston/templates/versions.hbs
@@ -0,0 +1,13 @@
+{{#if (or release.node_version release.npm_version release.mongo_versions)}}
+
+### Engine versions
+{{#if release.node_version}}
+- Node: `{{ release.node_version }}`
+{{/if}}
+{{#if release.npm_version}}
+- NPM: `{{ release.npm_version }}`
+{{/if}}
+{{#if release.mongo_versions}}
+- MongoDB: `{{ join release.mongo_versions ', ' }}`
+{{/if}}
+{{/if}}
diff --git a/app/apps/client/admin/helpers.js b/app/apps/client/admin/helpers.js
index f78b4c661599..a1b0b2cdf9c5 100644
--- a/app/apps/client/admin/helpers.js
+++ b/app/apps/client/admin/helpers.js
@@ -363,11 +363,12 @@ export const appStatusSpanProps = ({
export const formatPrice = (price) => `\$${ Number.parseFloat(price).toFixed(2) }`;
-export const formatPricingPlan = ({ strategy, price, tiers }) => {
+export const formatPricingPlan = ({ strategy, price, tiers = [] }) => {
const { perUnit = false } = (Array.isArray(tiers) && tiers.find((tier) => tier.price === price)) || {};
const pricingPlanTranslationString = [
'Apps_Marketplace_pricingPlan',
+ Array.isArray(tiers) && tiers.length > 0 && 'startingAt',
strategy,
perUnit && 'perUser',
].filter(Boolean).join('_');
diff --git a/app/apps/server/bridges/users.js b/app/apps/server/bridges/users.js
index 5aac0567bed6..cbcdab1795d8 100644
--- a/app/apps/server/bridges/users.js
+++ b/app/apps/server/bridges/users.js
@@ -1,10 +1,9 @@
import { Random } from 'meteor/random';
import { setUserAvatar, checkUsernameAvailability, deleteUser, _setStatusTextPromise } from '../../../lib/server/functions';
-import { Users } from '../../../models';
+import { Users } from '../../../models/server';
import { Users as UsersRaw } from '../../../models/server/raw';
-
export class AppUserBridge {
constructor(orch) {
this.orch = orch;
@@ -25,7 +24,7 @@ export class AppUserBridge {
async getAppUser(appId) {
this.orch.debugLog(`The App ${ appId } is getting its assigned user`);
- const user = Users.findOne({ appId });
+ const user = Users.findOneByAppId(appId);
return this.orch.getConverters().get('users').convertToApp(user);
}
diff --git a/app/cors/server/cors.js b/app/cors/server/cors.js
index c5853db94059..9c6d8eb31803 100644
--- a/app/cors/server/cors.js
+++ b/app/cors/server/cors.js
@@ -44,6 +44,7 @@ WebApp.rawConnectHandlers.use(Meteor.bindEnvironment(function(req, res, next) {
});
}));
+// Deprecated setting
let Support_Cordova_App = false;
settings.get('Support_Cordova_App', (key, value) => {
Support_Cordova_App = value;
@@ -53,24 +54,24 @@ WebApp.rawConnectHandlers.use(function(req, res, next) {
// XSS Protection for old browsers (IE)
res.setHeader('X-XSS-Protection', '1');
- if (Support_Cordova_App !== true) {
- return next();
- }
-
- if (/^\/(api|_timesync|sockjs|tap-i18n)(\/|$)/.test(req.url)) {
- res.setHeader('Access-Control-Allow-Origin', '*');
- }
if (settings.get('Iframe_Restrict_Access')) {
res.setHeader('X-Frame-Options', settings.get('Iframe_X_Frame_Options'));
}
- const { setHeader } = res;
- res.setHeader = function(key, val, ...args) {
- if (key.toLowerCase() === 'access-control-allow-origin' && val === 'http://meteor.local') {
- return;
+ // Deprecated behavior
+ if (Support_Cordova_App === true) {
+ if (/^\/(api|_timesync|sockjs|tap-i18n)(\/|$)/.test(req.url)) {
+ res.setHeader('Access-Control-Allow-Origin', '*');
}
- return setHeader.apply(this, [key, val, ...args]);
- };
+
+ const { setHeader } = res;
+ res.setHeader = function(key, val, ...args) {
+ if (key.toLowerCase() === 'access-control-allow-origin' && val === 'http://meteor.local') {
+ return;
+ }
+ return setHeader.apply(this, [key, val, ...args]);
+ };
+ }
return next();
});
diff --git a/app/emoji/client/emojiPicker.html b/app/emoji/client/emojiPicker.html
index 0e3a5c7546e1..498f4ec1e487 100644
--- a/app/emoji/client/emojiPicker.html
+++ b/app/emoji/client/emojiPicker.html
@@ -44,6 +44,9 @@
{{_ ca
{{/each}}
{{/if}}
-
+
diff --git a/app/emoji/client/emojiPicker.js b/app/emoji/client/emojiPicker.js
index 410bbfa5682c..86360cc47575 100644
--- a/app/emoji/client/emojiPicker.js
+++ b/app/emoji/client/emojiPicker.js
@@ -1,6 +1,7 @@
import _ from 'underscore';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
+import { FlowRouter } from 'meteor/kadira:flow-router';
import { Template } from 'meteor/templating';
import { t } from '../../utils/client';
@@ -142,6 +143,12 @@ Template.emojiPicker.events({
event.stopPropagation();
event.preventDefault();
},
+ 'click .add-custom'(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ FlowRouter.go('/admin/emoji-custom');
+ EmojiPicker.close();
+ },
'click .category-link'(event) {
event.stopPropagation();
event.preventDefault();
diff --git a/app/lib/server/startup/settings.js b/app/lib/server/startup/settings.js
index 618e917331c9..63241e0b0bed 100644
--- a/app/lib/server/startup/settings.js
+++ b/app/lib/server/startup/settings.js
@@ -874,6 +874,8 @@ settings.addGroup('General', function() {
type: 'boolean',
public: true,
});
+
+ // Deprecated setting
this.add('Support_Cordova_App', false, {
type: 'boolean',
i18nDescription: 'Support_Cordova_App_Description',
diff --git a/app/mailer/server/api.js b/app/mailer/server/api.js
index 45c7f10030f3..38bb11418273 100644
--- a/app/mailer/server/api.js
+++ b/app/mailer/server/api.js
@@ -23,7 +23,7 @@ settings.get('Language', (key, value) => {
lng = value || 'en';
});
-export const replacekey = (str, key, value = '') => str.replace(new RegExp(`(\\[${ key }\\]|__${ key }__)`, 'igm'), value);
+export const replacekey = (str, key, value = '') => str.replace(new RegExp(`(\\[${ key }\\]|__${ key }__)`, 'igm'), s.escapeHTML(value));
export const translate = (str) => str.replace(/\{ ?([^\} ]+)(( ([^\}]+))+)? ?\}/gmi, (match, key) => TAPi18n.__(key, { lng }));
export const replace = function replace(str, data = {}) {
if (!str) {
diff --git a/app/theme/client/imports/components/emojiPicker.css b/app/theme/client/imports/components/emojiPicker.css
index bd2d72a0b9c1..f8601a798a4c 100644
--- a/app/theme/client/imports/components/emojiPicker.css
+++ b/app/theme/client/imports/components/emojiPicker.css
@@ -122,6 +122,12 @@
font-size: 12px;
font-weight: 500;
+
+ & .add-custom {
+ display: inline-block;
+
+ width: 100%;
+ }
}
.emoji-top {
diff --git a/app/ui/client/views/app/components/Directory/UserTab.js b/app/ui/client/views/app/components/Directory/UserTab.js
index 25145c0a7c70..58a997e1784d 100644
--- a/app/ui/client/views/app/components/Directory/UserTab.js
+++ b/app/ui/client/views/app/components/Directory/UserTab.js
@@ -23,7 +23,7 @@ const FilterByText = ({ setFilter, ...props }) => {
}, [text]);
return
- } onChange={handleChange} value={text} />
+ } onChange={handleChange} value={text} />
;
};
diff --git a/package.json b/package.json
index bb91d7d6aa59..c5783cac5b30 100644
--- a/package.json
+++ b/package.json
@@ -253,9 +253,10 @@
}
},
"houston": {
- "metadata": ".scripts/houstonMetadata.js",
+ "minTag": "0.55.0-rc.0",
"updateFiles": [
"package.json",
+ "package-lock.json",
".circleci/snap.sh",
".circleci/update-releases.sh",
".docker/Dockerfile",
diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json
index a0f25130867f..ffc3965f6d9c 100644
--- a/packages/rocketchat-i18n/i18n/en.i18n.json
+++ b/packages/rocketchat-i18n/i18n/en.i18n.json
@@ -233,6 +233,7 @@
"MAU_value": "MAU __value__",
"Activity": "Activity",
"Add": "Add",
+ "Add_custom_emoji": "Add custom emoji",
"add-oauth-service": "Add Oauth Service",
"add-oauth-service_description": "Permission to add a new Oauth service",
"add-user": "Add User",
@@ -410,9 +411,13 @@
"Apps_Marketplace_Login_Required_Title": "Marketplace Login Required",
"Apps_Marketplace_Login_Required_Description": "Purchasing apps from the Rocket.Chat Marketplace requires registering your workspace and logging in.",
"Apps_Marketplace_pricingPlan_monthly": "__price__ / month",
+ "Apps_Marketplace_pricingPlan_startingAt_monthly": "starting at __price__ / month",
"Apps_Marketplace_pricingPlan_monthly_perUser": "__price__ / month per user",
+ "Apps_Marketplace_pricingPlan_startingAt_monthly_perUser": "starting at __price__ / month per user",
"Apps_Marketplace_pricingPlan_yearly": "__price__ / year",
+ "Apps_Marketplace_pricingPlan_startingAt_yearly": "starting at __price__ / year",
"Apps_Marketplace_pricingPlan_yearly_perUser": "__price__ / year per user",
+ "Apps_Marketplace_pricingPlan_startingAt_yearly_perUser": "starting at __price__ / year per user",
"Apps_Settings": "App's Settings",
"Apps_User_Already_Exists": "The username \"__username__\" is already being used. Rename or remove the user using it to install this App",
"Apps_WhatIsIt": "Apps: What Are They?",
diff --git a/server/methods/registerUser.js b/server/methods/registerUser.js
index d95098efcae0..9ef019fab962 100644
--- a/server/methods/registerUser.js
+++ b/server/methods/registerUser.js
@@ -3,18 +3,11 @@ import { Match, check } from 'meteor/check';
import { Accounts } from 'meteor/accounts-base';
import s from 'underscore.string';
-import * as Mailer from '../../app/mailer';
import { Users } from '../../app/models';
import { settings } from '../../app/settings';
import { saveCustomFields, validateEmailDomain, passwordPolicy } from '../../app/lib';
import { validateInviteToken } from '../../app/invites/server/functions/validateInviteToken';
-let verifyEmailTemplate = '';
-Meteor.startup(() => {
- Mailer.getTemplateWrapped('Verification_Email', (value) => {
- verifyEmailTemplate = value;
- });
-});
Meteor.methods({
registerUser(formData) {
const AllowAnonymousRead = settings.get('Accounts_AllowAnonymousRead');
@@ -46,12 +39,14 @@ Meteor.methods({
}
if (settings.get('Accounts_RegistrationForm') === 'Secret URL' && (!formData.secretURL || formData.secretURL !== settings.get('Accounts_RegistrationForm_SecretURL'))) {
- if (formData.secretURL) {
- try {
- validateInviteToken(formData.secretURL);
- } catch (e) {
- throw new Meteor.Error('error-user-registration-secret', 'User registration is only allowed via Secret URL', { method: 'registerUser' });
- }
+ if (!formData.secretURL) {
+ throw new Meteor.Error('error-user-registration-secret', 'User registration is only allowed via Secret URL', { method: 'registerUser' });
+ }
+
+ try {
+ validateInviteToken(formData.secretURL);
+ } catch (e) {
+ throw new Meteor.Error('error-user-registration-secret', 'User registration is only allowed via Secret URL', { method: 'registerUser' });
}
}
@@ -86,11 +81,6 @@ Meteor.methods({
saveCustomFields(userId, formData);
try {
- const subject = Mailer.replace(settings.get('Verification_Email_Subject'));
-
- Accounts.emailTemplates.verifyEmail.subject = () => subject;
- Accounts.emailTemplates.verifyEmail.html = (userModel, url) => Mailer.replace(Mailer.replacekey(verifyEmailTemplate, 'Verification_Url', url), userModel);
-
Accounts.sendVerificationEmail(userId, userData.email);
} catch (error) {
// throw new Meteor.Error 'error-email-send-failed', 'Error trying to send email: ' + error.message, { method: 'registerUser', message: error.message }