first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,24 @@
import type { INodeProperties } from 'n8n-workflow';
export const accountOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['account'],
},
},
options: [
{
name: 'Me',
value: 'me',
description: "Get current user's account information",
action: "Get the current user's account information",
},
],
default: 'me',
},
];
@@ -0,0 +1,60 @@
import type { INodeProperties } from 'n8n-workflow';
export const eventOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['event'],
},
},
options: [
{
name: 'Get',
value: 'get',
description: 'Get single event by ID',
action: 'Get an event by ID',
},
],
default: 'get',
},
];
export const eventFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* event:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room ID',
name: 'roomId',
type: 'string',
default: '',
placeholder: '!123abc:matrix.org',
displayOptions: {
show: {
operation: ['get'],
resource: ['event'],
},
},
required: true,
description: 'The room related to the event',
},
{
displayName: 'Event ID',
name: 'eventId',
type: 'string',
default: '',
placeholder: '$1234abcd:matrix.org',
displayOptions: {
show: {
operation: ['get'],
resource: ['event'],
},
},
required: true,
description: 'The room related to the event',
},
];
@@ -0,0 +1,252 @@
import type {
IDataObject,
IExecuteFunctions,
IHttpRequestMethods,
ILoadOptionsFunctions,
IRequestOptions,
JsonObject,
} from 'n8n-workflow';
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
import { v4 as uuid } from 'uuid';
export async function matrixApiRequest(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
resource: string,
body: string | object = {},
query: IDataObject = {},
headers: IDataObject | undefined = undefined,
option: IDataObject = {},
) {
let options: IRequestOptions = {
method,
headers: headers || {
'Content-Type': 'application/json; charset=utf-8',
},
body,
qs: query,
uri: '',
json: true,
};
options = Object.assign({}, options, option);
if (Object.keys(body).length === 0) {
delete options.body;
}
if (Object.keys(query).length === 0) {
delete options.qs;
}
try {
const credentials = await this.getCredentials('matrixApi');
options.uri = `${credentials.homeserverUrl}/_matrix/${
option.overridePrefix || 'client'
}/r0${resource}`;
options.headers!.Authorization = `Bearer ${credentials.accessToken}`;
const response = await this.helpers.request(options);
// When working with images, the request cannot be JSON (it's raw binary data)
// But the output is JSON so we have to parse it manually.
//@ts-ignore
return options.overridePrefix === 'media' ? JSON.parse(response as string) : response;
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
export async function handleMatrixCall(
this: IExecuteFunctions,
index: number,
resource: string,
operation: string,
): Promise<any> {
if (resource === 'account') {
if (operation === 'me') {
return await matrixApiRequest.call(this, 'GET', '/account/whoami');
}
} else if (resource === 'room') {
if (operation === 'create') {
const name = this.getNodeParameter('roomName', index) as string;
const preset = this.getNodeParameter('preset', index) as string;
const roomAlias = this.getNodeParameter('roomAlias', index) as string;
const body: IDataObject = {
name,
preset,
};
if (roomAlias) {
body.room_alias_name = roomAlias;
}
return await matrixApiRequest.call(this, 'POST', '/createRoom', body);
} else if (operation === 'join') {
const roomIdOrAlias = this.getNodeParameter('roomIdOrAlias', index) as string;
return await matrixApiRequest.call(this, 'POST', `/rooms/${roomIdOrAlias}/join`);
} else if (operation === 'leave') {
const roomId = this.getNodeParameter('roomId', index) as string;
return await matrixApiRequest.call(this, 'POST', `/rooms/${roomId}/leave`);
} else if (operation === 'invite') {
const roomId = this.getNodeParameter('roomId', index) as string;
const userId = this.getNodeParameter('userId', index) as string;
const body: IDataObject = {
user_id: userId,
};
return await matrixApiRequest.call(this, 'POST', `/rooms/${roomId}/invite`, body);
} else if (operation === 'kick') {
const roomId = this.getNodeParameter('roomId', index) as string;
const userId = this.getNodeParameter('userId', index) as string;
const reason = this.getNodeParameter('reason', index) as string;
const body: IDataObject = {
user_id: userId,
reason,
};
return await matrixApiRequest.call(this, 'POST', `/rooms/${roomId}/kick`, body);
}
} else if (resource === 'message') {
if (operation === 'create') {
const roomId = this.getNodeParameter('roomId', index) as string;
const text = this.getNodeParameter('text', index, '') as string;
const messageType = this.getNodeParameter('messageType', index) as string;
const messageFormat = this.getNodeParameter('messageFormat', index) as string;
const body: IDataObject = {
msgtype: messageType,
body: text,
};
if (messageFormat === 'org.matrix.custom.html') {
const fallbackText = this.getNodeParameter('fallbackText', index, '') as string;
body.format = messageFormat;
body.formatted_body = text;
body.body = fallbackText;
}
const messageId = uuid();
return await matrixApiRequest.call(
this,
'PUT',
`/rooms/${roomId}/send/m.room.message/${messageId}`,
body,
);
} else if (operation === 'getAll') {
const roomId = this.getNodeParameter('roomId', index) as string;
const returnAll = this.getNodeParameter('returnAll', index);
const otherOptions = this.getNodeParameter('otherOptions', index) as IDataObject;
const returnData: IDataObject[] = [];
if (returnAll) {
let responseData;
let from;
do {
const qs: IDataObject = {
dir: 'b', // Get latest messages first - doesn't return anything if we use f without a previous token.
from,
};
if (otherOptions.filter) {
qs.filter = otherOptions.filter;
}
responseData = await matrixApiRequest.call(
this,
'GET',
`/rooms/${roomId}/messages`,
{},
qs,
);
returnData.push.apply(returnData, responseData.chunk as IDataObject[]);
from = responseData.end;
} while (responseData.chunk.length > 0);
} else {
const limit = this.getNodeParameter('limit', index);
const qs: IDataObject = {
dir: 'b', // GetfallbackText latest messages first - doesn't return anything if we use f without a previous token.
limit,
};
if (otherOptions.filter) {
qs.filter = otherOptions.filter;
}
const responseData = await matrixApiRequest.call(
this,
'GET',
`/rooms/${roomId}/messages`,
{},
qs,
);
returnData.push.apply(returnData, responseData.chunk as IDataObject[]);
}
return returnData;
}
} else if (resource === 'event') {
if (operation === 'get') {
const roomId = this.getNodeParameter('roomId', index) as string;
const eventId = this.getNodeParameter('eventId', index) as string;
return await matrixApiRequest.call(this, 'GET', `/rooms/${roomId}/event/${eventId}`);
}
} else if (resource === 'media') {
if (operation === 'upload') {
const roomId = this.getNodeParameter('roomId', index) as string;
const mediaType = this.getNodeParameter('mediaType', index) as string;
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', index);
const additionalFields = this.getNodeParameter('additionalFields', index);
let body;
const qs: IDataObject = {};
const headers: IDataObject = {};
const { fileName, mimeType } = this.helpers.assertBinaryData(index, binaryPropertyName);
body = await this.helpers.getBinaryDataBuffer(index, binaryPropertyName);
if (additionalFields.fileName) {
qs.filename = additionalFields.fileName as string;
} else {
qs.filename = fileName;
}
headers['Content-Type'] = mimeType;
headers.accept = 'application/json,text/*;q=0.99';
const uploadRequestResult = await matrixApiRequest.call(
this,
'POST',
'/upload',
body,
qs,
headers,
{
overridePrefix: 'media',
json: false,
},
);
body = {
msgtype: `m.${mediaType}`,
body: qs.filename,
url: uploadRequestResult.content_uri,
};
const messageId = uuid();
return await matrixApiRequest.call(
this,
'PUT',
`/rooms/${roomId}/send/m.room.message/${messageId}`,
body,
);
}
} else if (resource === 'roomMember') {
if (operation === 'getAll') {
const roomId = this.getNodeParameter('roomId', index) as string;
const filters = this.getNodeParameter('filters', index);
const qs: IDataObject = {
membership: filters.membership ? filters.membership : '',
not_membership: filters.notMembership ? filters.notMembership : '',
};
const roomMembersResponse = await matrixApiRequest.call(
this,
'GET',
`/rooms/${roomId}/members`,
{},
qs,
);
return roomMembersResponse.chunk;
}
}
throw new NodeOperationError(this.getNode(), 'Not implemented yet');
}
@@ -0,0 +1,25 @@
{
"node": "n8n-nodes-base.matrix",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Communication"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/matrix/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.matrix/"
}
],
"generic": [
{
"label": "How to host virtual coffee breaks with n8n",
"icon": "☕️",
"url": "https://n8n.io/blog/how-to-host-virtual-coffee-breaks-with-n8n/"
}
]
}
}
@@ -0,0 +1,162 @@
import type {
IExecuteFunctions,
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { accountOperations } from './AccountDescription';
import { eventFields, eventOperations } from './EventDescription';
import { handleMatrixCall, matrixApiRequest } from './GenericFunctions';
import { mediaFields, mediaOperations } from './MediaDescription';
import { messageFields, messageOperations } from './MessageDescription';
import { roomFields, roomOperations } from './RoomDescription';
import { roomMemberFields, roomMemberOperations } from './RoomMemberDescription';
export class Matrix implements INodeType {
description: INodeTypeDescription = {
displayName: 'Matrix',
name: 'matrix',
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
icon: 'file:matrix.png',
group: ['output'],
version: 1,
description: 'Consume Matrix API',
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
defaults: {
name: 'Matrix',
},
usableAsTool: true,
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'matrixApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Account',
value: 'account',
},
{
name: 'Event',
value: 'event',
},
{
name: 'Media',
value: 'media',
},
{
name: 'Message',
value: 'message',
},
{
name: 'Room',
value: 'room',
},
{
name: 'Room Member',
value: 'roomMember',
},
],
default: 'message',
},
...accountOperations,
...eventOperations,
...eventFields,
...mediaOperations,
...mediaFields,
...messageOperations,
...messageFields,
...roomOperations,
...roomFields,
...roomMemberOperations,
...roomMemberFields,
],
};
methods = {
loadOptions: {
async getChannels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const joinedRoomsResponse = await matrixApiRequest.call(this, 'GET', '/joined_rooms');
await Promise.all(
joinedRoomsResponse.joined_rooms.map(async (roomId: string) => {
try {
const roomNameResponse = await matrixApiRequest.call(
this,
'GET',
`/rooms/${roomId}/state/m.room.name`,
);
returnData.push({
name: roomNameResponse.name,
value: roomId,
});
} catch (error) {
// TODO: Check, there is probably another way to get the name of this private-chats
returnData.push({
name: `Unknown: ${roomId}`,
value: roomId,
});
}
}),
);
returnData.sort((a, b) => {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
});
return returnData;
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData() as IDataObject[];
const returnData: INodeExecutionData[] = [];
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
for (let i = 0; i < items.length; i++) {
try {
const responseData = await handleMatrixCall.call(this, i, resource, operation);
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
} catch (error) {
if (this.continueOnFail()) {
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push(...executionData);
continue;
}
throw error;
}
}
return [returnData];
}
}
@@ -0,0 +1,121 @@
import type { INodeProperties } from 'n8n-workflow';
export const mediaOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['media'],
},
},
options: [
{
name: 'Upload',
value: 'upload',
description: 'Send media to a chat room',
action: 'Upload media to a chatroom',
},
],
default: 'upload',
},
];
export const mediaFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* media:upload */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
default: '',
displayOptions: {
show: {
resource: ['media'],
operation: ['upload'],
},
},
description:
'Room ID to post. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
required: true,
},
{
displayName: 'Input Binary Field',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
required: true,
hint: 'The name of the input binary field containing the file to be uploaded',
displayOptions: {
show: {
resource: ['media'],
operation: ['upload'],
},
},
},
{
displayName: 'Media Type',
name: 'mediaType',
type: 'options',
default: 'image',
displayOptions: {
show: {
resource: ['media'],
operation: ['upload'],
},
},
options: [
{
name: 'File',
value: 'file',
description: 'General file',
},
{
name: 'Image',
value: 'image',
description: 'Image media type',
},
{
name: 'Audio',
value: 'audio',
description: 'Audio media type',
},
{
name: 'Video',
value: 'video',
description: 'Video media type',
},
],
description: 'Type of file being uploaded',
placeholder: 'mxc://matrix.org/uploaded-media-uri',
required: true,
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['media'],
operation: ['upload'],
},
},
options: [
{
displayName: 'File Name',
name: 'fileName',
type: 'string',
default: '',
description: 'Name of the file being uploaded',
},
],
},
];
@@ -0,0 +1,217 @@
import type { INodeProperties } from 'n8n-workflow';
export const messageOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['message'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Send a message to a room',
action: 'Create a message',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many messages from a room',
action: 'Get many messages',
},
],
default: 'create',
},
];
export const messageFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* message:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
default: '',
placeholder: '!123abc:matrix.org',
displayOptions: {
show: {
operation: ['create'],
resource: ['message'],
},
},
required: true,
description:
'The channel to send the message to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Text',
name: 'text',
type: 'string',
default: '',
placeholder: 'Hello from n8n!',
displayOptions: {
show: {
operation: ['create'],
resource: ['message'],
},
},
description: 'The text to send',
},
{
displayName: 'Message Type',
name: 'messageType',
displayOptions: {
show: {
operation: ['create'],
resource: ['message'],
},
},
type: 'options',
options: [
{
name: 'Emote',
value: 'm.emote',
description: 'Perform an action (similar to /me in IRC)',
},
{
name: 'Notice',
value: 'm.notice',
description: 'Send a notice',
},
{
name: 'Text',
value: 'm.text',
description: 'Send a text message',
},
],
default: 'm.text',
description: 'The type of message to send',
},
{
displayName: 'Message Format',
name: 'messageFormat',
displayOptions: {
show: {
operation: ['create'],
resource: ['message'],
},
},
type: 'options',
options: [
{
name: 'Plain Text',
value: 'plain',
description: 'Text only',
},
{
name: 'HTML',
value: 'org.matrix.custom.html',
description: 'HTML-formatted text',
},
],
default: 'plain',
description: "The format of the message's body",
},
{
displayName: 'Fallback Text',
name: 'fallbackText',
default: '',
displayOptions: {
show: {
resource: ['message'],
operation: ['create'],
messageFormat: ['org.matrix.custom.html'],
},
},
type: 'string',
description:
'A plain text message to display in case the HTML cannot be rendered by the Matrix client',
},
/* ----------------------------------------------------------------------- */
/* message:getAll */
/* ----------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
displayOptions: {
show: {
resource: ['message'],
operation: ['getAll'],
},
},
description:
'The token to start returning events from. This token can be obtained from a prev_batch token returned for each room by the sync API. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
displayOptions: {
show: {
resource: ['message'],
operation: ['getAll'],
},
},
description: 'Whether to return all results or only up to a given limit',
required: true,
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['message'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
maxValue: 500,
},
default: 100,
description: 'Max number of results to return',
},
{
displayName: 'Other Options',
name: 'otherOptions',
type: 'collection',
displayOptions: {
show: {
resource: ['message'],
operation: ['getAll'],
},
},
default: {},
placeholder: 'Add option',
options: [
{
displayName: 'Filter',
name: 'filter',
type: 'string',
default: '',
description:
'A JSON RoomEventFilter to filter returned events with. More information can be found on this <a href="https://matrix.org/docs/spec/client_server/r0.6.0">page</a>.',
placeholder: '{"contains_url":true,"types":["m.room.message", "m.sticker"]}',
},
],
},
];
@@ -0,0 +1,234 @@
import type { INodeProperties } from 'n8n-workflow';
export const roomOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['room'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'New chat room with defined settings',
action: 'Create a room',
},
{
name: 'Invite',
value: 'invite',
description: 'Invite a user to a room',
action: 'Invite a room',
},
{
name: 'Join',
value: 'join',
description: 'Join a new room',
action: 'Join a room',
},
{
name: 'Kick',
value: 'kick',
description: 'Kick a user from a room',
action: 'Kick a user from a room',
},
{
name: 'Leave',
value: 'leave',
description: 'Leave a room',
action: 'Leave a room',
},
],
default: 'create',
},
];
export const roomFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* room:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name',
name: 'roomName',
type: 'string',
displayOptions: {
show: {
resource: ['room'],
operation: ['create'],
},
},
default: '',
placeholder: 'My new room',
required: true,
},
{
displayName: 'Preset',
name: 'preset',
type: 'options',
displayOptions: {
show: {
resource: ['room'],
operation: ['create'],
},
},
options: [
{
name: 'Private Chat',
value: 'private_chat',
},
{
name: 'Public Chat',
value: 'public_chat',
description: 'Open and public chat',
},
],
default: 'public_chat',
placeholder: 'My new room',
required: true,
},
{
displayName: 'Room Alias',
name: 'roomAlias',
type: 'string',
displayOptions: {
show: {
resource: ['room'],
operation: ['create'],
},
},
default: '',
placeholder: 'coolest-room-around',
},
/* -------------------------------------------------------------------------- */
/* room:join */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room ID or Alias',
name: 'roomIdOrAlias',
type: 'string',
displayOptions: {
show: {
resource: ['room'],
operation: ['join'],
},
},
default: '',
required: true,
},
/* -------------------------------------------------------------------------- */
/* room:leave */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
displayOptions: {
show: {
resource: ['room'],
operation: ['leave'],
},
},
default: '',
required: true,
},
/* -------------------------------------------------------------------------- */
/* room:invite */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
displayOptions: {
show: {
resource: ['room'],
operation: ['invite'],
},
},
default: '',
required: true,
},
{
displayName: 'User ID',
name: 'userId',
type: 'string',
displayOptions: {
show: {
resource: ['room'],
operation: ['invite'],
},
},
default: '',
description: 'The fully qualified user ID of the invitee',
placeholder: '@cheeky_monkey:matrix.org',
required: true,
},
/* -------------------------------------------------------------------------- */
/* room:kick */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
displayOptions: {
show: {
resource: ['room'],
operation: ['kick'],
},
},
default: '',
required: true,
},
{
displayName: 'User ID',
name: 'userId',
type: 'string',
displayOptions: {
show: {
resource: ['room'],
operation: ['kick'],
},
},
default: '',
description: 'The fully qualified user ID',
placeholder: '@cheeky_monkey:matrix.org',
required: true,
},
{
displayName: 'Reason',
name: 'reason',
type: 'string',
displayOptions: {
show: {
resource: ['room'],
operation: ['kick'],
},
},
default: '',
description: 'Reason for kick',
placeholder: 'Telling unfunny jokes',
},
];
@@ -0,0 +1,134 @@
import type { INodeProperties } from 'n8n-workflow';
export const roomMemberOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['roomMember'],
},
},
options: [
{
name: 'Get Many',
value: 'getAll',
description: 'Get many members',
action: 'Get many room members',
},
],
default: 'getAll',
},
];
export const roomMemberFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* roomMember:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Room Name or ID',
name: 'roomId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getChannels',
},
displayOptions: {
show: {
resource: ['roomMember'],
operation: ['getAll'],
},
},
default: '',
required: true,
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
displayOptions: {
show: {
resource: ['roomMember'],
operation: ['getAll'],
},
},
default: {},
description: 'Filtering options',
placeholder: 'Add filter',
options: [
{
displayName: 'Exclude Membership',
name: 'notMembership',
type: 'options',
default: '',
description:
'Excludes members whose membership is other than selected (uses OR filter with membership)',
options: [
{
name: 'Any',
value: '',
description: 'Any user membership',
},
{
name: 'Ban',
value: 'ban',
description: 'Users removed from the room',
},
{
name: 'Invite',
value: 'invite',
description: 'Users invited to join',
},
{
name: 'Join',
value: 'join',
description: 'Users currently in the room',
},
{
name: 'Leave',
value: 'leave',
description: 'Users who left',
},
],
},
{
displayName: 'Membership',
name: 'membership',
type: 'options',
default: '',
description:
'Only fetch users with selected membership status (uses OR filter with exclude membership)',
options: [
{
name: 'Any',
value: '',
description: 'Any user membership',
},
{
name: 'Ban',
value: 'ban',
description: 'Users removed from the room',
},
{
name: 'Invite',
value: 'invite',
description: 'Users invited to join',
},
{
name: 'Join',
value: 'join',
description: 'Users currently in the room',
},
{
name: 'Leave',
value: 'leave',
description: 'Users who left',
},
],
},
],
},
];
@@ -0,0 +1,9 @@
{
"type": "object",
"properties": {
"event_id": {
"type": "string"
}
},
"version": 1
}
@@ -0,0 +1,52 @@
{
"type": "object",
"properties": {
"age": {
"type": "integer"
},
"content": {
"type": "object",
"properties": {
"body": {
"type": "string"
},
"msgtype": {
"type": "string"
}
}
},
"event_id": {
"type": "string"
},
"origin_server_ts": {
"type": "integer"
},
"room_id": {
"type": "string"
},
"sender": {
"type": "string"
},
"type": {
"type": "string"
},
"unsigned": {
"type": "object",
"properties": {
"age": {
"type": "integer"
},
"membership": {
"type": "string"
},
"transaction_id": {
"type": "string"
}
}
},
"user_id": {
"type": "string"
}
},
"version": 4
}
@@ -0,0 +1,58 @@
{
"type": "object",
"properties": {
"age": {
"type": "integer"
},
"content": {
"type": "object",
"properties": {
"avatar_url": {
"type": "string"
},
"displayname": {
"type": "string"
},
"membership": {
"type": "string"
}
}
},
"event_id": {
"type": "string"
},
"origin_server_ts": {
"type": "integer"
},
"replaces_state": {
"type": "string"
},
"room_id": {
"type": "string"
},
"sender": {
"type": "string"
},
"state_key": {
"type": "string"
},
"type": {
"type": "string"
},
"unsigned": {
"type": "object",
"properties": {
"age": {
"type": "integer"
},
"replaces_state": {
"type": "string"
}
}
},
"user_id": {
"type": "string"
}
},
"version": 1
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B