import type {
	IHookFunctions,
	IWebhookFunctions,
	IDataObject,
	ILoadOptionsFunctions,
	INodePropertyOptions,
	INodeType,
	INodeTypeDescription,
	IWebhookResponseData,
} from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';

import { zendeskApiRequest, zendeskApiRequestAllItems } from './GenericFunctions';
import { conditionFields } from './ConditionDescription';

import { triggerPlaceholders } from './TriggerPlaceholders';

export class ZendeskTrigger implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Zendesk Trigger',
		name: 'zendeskTrigger',
		icon: 'file:zendesk.svg',
		group: ['trigger'],
		version: 1,
		description: 'Handle Zendesk events via webhooks',
		defaults: {
			name: 'Zendesk Trigger',
		},
		inputs: [],
		outputs: ['main'],
		credentials: [
			{
				name: 'zendeskApi',
				required: true,
				displayOptions: {
					show: {
						authentication: ['apiToken'],
					},
				},
			},
			{
				name: 'zendeskOAuth2Api',
				required: true,
				displayOptions: {
					show: {
						authentication: ['oAuth2'],
					},
				},
			},
		],
		webhooks: [
			{
				name: 'default',
				httpMethod: 'POST',
				responseMode: 'onReceived',
				path: 'webhook',
			},
		],
		properties: [
			{
				displayName: 'Authentication',
				name: 'authentication',
				type: 'options',
				options: [
					{
						name: 'API Token',
						value: 'apiToken',
					},
					{
						name: 'OAuth2',
						value: 'oAuth2',
					},
				],
				default: 'apiToken',
			},
			{
				displayName: 'Service',
				name: 'service',
				type: 'options',
				required: true,
				options: [
					{
						name: 'Support',
						value: 'support',
					},
				],
				default: 'support',
			},
			{
				displayName: 'Options',
				name: 'options',
				type: 'collection',
				displayOptions: {
					show: {
						service: ['support'],
					},
				},
				default: {},
				options: [
					{
						displayName: 'Field Names or IDs',
						name: 'fields',
						description:
							'The fields to return the values of. Choose from the list, or specify IDs using an expression.',
						type: 'multiOptions',
						default: [],
						typeOptions: {
							loadOptionsMethod: 'getFields',
						},
					},
				],
				placeholder: 'Add Option',
			},
			{
				displayName: 'Conditions',
				name: 'conditions',
				placeholder: 'Add Condition',
				type: 'fixedCollection',
				typeOptions: {
					multipleValues: true,
				},
				displayOptions: {
					show: {
						service: ['support'],
					},
				},
				description: 'The condition to set',
				default: {},
				options: [
					{
						name: 'all',
						displayName: 'All',
						values: [...conditionFields],
					},
					{
						name: 'any',
						displayName: 'Any',
						values: [...conditionFields],
					},
				],
			},
		],
	};

	methods = {
		loadOptions: {
			// Get all the fields to display them to user so that he can
			// select them easily
			async getFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
				const returnData: INodePropertyOptions[] = triggerPlaceholders;
				const customFields = [
					'text',
					'textarea',
					'date',
					'integer',
					'decimal',
					'regexp',
					'multiselect',
					'tagger',
				];
				const fields = await zendeskApiRequestAllItems.call(
					this,
					'ticket_fields',
					'GET',
					'/ticket_fields',
				);
				for (const field of fields) {
					if (customFields.includes(field.type as string) && field.removable && field.active) {
						const fieldName = field.title;
						const fieldId = field.id;
						returnData.push({
							name: fieldName,
							value: `ticket.ticket_field_${fieldId}`,
							description: `Custom field ${fieldName}`,
						});
					}
				}
				return returnData;
			},
			// Get all the groups to display them to user so that he can
			// select them easily
			async getGroups(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
				const returnData: INodePropertyOptions[] = [];
				const groups = await zendeskApiRequestAllItems.call(this, 'groups', 'GET', '/groups');
				for (const group of groups) {
					const groupName = group.name;
					const groupId = group.id;
					returnData.push({
						name: groupName,
						value: groupId,
					});
				}
				return returnData;
			},
			// Get all the users to display them to user so that he can
			// select them easily
			async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
				const returnData: INodePropertyOptions[] = [];
				const users = await zendeskApiRequestAllItems.call(this, 'users', 'GET', '/users');
				for (const user of users) {
					const userName = user.name;
					const userId = user.id;
					returnData.push({
						name: userName,
						value: userId,
					});
				}
				returnData.push({
					name: 'Current User',
					value: 'current_user',
				});
				returnData.push({
					name: 'Requester',
					value: 'requester_id',
				});
				return returnData;
			},
		},
	};

	webhookMethods = {
		default: {
			async checkExists(this: IHookFunctions): Promise<boolean> {
				const webhookUrl = this.getNodeWebhookUrl('default') as string;
				const webhookData = this.getWorkflowStaticData('node');
				const conditions = this.getNodeParameter('conditions') as IDataObject;

				let endpoint = '';
				const resultAll = [],
					resultAny = [];

				const conditionsAll = conditions.all as [IDataObject];
				if (conditionsAll) {
					for (const conditionAll of conditionsAll) {
						const aux: IDataObject = {};
						aux.field = conditionAll.field;
						aux.operator = conditionAll.operation;
						if (conditionAll.operation !== 'changed' && conditionAll.operation !== 'not_changed') {
							aux.value = conditionAll.value;
						} else {
							aux.value = null;
						}
						resultAll.push(aux);
					}
				}

				const conditionsAny = conditions.any as [IDataObject];
				if (conditionsAny) {
					for (const conditionAny of conditionsAny) {
						const aux: IDataObject = {};
						aux.field = conditionAny.field;
						aux.operator = conditionAny.operation;
						if (conditionAny.operation !== 'changed' && conditionAny.operation !== 'not_changed') {
							aux.value = conditionAny.value;
						} else {
							aux.value = null;
						}
						resultAny.push(aux);
					}
				}

				// get all webhooks
				// https://developer.zendesk.com/api-reference/event-connectors/webhooks/webhooks/#list-webhooks
				const { webhooks } = await zendeskApiRequest.call(this, 'GET', '/webhooks');
				for (const webhook of webhooks) {
					if (webhook.endpoint === webhookUrl) {
						webhookData.targetId = webhook.id;
						break;
					}
				}

				// no target was found
				if (webhookData.targetId === undefined) {
					return false;
				}

				endpoint = '/triggers/active';
				const triggers = await zendeskApiRequestAllItems.call(this, 'triggers', 'GET', endpoint);

				for (const trigger of triggers) {
					const toDeleteTriggers = [];
					// this trigger belong to the current target
					if (trigger.actions[0].value[0].toString() === webhookData.targetId?.toString()) {
						toDeleteTriggers.push(trigger.id);
					}
					// delete all trigger attach to this target;
					if (toDeleteTriggers.length !== 0) {
						await zendeskApiRequest.call(
							this,
							'DELETE',
							'/triggers/destroy_many',
							{},
							{ ids: toDeleteTriggers.join(',') },
						);
					}
				}

				return false;
			},
			async create(this: IHookFunctions): Promise<boolean> {
				const webhookUrl = this.getNodeWebhookUrl('default') as string;
				const webhookData = this.getWorkflowStaticData('node');
				const service = this.getNodeParameter('service') as string;

				if (service === 'support') {
					const message: IDataObject = {};
					const resultAll = [],
						resultAny = [];
					const conditions = this.getNodeParameter('conditions') as IDataObject;
					const options = this.getNodeParameter('options') as IDataObject;

					if (Object.keys(conditions).length === 0) {
						throw new NodeOperationError(this.getNode(), 'You must have at least one condition');
					}

					if (options.fields) {
						for (const field of options.fields as string[]) {
							message[field] = `{{${field}}}`;
						}
					} else {
						message['ticket.id'] = '{{ticket.id}}';
					}

					const conditionsAll = conditions.all as [IDataObject];
					if (conditionsAll) {
						for (const conditionAll of conditionsAll) {
							const aux: IDataObject = {};
							aux.field = conditionAll.field;
							aux.operator = conditionAll.operation;
							if (
								conditionAll.operation !== 'changed' &&
								conditionAll.operation !== 'not_changed'
							) {
								aux.value = conditionAll.value;
							} else {
								aux.value = null;
							}
							resultAll.push(aux);
						}
					}

					const conditionsAny = conditions.any as [IDataObject];
					if (conditionsAny) {
						for (const conditionAny of conditionsAny) {
							const aux: IDataObject = {};
							aux.field = conditionAny.field;
							aux.operator = conditionAny.operation;
							if (
								conditionAny.operation !== 'changed' &&
								conditionAny.operation !== 'not_changed'
							) {
								aux.value = conditionAny.value;
							} else {
								aux.value = null;
							}
							resultAny.push(aux);
						}
					}

					const urlParts = new URL(webhookUrl);

					const bodyTrigger: IDataObject = {
						trigger: {
							title: `n8n-webhook:${urlParts.pathname}`,
							conditions: {
								all: resultAll,
								any: resultAny,
							},
							actions: [
								{
									field: 'notification_webhook',
									value: [],
								},
							],
						},
					};

					const bodyTarget: IDataObject = {
						webhook: {
							name: 'n8n webhook',
							endpoint: webhookUrl,
							http_method: 'POST',
							status: 'active',
							request_format: 'json',
							subscriptions: ['conditional_ticket_events'],
						},
					};
					let target: IDataObject = {};

					// if target id exists but trigger does not then reuse the target
					// and create the trigger else create both
					if (webhookData.targetId !== undefined) {
						target.id = webhookData.targetId;
					} else {
						// create a webhook
						// https://developer.zendesk.com/api-reference/event-connectors/webhooks/webhooks/#create-or-clone-webhook
						target = (await zendeskApiRequest.call(this, 'POST', '/webhooks', bodyTarget))
							.webhook as IDataObject;
					}

					((bodyTrigger.trigger as IDataObject).actions as IDataObject[])[0].value = [
						target.id,
						JSON.stringify(message),
					];

					const { trigger } = await zendeskApiRequest.call(this, 'POST', '/triggers', bodyTrigger);
					webhookData.webhookId = trigger.id;
					webhookData.targetId = target.id;
				}
				return true;
			},
			async delete(this: IHookFunctions): Promise<boolean> {
				const webhookData = this.getWorkflowStaticData('node');
				try {
					await zendeskApiRequest.call(this, 'DELETE', `/triggers/${webhookData.webhookId}`);
					await zendeskApiRequest.call(this, 'DELETE', `/webhooks/${webhookData.targetId}`);
				} catch (error) {
					return false;
				}
				delete webhookData.triggerId;
				delete webhookData.targetId;
				return true;
			},
		},
	};

	async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
		const req = this.getRequestObject();
		return {
			workflowData: [this.helpers.returnJsonArray(req.body as IDataObject)],
		};
	}
}


runExternalHook('main.routeChange', useWebhooksStore(), { from, to });

if (userStore.currentUser && to.name && to.name !== VIEWS.SIGNOUT && !to.name.includes('Modal')) {

keep keep keep replace replace replace keep keep keep

import type {
	IExecuteFunctions,
	IDataObject,
	ILoadOptionsFunctions,
	INodeExecutionData,
	INodePropertyOptions,
	INodeType,
	INodeTypeDescription,
} from 'n8n-workflow';

import {
	accountFields,
	accountOperations,
	exchangeRateFields,
	exchangeRateOperations,
	profileFields,
	profileOperations,
	quoteFields,
	quoteOperations,
	recipientFields,
	recipientOperations,
	transferFields,
	transferOperations,
} from './descriptions';

import type {
	BorderlessAccount,
	ExchangeRateAdditionalFields,
	Profile,
	Recipient,
	StatementAdditionalFields,
	TransferFilters,
} from './GenericFunctions';
import { wiseApiRequest } from './GenericFunctions';

import omit from 'lodash.omit';

import moment from 'moment-timezone';

import { v4 as uuid } from 'uuid';

export class Wise implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Wise',
		name: 'wise',
		icon: 'file:wise.svg',
		group: ['transform'],
		version: 1,
		subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
		description: 'Consume the Wise API',
		defaults: {
			name: 'Wise',
		},
		inputs: ['main'],
		outputs: ['main'],
		credentials: [
			{
				name: 'wiseApi',
				required: true,
			},
		],
		properties: [
			{
				displayName: 'Resource',
				name: 'resource',
				type: 'options',
				noDataExpression: true,
				options: [
					{
						name: 'Account',
						value: 'account',
					},
					{
						name: 'Exchange Rate',
						value: 'exchangeRate',
					},
					{
						name: 'Profile',
						value: 'profile',
					},
					{
						name: 'Quote',
						value: 'quote',
					},
					{
						name: 'Recipient',
						value: 'recipient',
					},
					{
						name: 'Transfer',
						value: 'transfer',
					},
				],
				default: 'account',
			},
			...accountOperations,
			...accountFields,
			...exchangeRateOperations,
			...exchangeRateFields,
			...profileOperations,
			...profileFields,
			...quoteOperations,
			...quoteFields,
			...recipientOperations,
			...recipientFields,
			...transferOperations,
			...transferFields,
		],
	};

	methods = {
		loadOptions: {
			async getBorderlessAccounts(this: ILoadOptionsFunctions) {
				const qs = {
					profileId: this.getNodeParameter('profileId', 0),
				};

				const accounts = await wiseApiRequest.call(this, 'GET', 'v1/borderless-accounts', {}, qs);

				return accounts.map(({ id, balances }: BorderlessAccount) => ({
					name: balances.map(({ currency }) => currency).join(' - '),
					value: id,
				}));
			},

			async getProfiles(this: ILoadOptionsFunctions) {
				const profiles = await wiseApiRequest.call(this, 'GET', 'v1/profiles');

				return profiles.map(({ id, type }: Profile) => ({
					name: type.charAt(0).toUpperCase() + type.slice(1),
					value: id,
				}));
			},

			async getRecipients(this: ILoadOptionsFunctions) {
				const qs = {
					profileId: this.getNodeParameter('profileId', 0),
				};

				const recipients = (await wiseApiRequest.call(
					this,
					'GET',
					'v1/accounts',
					{},
					qs,
				)) as Recipient[];

				return recipients.reduce<INodePropertyOptions[]>(
					(activeRecipients, { active, id, accountHolderName, currency, country, type }) => {
						if (active) {
							const recipient = {
								name: `[${currency}] ${accountHolderName} - (${
									country !== null ? country + ' - ' : ''
								}${type})`,
								value: id,
							};
							activeRecipients.push(recipient);
						}
						return activeRecipients;
					},
					[],
				);
			},
		},
	};

	async execute(this: IExecuteFunctions) {
		const items = this.getInputData();

		const resource = this.getNodeParameter('resource', 0);
		const operation = this.getNodeParameter('operation', 0);

		const timezone = this.getTimezone();

		let responseData;
		const returnData: IDataObject[] = [];
		let binaryOutput = false;

		for (let i = 0; i < items.length; i++) {
			try {
				if (resource === 'account') {
					// *********************************************************************
					//                             account
					// *********************************************************************

					if (operation === 'getBalances') {
						// ----------------------------------
						//      account: getBalances
						// ----------------------------------

						// https://api-docs.transferwise.com/#borderless-accounts-get-account-balance

						const qs = {
							profileId: this.getNodeParameter('profileId', i),
						};

						responseData = await wiseApiRequest.call(this, 'GET', 'v1/borderless-accounts', {}, qs);
					} else if (operation === 'getCurrencies') {
						// ----------------------------------
						//      account: getCurrencies
						// ----------------------------------

						// https://api-docs.transferwise.com/#borderless-accounts-get-available-currencies

						responseData = await wiseApiRequest.call(
							this,
							'GET',
							'v1/borderless-accounts/balance-currencies',
						);
					} else if (operation === 'getStatement') {
						// ----------------------------------
						//      account: getStatement
						// ----------------------------------

						// https://api-docs.transferwise.com/#borderless-accounts-get-account-statement

						const profileId = this.getNodeParameter('profileId', i);
						const borderlessAccountId = this.getNodeParameter('borderlessAccountId', i);
						const format = this.getNodeParameter('format', i) as 'json' | 'csv' | 'pdf';
						const endpoint = `v3/profiles/${profileId}/borderless-accounts/${borderlessAccountId}/statement.${format}`;

						const qs = {
							currency: this.getNodeParameter('currency', i),
						} as IDataObject;

						const { lineStyle, range } = this.getNodeParameter(
							'additionalFields',
							i,
						) as StatementAdditionalFields;

						if (lineStyle !== undefined) {
							qs.type = lineStyle;
						}

						if (range !== undefined) {
							qs.intervalStart = moment
								.tz(range.rangeProperties.intervalStart, timezone)
								.utc()
								.format();
							qs.intervalEnd = moment
								.tz(range.rangeProperties.intervalEnd, timezone)
								.utc()
								.format();
						} else {
							qs.intervalStart = moment().subtract(1, 'months').utc().format();
							qs.intervalEnd = moment().utc().format();
						}

						if (format === 'json') {
							responseData = await wiseApiRequest.call(this, 'GET', endpoint, {}, qs);
						} else {
							const data = await wiseApiRequest.call(this, 'GET', endpoint, {}, qs, {
								encoding: 'arraybuffer',
							});
							const binaryProperty = this.getNodeParameter('binaryProperty', i);

							items[i].binary = items[i].binary ?? {};
							items[i].binary![binaryProperty] = await this.helpers.prepareBinaryData(
								data as Buffer,
								this.getNodeParameter('fileName', i) as string,
							);

							responseData = items;
							binaryOutput = true;
						}
					}
				} else if (resource === 'exchangeRate') {
					// *********************************************************************
					//                             exchangeRate
					// *********************************************************************

					if (operation === 'get') {
						// ----------------------------------
						//       exchangeRate: get
						// ----------------------------------

						// https://api-docs.transferwise.com/#exchange-rates-list

						const qs = {
							source: this.getNodeParameter('source', i),
							target: this.getNodeParameter('target', i),
						} as IDataObject;

						const { interval, range, time } = this.getNodeParameter(
							'additionalFields',
							i,
						) as ExchangeRateAdditionalFields;

						if (interval !== undefined) {
							qs.group = interval;
						}

						if (time !== undefined) {
							qs.time = time;
						}

						if (range !== undefined && time === undefined) {
							qs.from = moment.tz(range.rangeProperties.from, timezone).utc().format();
							qs.to = moment.tz(range.rangeProperties.to, timezone).utc().format();
						} else if (time === undefined) {
							qs.from = moment().subtract(1, 'months').utc().format();
							qs.to = moment().format();
						}

						responseData = await wiseApiRequest.call(this, 'GET', 'v1/rates', {}, qs);
					}
				} else if (resource === 'profile') {
					// *********************************************************************
					//                             profile
					// *********************************************************************

					if (operation === 'get') {
						// ----------------------------------
						//          profile: get
						// ----------------------------------

						// https://api-docs.transferwise.com/#user-profiles-get-by-id

						const profileId = this.getNodeParameter('profileId', i);
						responseData = await wiseApiRequest.call(this, 'GET', `v1/profiles/${profileId}`);
					} else if (operation === 'getAll') {
						// ----------------------------------
						//         profile: getAll
						// ----------------------------------

						// https://api-docs.transferwise.com/#user-profiles-list

						responseData = await wiseApiRequest.call(this, 'GET', 'v1/profiles');
					}
				} else if (resource === 'recipient') {
					// *********************************************************************
					//                             recipient
					// *********************************************************************

					if (operation === 'getAll') {
						// ----------------------------------
						//       recipient: getAll
						// ----------------------------------

						// https://api-docs.transferwise.com/#recipient-accounts-list

						responseData = await wiseApiRequest.call(this, 'GET', 'v1/accounts');

						const returnAll = this.getNodeParameter('returnAll', i);

						if (!returnAll) {
							const limit = this.getNodeParameter('limit', i);
							responseData = responseData.slice(0, limit);
						}
					}
				} else if (resource === 'quote') {
					// *********************************************************************
					//                             quote
					// *********************************************************************

					if (operation === 'create') {
						// ----------------------------------
						//          quote: create
						// ----------------------------------

						// https://api-docs.transferwise.com/#quotes-create

						const body = {
							profile: this.getNodeParameter('profileId', i),
							sourceCurrency: (this.getNodeParameter('sourceCurrency', i) as string).toUpperCase(),
							targetCurrency: (this.getNodeParameter('targetCurrency', i) as string).toUpperCase(),
						} as IDataObject;

						const amountType = this.getNodeParameter('amountType', i) as 'source' | 'target';

						if (amountType === 'source') {
							body.sourceAmount = this.getNodeParameter('amount', i);
						} else if (amountType === 'target') {
							body.targetAmount = this.getNodeParameter('amount', i);
						}

						responseData = await wiseApiRequest.call(this, 'POST', 'v2/quotes', body, {});
					} else if (operation === 'get') {
						// ----------------------------------
						//          quote: get
						// ----------------------------------

						// https://api-docs.transferwise.com/#quotes-get-by-id

						const quoteId = this.getNodeParameter('quoteId', i);
						responseData = await wiseApiRequest.call(this, 'GET', `v2/quotes/${quoteId}`);
					}
				} else if (resource === 'transfer') {
					// *********************************************************************
					//                             transfer
					// *********************************************************************

					if (operation === 'create') {
						// ----------------------------------
						//         transfer: create
						// ----------------------------------

						// https://api-docs.transferwise.com/#transfers-create

						const body = {
							quoteUuid: this.getNodeParameter('quoteId', i),
							targetAccount: this.getNodeParameter('targetAccountId', i),
							customerTransactionId: uuid(),
						} as IDataObject;

						const { reference } = this.getNodeParameter('additionalFields', i) as {
							reference: string;
						};

						if (reference !== undefined) {
							body.details = { reference };
						}

						responseData = await wiseApiRequest.call(this, 'POST', 'v1/transfers', body, {});
					} else if (operation === 'delete') {
						// ----------------------------------
						//        transfer: delete
						// ----------------------------------

						// https://api-docs.transferwise.com/#transfers-cancel

						const transferId = this.getNodeParameter('transferId', i);
						responseData = await wiseApiRequest.call(
							this,
							'PUT',
							`v1/transfers/${transferId}/cancel`,
						);
					} else if (operation === 'execute') {
						// ----------------------------------
						//        transfer: execute
						// ----------------------------------

						// https://api-docs.transferwise.com/#transfers-fund

						const profileId = this.getNodeParameter('profileId', i);
						const transferId = this.getNodeParameter('transferId', i) as string;

						const endpoint = `v3/profiles/${profileId}/transfers/${transferId}/payments`;
						responseData = await wiseApiRequest.call(
							this,
							'POST',
							endpoint,
							{ type: 'BALANCE' },
							{},
						);

						// in sandbox, simulate transfer completion so that PDF receipt can be downloaded

						const { environment } = await this.getCredentials('wiseApi');

						if (environment === 'test') {
							for (const testEndpoint of [
								'processing',
								'funds_converted',
								'outgoing_payment_sent',
							]) {
								await wiseApiRequest.call(
									this,
									'GET',
									`v1/simulation/transfers/${transferId}/${testEndpoint}`,
								);
							}
						}
					} else if (operation === 'get') {
						// ----------------------------------
						//        transfer: get
						// ----------------------------------

						const transferId = this.getNodeParameter('transferId', i);
						const downloadReceipt = this.getNodeParameter('downloadReceipt', i) as boolean;

						if (downloadReceipt) {
							// https://api-docs.transferwise.com/#transfers-get-receipt-pdf

							const data = await wiseApiRequest.call(
								this,
								'GET',
								`v1/transfers/${transferId}/receipt.pdf`,
								{},
								{},
								{ encoding: 'arraybuffer' },
							);
							const binaryProperty = this.getNodeParameter('binaryProperty', i);

							items[i].binary = items[i].binary ?? {};
							items[i].binary![binaryProperty] = await this.helpers.prepareBinaryData(
								data as Buffer,
								this.getNodeParameter('fileName', i) as string,
							);

							responseData = items;
							binaryOutput = true;
						} else {
							// https://api-docs.transferwise.com/#transfers-get-by-id

							responseData = await wiseApiRequest.call(this, 'GET', `v1/transfers/${transferId}`);
						}
					} else if (operation === 'getAll') {
						// ----------------------------------
						//        transfer: getAll
						// ----------------------------------

						// https://api-docs.transferwise.com/#transfers-list

						const qs = {
							profile: this.getNodeParameter('profileId', i),
						} as IDataObject;

						const filters = this.getNodeParameter('filters', i) as TransferFilters;

						Object.keys(omit(filters, 'range')).forEach((key) => {
							qs[key] = filters[key];
						});

						if (filters.range !== undefined) {
							qs.createdDateStart = moment(filters.range.rangeProperties.createdDateStart).format();
							qs.createdDateEnd = moment(filters.range.rangeProperties.createdDateEnd).format();
						} else {
							qs.createdDateStart = moment().subtract(1, 'months').format();
							qs.createdDateEnd = moment().format();
						}

						const returnAll = this.getNodeParameter('returnAll', i);

						if (!returnAll) {
							qs.limit = this.getNodeParameter('limit', i);
						}

						responseData = await wiseApiRequest.call(this, 'GET', 'v1/transfers', {}, qs);
					}
				}
			} catch (error) {
				if (this.continueOnFail()) {
					returnData.push({ error: error.toString() });
					continue;
				}

				throw error;
			}

			Array.isArray(responseData)
				? returnData.push(...(responseData as IDataObject[]))
				: returnData.push(responseData as IDataObject);
		}

		if (binaryOutput && responseData !== undefined) {
			return this.prepareOutputData(responseData as INodeExecutionData[]);
		}

		return [this.helpers.returnJsonArray(returnData)];
	}
}


keep keep keep keep keep replace keep keep keep keep

// Insert server unique id if it doesn't exist
RocketChat.settings.add('uniqueID', process.env.DEPLOYMENT_ID || Random.id(), {
	'public': true,
	hidden: true
});

// When you define a setting and want to add a description, you don't need to automatically define the i18nDescription
// if you add a node to the i18n.json with the same setting name but with `_Description` it will automatically work.

RocketChat.settings.addGroup('Accounts', function() {
	this.add('Accounts_AllowAnonymousRead', false, {
		type: 'boolean',
		public: true
	});
	this.add('Accounts_AllowAnonymousWrite', false, {
		type: 'boolean',
		public: true,
		enableQuery: {
			_id: 'Accounts_AllowAnonymousRead',
			value: true
		}
	});
	this.add('Accounts_AllowDeleteOwnAccount', false, {
		type: 'boolean',
		'public': true,
		enableQuery: {
			_id: 'Accounts_AllowUserProfileChange',
			value: true
		}
	});
	this.add('Accounts_AllowUserProfileChange', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Accounts_AllowUserAvatarChange', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Accounts_AllowUsernameChange', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Accounts_AllowEmailChange', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Accounts_AllowPasswordChange', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Accounts_LoginExpiration', 90, {
		type: 'int',
		'public': true
	});
	this.add('Accounts_ShowFormLogin', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Accounts_EmailOrUsernamePlaceholder', '', {
		type: 'string',
		'public': true,
		i18nLabel: 'Placeholder_for_email_or_username_login_field'
	});
	this.add('Accounts_PasswordPlaceholder', '', {
		type: 'string',
		'public': true,
		i18nLabel: 'Placeholder_for_password_login_field'
	});
	this.add('Accounts_ForgetUserSessionOnWindowClose', false, {
		type: 'boolean',
		'public': true
	});

	this.section('Registration', function() {
		this.add('Accounts_DefaultUsernamePrefixSuggestion', 'user', {
			type: 'string'
		});
		this.add('Accounts_RequireNameForSignUp', true, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_RequirePasswordConfirmation', true, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_EmailVerification', false, {
			type: 'boolean',
			'public': true,
			enableQuery: {
				_id: 'SMTP_Host',
				value: {
					$exists: 1,
					$ne: ''
				}
			}
		});
		this.add('Accounts_ManuallyApproveNewUsers', false, {
			type: 'boolean'
		});
		this.add('Accounts_AllowedDomainsList', '', {
			type: 'string',
			'public': true
		});
		this.add('Accounts_BlockedDomainsList', '', {
			type: 'string'
		});
		this.add('Accounts_BlockedUsernameList', '', {
			type: 'string'
		});
		this.add('Accounts_UseDefaultBlockedDomainsList', true, {
			type: 'boolean'
		});
		this.add('Accounts_UseDNSDomainCheck', false, {
			type: 'boolean'
		});
		this.add('Accounts_RegistrationForm', 'Public', {
			type: 'select',
			'public': true,
			values: [
				{
					key: 'Public',
					i18nLabel: 'Accounts_RegistrationForm_Public'
				}, {
					key: 'Disabled',
					i18nLabel: 'Accounts_RegistrationForm_Disabled'
				}, {
					key: 'Secret URL',
					i18nLabel: 'Accounts_RegistrationForm_Secret_URL'
				}
			]
		});
		this.add('Accounts_RegistrationForm_SecretURL', Random.id(), {
			type: 'string'
		});
		this.add('Accounts_RegistrationForm_LinkReplacementText', 'New user registration is currently disabled', {
			type: 'string',
			'public': true
		});
		this.add('Accounts_Registration_AuthenticationServices_Enabled', true, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_Registration_AuthenticationServices_Default_Roles', 'user', {
			type: 'string',
			enableQuery: {
				_id: 'Accounts_Registration_AuthenticationServices_Enabled',
				value: true
			}
		});
		this.add('Accounts_PasswordReset', true, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_CustomFields', '', {
			type: 'code',
			'public': true,
			i18nLabel: 'Custom_Fields'
		});
	});

	this.section('Avatar', function() {
		this.add('Accounts_AvatarResize', true, {
			type: 'boolean'
		});
		this.add('Accounts_AvatarSize', 200, {
			type: 'int',
			enableQuery: {
				_id: 'Accounts_AvatarResize',
				value: true
			}
		});
		this.add('Accounts_AvatarStoreType', 'GridFS', {
			type: 'select',
			values: [
				{
					key: 'GridFS',
					i18nLabel: 'GridFS'
				}, {
					key: 'FileSystem',
					i18nLabel: 'FileSystem'
				}
			]
		});
		this.add('Accounts_AvatarStorePath', '', {
			type: 'string',
			enableQuery: {
				_id: 'Accounts_AvatarStoreType',
				value: 'FileSystem'
			}
		});
		return this.add('Accounts_SetDefaultAvatar', true, {
			type: 'boolean'
		});
	});
});

RocketChat.settings.addGroup('OAuth', function() {
	this.section('Facebook', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Facebook',
			value: true
		};
		this.add('Accounts_OAuth_Facebook', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_OAuth_Facebook_id', '', {
			type: 'string',
			enableQuery
		});
		this.add('Accounts_OAuth_Facebook_secret', '', {
			type: 'string',
			enableQuery
		});
		return this.add('Accounts_OAuth_Facebook_callback_url', '_oauth/facebook', {
			type: 'relativeUrl',
			readonly: true,
			force: true,
			enableQuery
		});
	});
	this.section('Google', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Google',
			value: true
		};
		this.add('Accounts_OAuth_Google', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_OAuth_Google_id', '', {
			type: 'string',
			enableQuery
		});
		this.add('Accounts_OAuth_Google_secret', '', {
			type: 'string',
			enableQuery
		});
		return this.add('Accounts_OAuth_Google_callback_url', '_oauth/google', {
			type: 'relativeUrl',
			readonly: true,
			force: true,
			enableQuery
		});
	});
	this.section('GitHub', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Github',
			value: true
		};
		this.add('Accounts_OAuth_Github', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_OAuth_Github_id', '', {
			type: 'string',
			enableQuery
		});
		this.add('Accounts_OAuth_Github_secret', '', {
			type: 'string',
			enableQuery
		});
		return this.add('Accounts_OAuth_Github_callback_url', '_oauth/github', {
			type: 'relativeUrl',
			readonly: true,
			force: true,
			enableQuery
		});
	});
	this.section('Linkedin', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Linkedin',
			value: true
		};
		this.add('Accounts_OAuth_Linkedin', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_OAuth_Linkedin_id', '', {
			type: 'string',
			enableQuery
		});
		this.add('Accounts_OAuth_Linkedin_secret', '', {
			type: 'string',
			enableQuery
		});
		return this.add('Accounts_OAuth_Linkedin_callback_url', '_oauth/linkedin', {
			type: 'relativeUrl',
			readonly: true,
			force: true,
			enableQuery
		});
	});
	this.section('Meteor', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Meteor',
			value: true
		};
		this.add('Accounts_OAuth_Meteor', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_OAuth_Meteor_id', '', {
			type: 'string',
			enableQuery
		});
		this.add('Accounts_OAuth_Meteor_secret', '', {
			type: 'string',
			enableQuery
		});
		return this.add('Accounts_OAuth_Meteor_callback_url', '_oauth/meteor', {
			type: 'relativeUrl',
			readonly: true,
			force: true,
			enableQuery
		});
	});
	this.section('Twitter', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Twitter',
			value: true
		};
		this.add('Accounts_OAuth_Twitter', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Accounts_OAuth_Twitter_id', '', {
			type: 'string',
			enableQuery
		});
		this.add('Accounts_OAuth_Twitter_secret', '', {
			type: 'string',
			enableQuery
		});
		return this.add('Accounts_OAuth_Twitter_callback_url', '_oauth/twitter', {
			type: 'relativeUrl',
			readonly: true,
			force: true,
			enableQuery
		});
	});
	return this.section('Proxy', function() {
		this.add('Accounts_OAuth_Proxy_host', 'https://oauth-proxy.rocket.chat', {
			type: 'string',
			'public': true
		});
		return this.add('Accounts_OAuth_Proxy_services', '', {
			type: 'string',
			'public': true
		});
	});
});

RocketChat.settings.addGroup('General', function() {
	this.add('Site_Url', typeof __meteor_runtime_config__ !== 'undefined' && __meteor_runtime_config__ !== null ? __meteor_runtime_config__.ROOT_URL : null, {
		type: 'string',
		i18nDescription: 'Site_Url_Description',
		'public': true
	});
	this.add('Site_Name', 'Rocket.Chat', {
		type: 'string',
		'public': true
	});
	this.add('Language', '', {
		type: 'language',
		'public': true
	});
	this.add('Allow_Invalid_SelfSigned_Certs', false, {
		type: 'boolean'
	});
	this.add('Favorite_Rooms', true, {
		type: 'boolean',
		'public': true
	});
	this.add('CDN_PREFIX', '', {
		type: 'string',
		'public': true
	});
	this.add('Force_SSL', false, {
		type: 'boolean',
		'public': true
	});
	this.add('GoogleTagManager_id', '', {
		type: 'string',
		'public': true
	});
	this.add('Bugsnag_api_key', '', {
		type: 'string',
		'public': false
	});
	this.add('Force_Disable_OpLog_For_Cache', false, {
		type: 'boolean',
		'public': false
	});
	this.add('Restart', 'restart_server', {
		type: 'action',
		actionText: 'Restart_the_server'
	});
	this.section('UTF8', function() {
		this.add('UTF8_Names_Validation', '[0-9a-zA-Z-_.]+', {
			type: 'string',
			'public': true,
			i18nDescription: 'UTF8_Names_Validation_Description'
		});
		return this.add('UTF8_Names_Slugify', true, {
			type: 'boolean',
			'public': true
		});
	});
	this.section('Reporting', function() {
		return this.add('Statistics_reporting', true, {
			type: 'boolean'
		});
	});
	this.section('Notifications', function() {
		return this.add('Desktop_Notifications_Duration', 0, {
			type: 'int',
			'public': true,
			i18nDescription: 'Desktop_Notification_Durations_Description'
		});
	});
	this.section('REST API', function() {
		return this.add('API_User_Limit', 500, {
			type: 'int',
			'public': true,
			i18nDescription: 'API_User_Limit'
		});
	});
	this.section('Iframe_Integration', function() {
		this.add('Iframe_Integration_send_enable', false, {
			type: 'boolean',
			'public': true
		});
		this.add('Iframe_Integration_send_target_origin', '*', {
			type: 'string',
			'public': true,
			enableQuery: {
				_id: 'Iframe_Integration_send_enable',
				value: true
			}
		});
		this.add('Iframe_Integration_receive_enable', false, {
			type: 'boolean',
			'public': true
		});
		return this.add('Iframe_Integration_receive_origin', '*', {
			type: 'string',
			'public': true,
			enableQuery: {
				_id: 'Iframe_Integration_receive_enable',
				value: true
			}
		});
	});
	this.section('Translations', function() {
		return this.add('Custom_Translations', '', {
			type: 'code',
			'public': true
		});
	});
	return this.section('Stream_Cast', function() {
		return this.add('Stream_Cast_Address', '', {
			type: 'string'
		});
	});
});

RocketChat.settings.addGroup('Email', function() {
	this.section('Header_and_Footer', function() {
		this.add('Email_Header', '

[Site_Name]

', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Header'
		});
		return this.add('Email_Footer', '

Powered by Rocket.Chat

', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Footer'
		});
	});
	this.section('SMTP', function() {
		this.add('SMTP_Protocol', 'smtp', {
			type: 'select',
			values: [
				{
					key: 'smtp',
					i18nLabel: 'smtp'
				}, {
					key: 'smtps',
					i18nLabel: 'smtps'
				}
			],
			env: true,
			i18nLabel: 'Protocol'
		});
		this.add('SMTP_Host', '', {
			type: 'string',
			env: true,
			i18nLabel: 'Host'
		});
		this.add('SMTP_Port', '', {
			type: 'string',
			env: true,
			i18nLabel: 'Port'
		});
		this.add('SMTP_Pool', true, {
			type: 'boolean',
			env: true,
			i18nLabel: 'Pool'
		});
		this.add('SMTP_Username', '', {
			type: 'string',
			env: true,
			i18nLabel: 'Username'
		});
		this.add('SMTP_Password', '', {
			type: 'password',
			env: true,
			i18nLabel: 'Password'
		});
		this.add('From_Email', '', {
			type: 'string',
			placeholder: 'email@domain'
		});
		return this.add('SMTP_Test_Button', 'sendSMTPTestEmail', {
			type: 'action',
			actionText: 'Send_a_test_mail_to_my_user'
		});
	});
	this.section('Invitation', function() {
		this.add('Invitation_Customized', false, {
			type: 'boolean',
			i18nLabel: 'Custom'
		});
		this.add('Invitation_Subject', '', {
			type: 'string',
			i18nLabel: 'Subject',
			enableQuery: {
				_id: 'Invitation_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Invitation_Customized',
				value: false
			}
		});
		return this.add('Invitation_HTML', '', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Body',
			i18nDescription: 'Invitation_HTML_Description',
			enableQuery: {
				_id: 'Invitation_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Invitation_Customized',
				value: false
			}
		});
	});
	this.section('Registration', function() {
		this.add('Accounts_Enrollment_Customized', false, {
			type: 'boolean',
			i18nLabel: 'Custom'
		});
		this.add('Accounts_Enrollment_Email_Subject', '', {
			type: 'string',
			i18nLabel: 'Subject',
			enableQuery: {
				_id: 'Accounts_Enrollment_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Accounts_Enrollment_Customized',
				value: false
			}
		});
		return this.add('Accounts_Enrollment_Email', '', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Body',
			enableQuery: {
				_id: 'Accounts_Enrollment_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Accounts_Enrollment_Customized',
				value: false
			}
		});
	});
	this.section('Registration_via_Admin', function() {
		this.add('Accounts_UserAddedEmail_Customized', false, {
			type: 'boolean',
			i18nLabel: 'Custom'
		});
		this.add('Accounts_UserAddedEmailSubject', '', {
			type: 'string',
			i18nLabel: 'Subject',
			enableQuery: {
				_id: 'Accounts_UserAddedEmail_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Accounts_UserAddedEmail_Customized',
				value: false
			}
		});
		return this.add('Accounts_UserAddedEmail', '', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Body',
			i18nDescription: 'Accounts_UserAddedEmail_Description',
			enableQuery: {
				_id: 'Accounts_UserAddedEmail_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Accounts_UserAddedEmail_Customized',
				value: false
			}
		});
	});
	this.section('Forgot_password_section', function() {
		this.add('Forgot_Password_Customized', false, {
			type: 'boolean',
			i18nLabel: 'Custom'
		});
		this.add('Forgot_Password_Email_Subject', '', {
			type: 'string',
			i18nLabel: 'Subject',
			enableQuery: {
				_id: 'Forgot_Password_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Forgot_Password_Customized',
				value: false
			}
		});
		return this.add('Forgot_Password_Email', '', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Body',
			i18nDescription: 'Forgot_Password_Description',
			enableQuery: {
				_id: 'Forgot_Password_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Forgot_Password_Customized',
				value: false
			}
		});
	});
	return this.section('Verification', function() {
		this.add('Verification_Customized', false, {
			type: 'boolean',
			i18nLabel: 'Custom'
		});
		this.add('Verification_Email_Subject', '', {
			type: 'string',
			i18nLabel: 'Subject',
			enableQuery: {
				_id: 'Verification_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Verification_Customized',
				value: false
			}
		});
		return this.add('Verification_Email', '', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			i18nLabel: 'Body',
			i18nDescription: 'Verification_Description',
			enableQuery: {
				_id: 'Verification_Customized',
				value: true
			},
			i18nDefaultQuery: {
				_id: 'Verification_Customized',
				value: false
			}
		});
	});
});

RocketChat.settings.addGroup('Message', function() {
	this.section('Message_Attachments', function() {
		this.add('Message_Attachments_GroupAttach', false, {
			type: 'boolean',
			'public': true,
			i18nDescription: 'Message_Attachments_GroupAttachDescription'
		});
		this.add('Message_AudioRecorderEnabled', true, {
			type: 'boolean',
			'public': true,
			i18nDescription: 'Message_AudioRecorderEnabledDescription'
		});
	});
	this.add('Message_AllowEditing', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_AllowEditing_BlockEditInMinutes', 0, {
		type: 'int',
		'public': true,
		i18nDescription: 'Message_AllowEditing_BlockEditInMinutesDescription'
	});
	this.add('Message_AllowDeleting', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_AllowDeleting_BlockDeleteInMinutes', 0, {
		type: 'int',
		'public': true,
		i18nDescription: 'Message_AllowDeleting_BlockDeleteInMinutes'
	});
	this.add('Message_AllowUnrecognizedSlashCommand', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_AlwaysSearchRegExp', false, {
		type: 'boolean'
	});
	this.add('Message_ShowEditedStatus', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_ShowDeletedStatus', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_AllowBadWordsFilter', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_BadWordsFilterList', '', {
		type: 'string',
		'public': true
	});
	this.add('Message_KeepHistory', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_MaxAll', 0, {
		type: 'int',
		'public': true
	});
	this.add('Message_MaxAllowedSize', 5000, {
		type: 'int',
		'public': true
	});
	this.add('Message_ShowFormattingTips', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_SetNameToAliasEnabled', false, {
		type: 'boolean',
		'public': false,
		i18nDescription: 'Message_SetNameToAliasEnabled_Description'
	});
	this.add('Message_GroupingPeriod', 300, {
		type: 'int',
		'public': true,
		i18nDescription: 'Message_GroupingPeriodDescription'
	});
	this.add('API_Embed', true, {
		type: 'boolean',
		'public': true
	});
	this.add('API_EmbedCacheExpirationDays', 30, {
		type: 'int',
		'public': false
	});
	this.add('API_Embed_clear_cache_now', 'OEmbedCacheCleanup', {
		type: 'action',
		actionText: 'clear',
		i18nLabel: 'clear_cache_now'
	});
	this.add('API_EmbedDisabledFor', '', {
		type: 'string',
		'public': true,
		i18nDescription: 'API_EmbedDisabledFor_Description'
	});
	this.add('API_EmbedIgnoredHosts', 'localhost, 127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16', {
		type: 'string',
		i18nDescription: 'API_EmbedIgnoredHosts_Description'
	});
	this.add('API_EmbedSafePorts', '80, 443', {
		type: 'string'
	});
	this.add('Message_TimeFormat', 'LT', {
		type: 'string',
		'public': true,
		i18nDescription: 'Message_TimeFormat_Description'
	});
	this.add('Message_DateFormat', 'LL', {
		type: 'string',
		'public': true,
		i18nDescription: 'Message_DateFormat_Description'
	});
	this.add('Message_TimeAndDateFormat', 'LLL', {
		type: 'string',
		'public': true,
		i18nDescription: 'Message_TimeAndDateFormat_Description'
	});
	this.add('Message_HideType_uj', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_HideType_ul', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_HideType_ru', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Message_HideType_au', false, {
		type: 'boolean',
		'public': true
	});
	return this.add('Message_HideType_mute_unmute', false, {
		type: 'boolean',
		'public': true
	});
});

RocketChat.settings.addGroup('Meta', function() {
	this.add('Meta_language', '', {
		type: 'string'
	});
	this.add('Meta_fb_app_id', '', {
		type: 'string'
	});
	this.add('Meta_robots', 'INDEX,FOLLOW', {
		type: 'string'
	});
	this.add('Meta_google-site-verification', '', {
		type: 'string'
	});
	this.add('Meta_msvalidate01', '', {
		type: 'string'
	});
	return this.add('Meta_custom', '', {
		type: 'code',
		code: 'text/html',
		multiline: true
	});
});

RocketChat.settings.addGroup('Push', function() {
	this.add('Push_enable', true, {
		type: 'boolean',
		'public': true
	});
	this.add('Push_debug', false, {
		type: 'boolean',
		'public': true,
		enableQuery: {
			_id: 'Push_enable',
			value: true
		}
	});
	this.add('Push_enable_gateway', true, {
		type: 'boolean',
		enableQuery: {
			_id: 'Push_enable',
			value: true
		}
	});
	this.add('Push_gateway', 'https://gateway.rocket.chat', {
		type: 'string',
		enableQuery: [
			{
				_id: 'Push_enable',
				value: true
			}, {
				_id: 'Push_enable_gateway',
				value: true
			}
		]
	});
	this.add('Push_production', true, {
		type: 'boolean',
		'public': true,
		enableQuery: [
			{
				_id: 'Push_enable',
				value: true
			}, {
				_id: 'Push_enable_gateway',
				value: false
			}
		]
	});
	this.add('Push_test_push', 'push_test', {
		type: 'action',
		actionText: 'Send_a_test_push_to_my_user',
		enableQuery: {
			_id: 'Push_enable',
			value: true
		}
	});
	this.section('Certificates_and_Keys', function() {
		this.add('Push_apn_passphrase', '', {
			type: 'string'
		});
		this.add('Push_apn_key', '', {
			type: 'string',
			multiline: true
		});
		this.add('Push_apn_cert', '', {
			type: 'string',
			multiline: true
		});
		this.add('Push_apn_dev_passphrase', '', {
			type: 'string'
		});
		this.add('Push_apn_dev_key', '', {
			type: 'string',
			multiline: true
		});
		this.add('Push_apn_dev_cert', '', {
			type: 'string',
			multiline: true
		});
		this.add('Push_gcm_api_key', '', {
			type: 'string'
		});
		return this.add('Push_gcm_project_number', '', {
			type: 'string',
			'public': true
		});
	});
	return this.section('Privacy', function() {
		this.add('Push_show_username_room', true, {
			type: 'boolean',
			'public': true
		});
		return this.add('Push_show_message', true, {
			type: 'boolean',
			'public': true
		});
	});
});

RocketChat.settings.addGroup('Layout', function() {
	this.section('Content', function() {
		this.add('Layout_Home_Title', 'Home', {
			type: 'string',
			'public': true
		});
		this.add('Layout_Home_Body', 'Welcome to Rocket.Chat
 Go to APP SETTINGS -> Layout to customize this intro.', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			'public': true
		});
		this.add('Layout_Terms_of_Service', 'Terms of Service
 Go to APP SETTINGS -> Layout to customize this page.', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			'public': true
		});
		this.add('Layout_Login_Terms', 'By proceeding you are agreeing to our Terms of Service and Privacy Policy.', {
			type: 'string',
			multiline: true,
			'public': true
		});
		this.add('Layout_Privacy_Policy', 'Privacy Policy
 Go to APP SETTINGS -> Layout to customize this page.', {
			type: 'code',
			code: 'text/html',
			multiline: true,
			'public': true
		});
		return this.add('Layout_Sidenav_Footer', '', {
			type: 'code',
			code: 'text/html',
			'public': true,
			i18nDescription: 'Layout_Sidenav_Footer_description'
		});
	});
	this.section('Custom_Scripts', function() {
		this.add('Custom_Script_Logged_Out', '//Add your script', {
			type: 'code',
			multiline: true,
			'public': true
		});
		return this.add('Custom_Script_Logged_In', '//Add your script', {
			type: 'code',
			multiline: true,
			'public': true
		});
	});
	return this.section('User_Interface', function() {
		this.add('UI_DisplayRoles', true, {
			type: 'boolean',
			'public': true
		});
		this.add('UI_Merge_Channels_Groups', true, {
			type: 'boolean',
			'public': true
		});
		this.add('UI_Use_Name_Avatar', false, {
			type: 'boolean',
			'public': true
		});
		this.add('UI_Use_Real_Name', false, {
			type: 'boolean',
			'public': true
		});
	});
});

RocketChat.settings.addGroup('Logs', function() {
	this.add('Log_Level', '0', {
		type: 'select',
		values: [
			{
				key: '0',
				i18nLabel: '0_Errors_Only'
			}, {
				key: '1',
				i18nLabel: '1_Errors_and_Information'
			}, {
				key: '2',
				i18nLabel: '2_Erros_Information_and_Debug'
			}
		],
		'public': true
	});
	this.add('Log_Package', false, {
		type: 'boolean',
		'public': true
	});
	this.add('Log_File', false, {
		type: 'boolean',
		'public': true
	});
	return this.add('Log_View_Limit', 1000, {
		type: 'int'
	});
});

RocketChat.settings.init();


<template name="adminSoundInfo">

			{{> soundInfo .}}

</template>


<template name="messageBox">
	{{#if subscribed}}
		<form class="message-form" method="post" action="/">
			{{> messagePopupConfig getPopupConfig}}

			{{#if allowedToSend}}

						<textarea dir="auto" name="msg" maxlength="{{maxMessageLength}}" class="message-form-text input-message autogrow-short" placeholder="{{_ 'Message'}}"></textarea>

					{{#unless showSend}}

							{{#if fileUploadEnabled}}

									<input type="file" accept="{{fileUploadAllowedMediaTypes}}">

								{{#if showMic}}

								{{/if}}

								{{#if showVRec}}

								{{/if}}

							{{/if}}

							{{#if showLocation}}

							{{/if}}

							{{#if showSandstorm}}

							{{/if}}

						{{#if groupAttachHidden}}

						{{/if}}

					{{/unless}}

					{{#if showSend}}

					{{/if}}

			{{else}}

					{{#if isBlockedOrBlocker}}
						{{_ "room_is_blocked"}}
					{{else}}
						{{_ "room_is_read_only"}}
					{{/if}}

			{{/if}}

				{{#with usersTyping}}
					{{users}}
					{{#if multi}}
						{{#if selfTyping}}
							{{_ "are_also_typing"}}
						{{else}}
							{{_ "are_typing"}}
						{{/if}}
					{{else}}
						{{#if selfTyping}}
							{{_ "is_also_typing" context="male"}}
						{{else}}
							{{_ "is_typing" context="male"}}
						{{/if}}
					{{/if}}
				{{/with}}

			{{#if allowedToSend}}
				{{#if showFormattingTips}}

						{{#if showMarkdown}}
							*{{_ "bold"}}*
							_{{_ "italics"}}_
							~{{_ "strike"}}~
						{{/if}}
						{{#if showMarkdownCode}}
							`{{_ "inline_code"}}`

```<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "multi"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>{{_ "line"}}<span class="hidden-br"><br></span><i class="icon-level-down"></i>```
						{{/if}}
						{{#if katexSyntax}}
							{{katexSyntax}}
						{{/if}}
						{{#if showMarkdown}}
							<q>
>{{_ "quote"}}</q>
						{{/if}}

				{{/if}}
			{{/if}}

{{_ 'Esc_to'}} <button type="button">{{_ 'Cancel_message_input'}}</button>

{{_ 'Enter_to'}} <button type="button">{{_ 'Save_changes'}}</button>

		</form>
	{{else}}
		{{#with notSubscribedTpl}}
			{{> Template.dynamic . }}
		{{else}}
			{{#if canJoin}}

				{{{_ "you_are_in_preview_mode_of" room_name=roomName}}}
				{{#if joinCodeRequired}}
					<input type="text" name="joinCode" placeholder="{{_ 'Code'}}" style="width: 100px">
				{{/if}}
				<button class="button join"> {{_ "join"}}</button>

			{{/if}}
			{{#if anonymousRead}}

					<button class="button register">{{_ "Sign_in_to_start_talking"}}</button>
					{{#if anonymousWrite}}
						<button class="button register-anonymous">{{_ "Or_talk_as_anonymous"}}</button>
					{{/if}}

			{{/if}}
		{{/with}}
	{{/if}}
</template>


Meteor.methods({
	openRoom(rid) {
		check(rid, String);

		if (!Meteor.userId()) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', {
				method: 'openRoom'
			});
		}

		return RocketChat.models.Subscriptions.openByRoomIdAndUserId(rid, Meteor.userId());
	}
});


type: 'string',
env: true,
i18nLabel: 'Port'
});
this.add('SMTP_Pool', true, {
type: 'boolean',
env: true,

this.add('SMTP_IgnoreTLS', false, {
type: 'boolean',
env: true,
i18nLabel: 'IgnoreTLS',
enableQuery: {
_id: 'SMTP_Protocol',
value: 'smtp'
}
});


/*globals Mailer */
Meteor.methods({
	'Mailer.sendMail'(from, subject, body, dryrun, query) {
		const userId = Meteor.userId();
		if (!userId) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', {
				method: 'Mailer.sendMail'
			});
		}
		if (RocketChat.authz.hasRole(userId, 'admin') !== true) {
			throw new Meteor.Error('error-not-allowed', 'Not allowed', {
				method: 'Mailer.sendMail'
			});
		}
		return Mailer.sendMail(from, subject, body, dryrun, query);
	}
});

//Limit setting username once per minute
//DDPRateLimiter.addRule
//	type: 'method'
//	name: 'Mailer.sendMail'
//	connectionId: -> return true
//	, 1, 60000


/* global menu */
let isLoading;
let filterText = '';
let usernamesFromClient;
let resultsFromClient;

Meteor.startup(() => {
	isLoading = new ReactiveVar(false);
});

const toolbarSearch = {
	shortcut: false,
	clear() {
		const $inputMessage = $('textarea.input-message');

		if (0 === $inputMessage.length) {
			return;
		}

		$inputMessage.focus();
		$('.toolbar-search__input').val('');

		if (this.shortcut) {
			menu.close();
		}
	},
	focus(fromShortcut) {
		menu.open();
		$('.toolbar-search__input').focus();
		this.shortcut = fromShortcut;
	}
};

this.toolbarSearch = toolbarSearch;

const getFromServer = (cb, type) => {
	isLoading.set(true);
	const currentFilter = filterText;

	Meteor.call('spotlight', currentFilter, usernamesFromClient, type, (err, results) => {
		if (currentFilter !== filterText) {
			return;
		}

		isLoading.set(false);

		if (err) {
			console.log(err);
			return false;
		}

		const resultsFromServer = [];
		const usersLength = results.users.length;
		const roomsLength = results.rooms.length;

		if (usersLength) {
			for (let i = 0; i < usersLength; i++) {
				resultsFromServer.push({
					_id: results.users[i]._id,
					t: 'd',
					name: results.users[i].username,
					fname: results.users[i].name
				});
			}
		}

		if (roomsLength) {
			for (let i = 0; i < roomsLength; i++) {
				const alreadyOnClient = resultsFromClient.find(item => item._id === results.rooms[i]._id);
				if (alreadyOnClient) {
					continue;
				}

				resultsFromServer.push({
					_id: results.rooms[i]._id,
					t: results.rooms[i].t,
					name: results.rooms[i].name
				});
			}
		}

		if (resultsFromServer.length) {
			cb(resultsFromClient.concat(resultsFromServer));
		}
	});
};

const getFromServerDebounced = _.debounce(getFromServer, 500);

Template.toolbar.helpers({
	canCreate() {
		return RocketChat.authz.hasAtLeastOnePermission(['create-c', 'create-p']);
	},
	results() {
		return Template.instance().resultsList.get();
	},
	getPlaceholder() {
		let placeholder = TAPi18n.__('Search');

		if (!Meteor.Device.isDesktop()) {
			return placeholder;
		} else if (window.navigator.platform.toLowerCase().includes('mac')) {
			placeholder = `${ placeholder } (CMD+K)`;
		} else {
			placeholder = `${ placeholder } (Ctrl+K)`;
		}

		return placeholder;
	},
	popupConfig() {
		const open = new ReactiveVar(false);

		Tracker.autorun(() => {
			if (open.get() === false) {
				toolbarSearch.clear();
			}
		});

		const config = {
			cls: 'search-results-list',
			collection: Meteor.userId() ? RocketChat.models.Subscriptions : RocketChat.models.Rooms,
			template: 'toolbarSearchList',
			emptyTemplate: 'toolbarSearchListEmpty',
			input: '.toolbar-search__input',
			cleanOnEnter: true,
			closeOnEsc: false,
			blurOnSelectItem: true,
			isLoading,
			open,
			getFilter(collection, filter, cb) {
				filterText = filter;

				const type = {
					users: true,
					rooms: true
				};

				const query = {
					rid: {
						$ne: Session.get('openedRoom')
					}
				};

				if (!Meteor.userId()) {
					query._id = query.rid;
					delete query.rid;
				}

				if (filterText[0] === '#') {
					filterText = filterText.slice(1);
					type.users = false;
					query.t = 'c';
				}

				if (filterText[0] === '@') {
					filterText = filterText.slice(1);
					type.rooms = false;
					query.t = 'd';
				}

				const searchQuery = new RegExp((RegExp.escape(filterText)), 'i');
				query.$or = [
					{ name: searchQuery },
					{ fname: searchQuery }
				];

				resultsFromClient = collection.find(query, {limit: 20, sort: {unread: -1, ls: -1}}).fetch();

				const resultsFromClientLength = resultsFromClient.length;
				const user = Meteor.user();
				if (user) {
					usernamesFromClient = [user];
				}

				for (let i = 0; i < resultsFromClientLength; i++) {
					if (resultsFromClient[i].t === 'd') {
						usernamesFromClient.push(resultsFromClient[i].name);
					}
				}

				cb(resultsFromClient);

				// Use `filter` here to get results for `#` or `@` filter only
				if (resultsFromClient.length < 20) {
					getFromServerDebounced(cb, type);
				}
			},

			getValue(_id, collection, records) {
				const doc = _.findWhere(records, {_id});

				RocketChat.roomTypes.openRouteLink(doc.t, doc, FlowRouter.current().queryParams);
				menu.close();
			}
		};

		return config;
	}
});

Template.toolbar.events({
	'keyup .toolbar-search__input'(e) {
		if (e.which === 27) {
			e.preventDefault();
			e.stopPropagation();

			toolbarSearch.clear();
		}
	},

	'click .toolbar-search__input'() {
		toolbarSearch.shortcut = false;
	},

	'click .toolbar-search__create-channel, touchend .toolbar-search__create-channel'(e) {
		if (RocketChat.authz.hasAtLeastOnePermission(['create-c', 'create-p'])) {
			SideNav.setFlex('createCombinedFlex');
			SideNav.openFlex();
		} else {
			e.preventDefault();
		}
	},

	'blur .toolbar-search__input'() {
		toolbarSearch.clear();
	}
});

Template.toolbarSearchList.helpers({
	icon() {
		return RocketChat.roomTypes.getIcon(this.t);
	},
	userStatus() {
		if (this.t === 'd') {
			return `status-${ Session.get(`user_${ this.name }_status`) || 'offline' }`;
		} else {
			return `status-${ RocketChat.roomTypes.getUserStatus(this.t, this.rid || this._id) || 'offline' }`;
		}
	},

	displayName() {
		if (RocketChat.settings.get('UI_Use_Real_Name') && this.fname) {
			return this.fname;
		} else {
			return this.name;
		}
	}
});


RocketChat.settings.addGroup('OAuth', function() {
	this.section('GitLab', function() {
		const enableQuery = {
			_id: 'Accounts_OAuth_Gitlab',
			value: true
		};

		this.add('Accounts_OAuth_Gitlab', false, { type: 'boolean', public: true });
		this.add('API_Gitlab_URL', '', { type: 'string', enableQuery, public: true });
		this.add('Accounts_OAuth_Gitlab_id', '', { type: 'string', enableQuery });
		this.add('Accounts_OAuth_Gitlab_secret', '', { type: 'string', enableQuery });
		this.add('Accounts_OAuth_Gitlab_callback_url', '_oauth/gitlab', { type: 'relativeUrl', readonly: true, force: true, enableQuery });
	});
});


process.env.MAIL_URL += `?pool=${ RocketChat.settings.get('SMTP_Pool') }`;

if (RocketChat.settings.get('SMTP_Protocol') === 'smtp' && RocketChat.settings.get('SMTP_IgnoreTLS')) {


<template name="toolbar">

				<input type="text" name="toolbar-input" class="toolbar-search__input background-transparent-light color-content-background-color border-transparent-lighter" placeholder="{{getPlaceholder}}">

			{{#if canCreate}}

			{{/if}}

		{{> messagePopup popupConfig}}

</template>

<template name="toolbarSearchList">

	{{displayName}}
	{{#if unread}}
		{{unread}}
	{{/if}}
</template>

<template name="toolbarSearchListEmpty">
	{{_ "No_results_found"}}
</template>


<template name="livechatDepartments">
	{{#requiresPermission 'view-livechat-manager'}}

						{{_ "Name"}}
						{{_ "Description"}}
						{{_ "Num_Agents"}}
						{{_ "Enabled"}}
						{{_ "Show_on_registration_page"}}
						{{_ "Delete"}}

					{{#each departments}}

							{{name}}
							{{description}}
							{{numAgents}}
							{{#if enabled}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}}
							{{#if showOnRegistration}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}}

					{{/each}}

		{{_ "New_Department"}}
	{{/requiresPermission}}
</template>


import toastr from 'toastr';

Template.channelSettings.helpers({
	toArray(obj) {
		return Object.keys(obj).map((key) => {
			return {
				$key: key,
				$value: obj[key]
			};
		});
	},
	valueOf(obj, key) {
		if (key === 't') {
			if (obj[key] === 'c') {
				return false;
			}
			return true;
		}
		return obj && obj[key];
	},
	showSetting(setting, room) {
		if (setting.showInDirect === false) {
			return room.t !== 'd';
		}
		return true;
	},
	settings() {
		return Template.instance().settings;
	},
	getRoom() {
		return ChatRoom.findOne(this.rid);
	},
	editing(field) {
		return Template.instance().editing.get() === field;
	},
	isDisabled(field, room) {
		const setting = Template.instance().settings[field];
		return (typeof setting.disabled === 'function' && setting.disabled(room)) || setting.processing.get() || !RocketChat.authz.hasAllPermission('edit-room', room._id);
	},
	channelSettings() {
		return RocketChat.ChannelSettings.getOptions(Template.currentData(), 'room');
	},
	unscape(value) {
		return s.unescapeHTML(value);
	},
	canDeleteRoom() {
		const room = ChatRoom.findOne(this.rid, {
			fields: {
				t: 1
			}
		});
		const roomType = room && room.t;
		return roomType && RocketChat.authz.hasAtLeastOnePermission(`delete-${ roomType }`, this.rid);
	},
	readOnly() {
		const room = ChatRoom.findOne(this.rid, {
			fields: {
				ro: 1
			}
		});
		return room && room.ro;
	},
	has(v, key) {
		return !!(v && v[key]);
	},
	readOnlyDescription() {
		const room = ChatRoom.findOne(this.rid, {
			fields: {
				ro: 1
			}
		});
		return t(room && room.ro ? 'True' : 'False');
	}
});

Template.channelSettings.events({
	'click .delete'() {
		return swal({
			title: t('Are_you_sure'),
			text: t('Delete_Room_Warning'),
			type: 'warning',
			showCancelButton: true,
			confirmButtonColor: '#DD6B55',
			confirmButtonText: t('Yes_delete_it'),
			cancelButtonText: t('Cancel'),
			closeOnConfirm: false,
			html: false
		}, () => {
			swal.disableButtons();
			Meteor.call('eraseRoom', this.rid, function(error) {
				if (error) {
					handleError(error);
					return swal.enableButtons();
				}
				swal({
					title: t('Deleted'),
					text: t('Room_has_been_deleted'),
					type: 'success',
					timer: 2000,
					showConfirmButton: false
				});
			});
		});
	},
	'keydown input[type=text]'(e, t) {
		if (e.keyCode === 13) {
			e.preventDefault();
			t.saveSetting();
		}
	},
	'click [data-edit]'(e, t) {
		e.preventDefault();
		if ($(e.currentTarget).data('edit')) {
			t.editing.set($(e.currentTarget).data('edit'));
			return setTimeout((function() {
				return t.$('input.editing').focus().select();
			}), 100);
		}
	},
	'change [type="radio"]'(e, t) {
		return t.editing.set($(e.currentTarget).attr('name'));
	},
	'change [type="checkbox"]'(e, t) {
		t.editing.set($(e.currentTarget).attr('name'));
		return t.saveSetting();
	},
	'click .cancel'(e, t) {
		e.preventDefault();
		return t.editing.set();
	},
	'click .save'(e, t) {
		e.preventDefault();
		return t.saveSetting();
	}
});

Template.channelSettings.onCreated(function() {
	this.editing = new ReactiveVar;
	this.settings = {
		name: {
			type: 'text',
			label: 'Name',
			canView(room) {
				return room.t !== 'd';
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('edit-room', room._id);
			},
			save(value, room) {
				let nameValidation;
				if (!RocketChat.authz.hasAllPermission('edit-room', room._id) || (room.t !== 'c' && room.t !== 'p')) {
					return toastr.error(t('error-not-allowed'));
				}
				try {
					nameValidation = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`);
				} catch (error1) {
					nameValidation = new RegExp('^[0-9a-zA-Z-_.]+$');
				}
				if (!nameValidation.test(value)) {
					return toastr.error(t('error-invalid-room-name', {
						room_name: {
							name: value
						}
					}));
				}
				Meteor.call('saveRoomSettings', room._id, 'roomName', value, function(err) {
					if (err) {
						return handleError(err);
					}
					RocketChat.callbacks.run('roomNameChanged', {
						_id: room._id,
						name: value
					});
					return toastr.success(TAPi18n.__('Room_name_changed_successfully'));
				});
			}
		},
		topic: {
			type: 'markdown',
			label: 'Topic',
			canView() {
				return true;
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('edit-room', room._id);
			},
			save(value, room) {
				return Meteor.call('saveRoomSettings', room._id, 'roomTopic', value, function(err) {
					if (err) {
						return handleError(err);
					}
					toastr.success(TAPi18n.__('Room_topic_changed_successfully'));
					return RocketChat.callbacks.run('roomTopicChanged', room);
				});
			}
		},
		announcement: {
			type: 'markdown',
			label: 'Announcement',
			canView() {
				return true;
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('edit-room', room._id);
			},
			save(value, room) {
				return Meteor.call('saveRoomSettings', room._id, 'roomAnnouncement', value, function(err) {
					if (err) {
						return handleError(err);
					}
					toastr.success(TAPi18n.__('Room_announcement_changed_successfully'));
					return RocketChat.callbacks.run('roomAnnouncementChanged', room);
				});
			}
		},
		description: {
			type: 'text',
			label: 'Description',
			canView(room) {
				return room.t !== 'd';
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('edit-room', room._id);
			},
			save(value, room) {
				return Meteor.call('saveRoomSettings', room._id, 'roomDescription', value, function(err) {
					if (err) {
						return handleError(err);
					}
					return toastr.success(TAPi18n.__('Room_description_changed_successfully'));
				});
			}
		},
		t: {
			type: 'boolean',
			label: 'Private',
			isToggle: true,
			processing: new ReactiveVar(false),
			disabled(room) {
				return room['default'] && !RocketChat.authz.hasRole(Meteor.userId(), 'admin');
			},
			message(room) {
				if (RocketChat.authz.hasAllPermission('edit-room', room._id) && room['default']) {
					if (!RocketChat.authz.hasRole(Meteor.userId(), 'admin')) {
						return 'Room_type_of_default_rooms_cant_be_changed';
					}
				}
			},
			canView(room) {
				if (['c', 'p'].includes(room.t) === false) {
					return false;
				} else if (room.t === 'p' && !RocketChat.authz.hasAllPermission('create-c')) {
					return false;
				} else if (room.t === 'c' && !RocketChat.authz.hasAllPermission('create-p')) {
					return false;
				}
				return true;
			},
			canEdit(room) {
				return (RocketChat.authz.hasAllPermission('edit-room', room._id) && !room['default']) || RocketChat.authz.hasRole(Meteor.userId(), 'admin');
			},
			save(value, room) {
				const saveRoomSettings = () => {
					this.processing.set(true);
					value = value ? 'p' : 'c';
					RocketChat.callbacks.run('roomTypeChanged', room);
					return Meteor.call('saveRoomSettings', room._id, 'roomType', value, (err) => {
						if (err) {
							return handleError(err);
						}
						this.processing.set(false);
						return toastr.success(TAPi18n.__('Room_type_changed_successfully'));
					});
				};
				if (room['default']) {
					if (RocketChat.authz.hasRole(Meteor.userId(), 'admin')) {
						swal({
							title: t('Room_default_change_to_private_will_be_default_no_more'),
							type: 'warning',
							showCancelButton: true,
							confirmButtonColor: '#DD6B55',
							confirmButtonText: t('Yes'),
							cancelButtonText: t('Cancel'),
							closeOnConfirm: true,
							html: false
						}, function(confirmed) {
							if (confirmed) {
								return saveRoomSettings();
							}
						});
					}
					return $('.channel-settings form [name=\'t\']').prop('checked', !!room.type === 'p');
				} else {
					return saveRoomSettings();
				}
			}
		},
		ro: {
			type: 'boolean',
			label: 'Read_only',
			isToggle: true,
			processing: new ReactiveVar(false),
			canView(room) {
				return room.t !== 'd';
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('set-readonly', room._id);
			},
			save(value, room) {
				this.processing.set(true);
				return Meteor.call('saveRoomSettings', room._id, 'readOnly', value, (err) => {
					if (err) {
						return handleError(err);
					}
					this.processing.set(false);
					return toastr.success(TAPi18n.__('Read_only_changed_successfully'));
				});
			}
		},
		reactWhenReadOnly: {
			type: 'boolean',
			label: 'React_when_read_only',
			isToggle: true,
			processing: new ReactiveVar(false),
			canView(room) {
				return room.t !== 'd' && room.ro;
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('set-react-when-readonly', room._id);
			},
			save(value, room) {
				this.processing.set(true);
				return Meteor.call('saveRoomSettings', room._id, 'reactWhenReadOnly', value, (err) => {
					if (err) {
						return handleError(err);
					}
					this.processing.set(false);
					return toastr.success(TAPi18n.__('React_when_read_only_changed_successfully'));
				});
			}
		},
		archived: {
			type: 'boolean',
			label: 'Room_archivation_state_true',
			isToggle: true,
			processing: new ReactiveVar(false),
			canView(room) {
				return room.t !== 'd';
			},
			canEdit(room) {
				return RocketChat.authz.hasAtLeastOnePermission(['archive-room', 'unarchive-room'], room._id);
			},
			save(value, room) {
				return swal({
					title: t('Are_you_sure'),
					type: 'warning',
					showCancelButton: true,
					confirmButtonColor: '#DD6B55',
					confirmButtonText: value ? t('Yes_archive_it') : t('Yes_unarchive_it'),
					cancelButtonText: t('Cancel'),
					closeOnConfirm: false,
					html: false
				}, function(confirmed) {
					swal.disableButtons();
					if (confirmed) {
						const action = value ? 'archiveRoom' : 'unarchiveRoom';
						return Meteor.call(action, room._id, function(err) {
							if (err) {
								swal.enableButtons();
								handleError(err);
							}
							swal({
								title: value ? t('Room_archived') : t('Room_has_been_archived'),
								text: value ? t('Room_has_been_archived') : t('Room_has_been_unarchived'),
								type: 'success',
								timer: 2000,
								showConfirmButton: false
							});
							return RocketChat.callbacks.run(action, room);
						});
					} else {
						return $('.channel-settings form [name=\'archived\']').prop('checked', !!room.archived);
					}
				});
			}
		},
		joinCode: {
			type: 'text',
			label: 'Password',
			canView(room) {
				return room.t === 'c' && RocketChat.authz.hasAllPermission('edit-room', room._id);
			},
			canEdit(room) {
				return RocketChat.authz.hasAllPermission('edit-room', room._id);
			},
			save(value, room) {
				return Meteor.call('saveRoomSettings', room._id, 'joinCode', value, function(err) {
					if (err) {
						return handleError(err);
					}
					toastr.success(TAPi18n.__('Room_password_changed_successfully'));
					return RocketChat.callbacks.run('roomCodeChanged', room);
				});
			}
		}
	};
	return this.saveSetting = () => {
		const room = ChatRoom.findOne(this.data && this.data.rid);
		const field = this.editing.get();
		let value;
		if (this.settings[field].type === 'select') {
			value = this.$(`.channel-settings form [name=${ field }]:checked`).val();
		} else if (this.settings[field].type === 'boolean') {
			value = this.$(`.channel-settings form [name=${ field }]`).is(':checked');
		} else {
			value = this.$(`.channel-settings form [name=${ field }]`).val();
		}
		if (value !== room[field]) {
			this.settings[field].save(value, room);
		}
		return this.editing.set();
	};
});


//! moment.js locale configuration
//! locale : Danish [da]
//! author : Ulrik Nielsen : https://github.com/mrbase

;(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined'
       && typeof require === 'function' ? factory(require('../moment')) :
   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
   factory(global.moment)
}(this, function (moment) { 'use strict';

    var da = moment.defineLocale('da', {
        months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
        monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
        weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
        weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
        weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
        longDateFormat : {
            LT : 'HH:mm',
            LTS : 'HH:mm:ss',
            L : 'DD/MM/YYYY',
            LL : 'D. MMMM YYYY',
            LLL : 'D. MMMM YYYY HH:mm',
            LLLL : 'dddd [d.] D. MMMM YYYY HH:mm'
        },
        calendar : {
            sameDay : '[I dag kl.] LT',
            nextDay : '[I morgen kl.] LT',
            nextWeek : 'dddd [kl.] LT',
            lastDay : '[I går kl.] LT',
            lastWeek : '[sidste] dddd [kl] LT',
            sameElse : 'L'
        },
        relativeTime : {
            future : 'om %s',
            past : '%s siden',
            s : 'få sekunder',
            m : 'et minut',
            mm : '%d minutter',
            h : 'en time',
            hh : '%d timer',
            d : 'en dag',
            dd : '%d dage',
            M : 'en måned',
            MM : '%d måneder',
            y : 'et år',
            yy : '%d år'
        },
        ordinalParse: /\d{1,2}\./,
        ordinal : '%d.',
        week : {
            dow : 1, // Monday is the first day of the week.
            doy : 4  // The week that contains Jan 4th is the first week of the year.
        }
    });

    return da;

}));


Package.describe({
	name: 'rocketchat:ui-account',
	version: '0.1.0',
	// Brief, one-line summary of the package.
	summary: '',
	// URL to the Git repository containing the source code for this package.
	git: '',
	// By default, Meteor will default to using README.md for documentation.
	// To avoid submitting documentation, set this field to null.
	documentation: 'README.md'
});

Package.onUse(function(api) {
	api.use([
		'ecmascript',
		'templating',
		'underscore',
		'rocketchat:lib',
		'sha'
	]);

	api.addFiles('client/account.html', 'client');
	api.addFiles('client/accountFlex.html', 'client');
	api.addFiles('client/accountPreferences.html', 'client');
	api.addFiles('client/accountProfile.html', 'client');
	api.addFiles('client/avatar/avatar.html', 'client');
	api.addFiles('client/avatar/prompt.html', 'client');

	api.addFiles('client/account.js', 'client');
	api.addFiles('client/accountFlex.js', 'client');
	api.addFiles('client/accountPreferences.js', 'client');
	api.addFiles('client/accountProfile.js', 'client');
	api.addFiles('client/avatar/avatar.js', 'client');
	api.addFiles('client/avatar/prompt.js', 'client');

	// api.addAssets('styles/side-nav.less', 'client');
});


BlazeLayout.setRoot('body');

FlowRouter.route '/livechat',
	name: 'index'

	triggersEnter: [
		->
			visitor.register()
	]

	action: ->
		BlazeLayout.render 'main', {center: 'livechatWindow'}


keep keep keep keep add keep keep keep keep

export const filterBusinessHoursThatMustBeOpenedByDay = async (

day: string, // Format: moment.format('dddd')

businessHour.workHours.some((workHour) => workHour.start.utc.dayOfWeek === day || workHour.finish.utc.dayOfWeek === day),

import moment from 'moment';
import type { ILivechatBusinessHour } from '@rocket.chat/core-typings';
import { LivechatBusinessHourTypes } from '@rocket.chat/core-typings';
import { LivechatBusinessHours, Users } from '@rocket.chat/models';

import { createDefaultBusinessHourRow } from '../../../models/server/models/LivechatBusinessHours';

export const filterBusinessHoursThatMustBeOpened = async (
	businessHours: ILivechatBusinessHour[],
): Promise<Pick<ILivechatBusinessHour, '_id' | 'type'>[]> => {
	const currentTime = moment(moment().format('dddd:HH:mm'), 'dddd:HH:mm');

	return businessHours
		.filter(
			(businessHour) =>
				businessHour.active &&
				businessHour.workHours
					.filter((hour) => hour.open)
					.some((hour) => {
						const localTimeStart = moment(`${hour.start.cron.dayOfWeek}:${hour.start.cron.time}`, 'dddd:HH:mm');
						const localTimeFinish = moment(`${hour.finish.cron.dayOfWeek}:${hour.finish.cron.time}`, 'dddd:HH:mm');
						return currentTime.isSameOrAfter(localTimeStart) && currentTime.isSameOrBefore(localTimeFinish);
					}),
		)
		.map((businessHour) => ({
			_id: businessHour._id,
			type: businessHour.type,
		}));
};

export const openBusinessHourDefault = async (): Promise<void> => {
	await Users.removeBusinessHoursFromAllUsers();
	const currentTime = moment(moment().format('dddd:HH:mm'), 'dddd:HH:mm');
	const day = currentTime.format('dddd');
	const activeBusinessHours = await LivechatBusinessHours.findDefaultActiveAndOpenBusinessHoursByDay(day, {
		fields: {
			workHours: 1,
			timezone: 1,
			type: 1,
			active: 1,
		},
	});
	const businessHoursToOpenIds = (await filterBusinessHoursThatMustBeOpened(activeBusinessHours)).map((businessHour) => businessHour._id);
	await Users.openAgentsBusinessHoursByBusinessHourId(businessHoursToOpenIds);
	await Users.updateLivechatStatusBasedOnBusinessHours();
};

export const createDefaultBusinessHourIfNotExists = async (): Promise<void> => {
	if ((await LivechatBusinessHours.find({ type: LivechatBusinessHourTypes.DEFAULT }).count()) === 0) {
		await LivechatBusinessHours.insertOne(createDefaultBusinessHourRow());
	}
};


import { ISetting } from '@rocket.chat/apps-engine/definition/settings';
import { Box } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import React, { FC, useMemo, useEffect, MutableRefObject } from 'react';

import { ISettings } from '../../../../app/apps/client/@types/IOrchestrator';
import { useForm } from '../../../hooks/useForm';
import AppSettingsAssembler from './AppSettingsAssembler';

type SettingsDisplayProps = {
	settings: ISettings;
	setHasUnsavedChanges: (hasUnsavedChanges: boolean) => void;
	settingsRef: MutableRefObject<Record<string, ISetting['value']>>;
};

const SettingsDisplay: FC<SettingsDisplayProps> = ({ settings, setHasUnsavedChanges, settingsRef }) => {
	const t = useTranslation();

	const stringifiedSettings = JSON.stringify(settings);

	const reducedSettings = useMemo(() => {
		const settings: SettingsDisplayProps['settings'] = JSON.parse(stringifiedSettings);
		return Object.values(settings).reduce((ret, { id, value, packageValue }) => ({ ...ret, [id]: value ?? packageValue }), {});
	}, [stringifiedSettings]);

	const { values, handlers, hasUnsavedChanges } = useForm(reducedSettings);
	const stringifiedValues = JSON.stringify(values);

	useEffect(() => {
		const values = JSON.parse(stringifiedValues);
		setHasUnsavedChanges(hasUnsavedChanges);
		settingsRef.current = values;
	}, [hasUnsavedChanges, stringifiedValues, setHasUnsavedChanges, settingsRef]);

	return (
		<>
			<Box display='flex' flexDirection='column' maxWidth='x640' w='full' marginInline='auto'>
				<Box fontScale='h4' mb='x12'>
					{t('Settings')}
				</Box>
				<AppSettingsAssembler settings={settings} values={values} handlers={handlers} />
			</Box>
		</>
	);
};

export default SettingsDisplay;


import type { ISetting } from '@rocket.chat/core-typings';
import type { AdminInfoPage, OrganizationInfoPage, RegisteredServerPage } from '@rocket.chat/onboarding-ui';
import { ComponentProps, createContext, useContext, Dispatch, SetStateAction } from 'react';

type SetupWizardData = {
	adminData: Omit<Parameters<ComponentProps<typeof AdminInfoPage>['onSubmit']>[0], 'keepPosted'>;
	organizationData: Parameters<ComponentProps<typeof OrganizationInfoPage>['onSubmit']>[0];
	serverData: Parameters<ComponentProps<typeof RegisteredServerPage>['onSubmit']>[0];
	registrationData: {
		device_code: string;
		user_code: string;
		cloudEmail: string;
		verification_url?: string;
		interval?: number;
		expires_in?: number;
	};
};

type SetupWizarContextValue = {
	setupWizardData: SetupWizardData;
	setSetupWizardData: Dispatch<SetStateAction<SetupWizardData>>;
	loaded: boolean;
	settings: Array<ISetting>;
	currentStep: number;
	validateEmail: (email: string) => string | true;
	skipCloudRegistration: boolean;
	goToPreviousStep: () => void;
	goToNextStep: () => void;
	goToStep: (step: number) => void;
	registerAdminUser: () => Promise<void>;
	registerServer: (params: { email: string; resend?: boolean }) => Promise<void>;
	saveWorkspaceData: () => Promise<void>;
	saveOrganizationData: () => Promise<void>;
	completeSetupWizard: () => Promise<void>;
	maxSteps: number;
};

export const SetupWizardContext = createContext<SetupWizarContextValue>({
	setupWizardData: {
		adminData: { fullname: '', username: '', email: '', password: '' },
		organizationData: {
			organizationName: '',
			organizationType: '',
			organizationIndustry: '',
			organizationSize: '',
			country: '',
		},
		serverData: {
			agreement: false,
			email: '',
			registerType: 'registered',
			updates: false,
		},
		registrationData: { cloudEmail: '', user_code: '', device_code: '' },
	},
	setSetupWizardData: (data) => data,
	loaded: false,
	settings: [],
	skipCloudRegistration: false,
	goToPreviousStep: () => undefined,
	goToNextStep: () => undefined,
	goToStep: () => undefined,
	registerAdminUser: async () => undefined,
	registerServer: async () => undefined,
	saveWorkspaceData: async () => undefined,
	saveOrganizationData: async () => undefined,
	validateEmail: () => true,
	currentStep: 1,
	completeSetupWizard: async () => undefined,
	maxSteps: 4,
});

export const useSetupWizardContext = (): SetupWizarContextValue => useContext(SetupWizardContext);


export { AttachmentContext, AttachmentContextValue } from './AttachmentContext';
export { AuthorizationContext, AuthorizationContextValue } from './AuthorizationContext';
export { AvatarUrlContext, AvatarUrlContextValue } from './AvatarUrlContext';
export { ConnectionStatusContext, ConnectionStatusContextValue } from './ConnectionStatusContext';
export { CustomSoundContext, CustomSoundContextValue } from './CustomSoundContext';
export { LayoutContext, LayoutContextValue } from './LayoutContext';
export { ModalContext, ModalContextValue } from './ModalContext';
export { RouterContext, RouterContextValue } from './RouterContext';
export { ServerContext, ServerContextValue } from './ServerContext';
export { SessionContext, SessionContextValue } from './SessionContext';
export { SettingsContext, SettingsContextValue, SettingsContextQuery } from './SettingsContext';
export { ToastMessagesContext, ToastMessagesContextValue } from './ToastMessagesContext';
export { TooltipContext, TooltipContextValue } from './TooltipContext';
export { TranslationContext, TranslationContextValue } from './TranslationContext';
export { UserContext, UserContextValue } from './UserContext';
export { DeviceContext, Device, IExperimentalHTMLAudioElement, DeviceContextValue } from './DeviceContext';

export { useAbsoluteUrl } from './hooks/useAbsoluteUrl';
export { useAllPermissions } from './hooks/useAllPermissions';
export { useAtLeastOnePermission } from './hooks/useAtLeastOnePermission';
export { useAttachmentAutoLoadEmbedMedia } from './hooks/useAttachmentAutoLoadEmbedMedia';
export { useAttachmentDimensions } from './hooks/useAttachmentDimensions';
export { useAttachmentIsCollapsedByDefault } from './hooks/useAttachmentIsCollapsedByDefault';
export { useConnectionStatus } from './hooks/useConnectionStatus';
export { useCurrentModal } from './hooks/useCurrentModal';
export { useCurrentRoute } from './hooks/useCurrentRoute';
export { useCustomSound } from './hooks/useCustomSound';
export { useEndpoint } from './hooks/useEndpoint';
export type { EndpointFunction } from './hooks/useEndpoint';
export { useIsPrivilegedSettingsContext } from './hooks/useIsPrivilegedSettingsContext';
export { useIsSettingsContextLoading } from './hooks/useIsSettingsContextLoading';
export { useLanguage } from './hooks/useLanguage';
export { useLanguages } from './hooks/useLanguages';
export { useLayout } from './hooks/useLayout';
export { useLayoutContextualBarExpanded } from './hooks/useLayoutContextualBarExpanded';
export { useLayoutContextualBarPosition } from './hooks/useLayoutContextualBarPosition';
export { useLayoutSizes } from './hooks/useLayoutSizes';
export { useLoadLanguage } from './hooks/useLoadLanguage';
export { useLoginWithPassword } from './hooks/useLoginWithPassword';
export { useLogout } from './hooks/useLogout';
export { useMediaUrl } from './hooks/useMediaUrl';
export { useMethod } from './hooks/useMethod';
export { useModal } from './hooks/useModal';
export { usePermission } from './hooks/usePermission';
export { useQueryStringParameter } from './hooks/useQueryStringParameter';
export { useRole } from './hooks/useRole';
export { useRolesDescription } from './hooks/useRolesDescription';
export { useRoomAvatarPath } from './hooks/useRoomAvatarPath';
export { useRoute } from './hooks/useRoute';
export { useRouteParameter } from './hooks/useRouteParameter';
export { useRoutePath } from './hooks/useRoutePath';
export { useRouteUrl } from './hooks/useRouteUrl';
export { useServerInformation } from './hooks/useServerInformation';
export { useSession } from './hooks/useSession';
export { useSessionDispatch } from './hooks/useSessionDispatch';
export { useSetModal } from './hooks/useSetModal';
export { useSetting } from './hooks/useSetting';
export { useSettings } from './hooks/useSettings';
export { useSettingsDispatch } from './hooks/useSettingsDispatch';
export { useSettingSetValue } from './hooks/useSettingSetValue';
export { useSettingStructure } from './hooks/useSettingStructure';
export { useStream } from './hooks/useStream';
export { useToastMessageDispatch } from './hooks/useToastMessageDispatch';
export { useTooltipClose } from './hooks/useTooltipClose';
export { useTooltipOpen } from './hooks/useTooltipOpen';
export { useTranslation } from './hooks/useTranslation';
export { useUpload } from './hooks/useUpload';
export { useUser } from './hooks/useUser';
export { useUserAvatarPath } from './hooks/useUserAvatarPath';
export { useUserId } from './hooks/useUserId';
export { useUserPreference } from './hooks/useUserPreference';
export { useUserRoom } from './hooks/useUserRoom';
export { useUserSubscription } from './hooks/useUserSubscription';
export { useUserSubscriptionByName } from './hooks/useUserSubscriptionByName';
export { useUserSubscriptions } from './hooks/useUserSubscriptions';
export { useSelectedDevices } from './hooks/useSelectedDevices';
export { useDeviceConstraints } from './hooks/useDeviceConstraints';
export { useAvailableDevices } from './hooks/useAvailableDevices';
export { useIsDeviceManagementEnabled } from './hooks/useIsDeviceManagementEnabled';
export { useSetOutputMediaDevice } from './hooks/useSetOutputMediaDevice';
export { useSetInputMediaDevice } from './hooks/useSetInputMediaDevice';

export { ServerMethods, ServerMethodName, ServerMethodParameters, ServerMethodReturn, ServerMethodFunction } from './ServerContext/methods';
export { UploadResult } from './ServerContext';
export { TranslationKey, TranslationLanguage } from './TranslationContext';
export { Fields } from './UserContext';

export interface ITest {
	test: string;
}