You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-23 17:02:25 +03:00
Convert filter classes to typescript
This commit is contained in:
@@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016 OpenMarket Ltd
|
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module filter-component
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a value matches a given field value, which may be a * terminated
|
|
||||||
* wildcard pattern.
|
|
||||||
* @param {String} actual_value The value to be compared
|
|
||||||
* @param {String} filter_value The filter pattern to be compared
|
|
||||||
* @return {bool} true if the actual_value matches the filter_value
|
|
||||||
*/
|
|
||||||
function _matches_wildcard(actual_value, filter_value) {
|
|
||||||
if (filter_value.endsWith("*")) {
|
|
||||||
const type_prefix = filter_value.slice(0, -1);
|
|
||||||
return actual_value.substr(0, type_prefix.length) === type_prefix;
|
|
||||||
} else {
|
|
||||||
return actual_value === filter_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FilterComponent is a section of a Filter definition which defines the
|
|
||||||
* types, rooms, senders filters etc to be applied to a particular type of resource.
|
|
||||||
* This is all ported over from synapse's Filter object.
|
|
||||||
*
|
|
||||||
* N.B. that synapse refers to these as 'Filters', and what js-sdk refers to as
|
|
||||||
* 'Filters' are referred to as 'FilterCollections'.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @param {Object} filter_json the definition of this filter JSON, e.g. { 'contains_url': true }
|
|
||||||
*/
|
|
||||||
export function FilterComponent(filter_json) {
|
|
||||||
this.filter_json = filter_json;
|
|
||||||
|
|
||||||
this.types = filter_json.types || null;
|
|
||||||
this.not_types = filter_json.not_types || [];
|
|
||||||
|
|
||||||
this.rooms = filter_json.rooms || null;
|
|
||||||
this.not_rooms = filter_json.not_rooms || [];
|
|
||||||
|
|
||||||
this.senders = filter_json.senders || null;
|
|
||||||
this.not_senders = filter_json.not_senders || [];
|
|
||||||
|
|
||||||
this.contains_url = filter_json.contains_url || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks with the filter component matches the given event
|
|
||||||
* @param {MatrixEvent} event event to be checked against the filter
|
|
||||||
* @return {bool} true if the event matches the filter
|
|
||||||
*/
|
|
||||||
FilterComponent.prototype.check = function(event) {
|
|
||||||
return this._checkFields(
|
|
||||||
event.getRoomId(),
|
|
||||||
event.getSender(),
|
|
||||||
event.getType(),
|
|
||||||
event.getContent() ? event.getContent().url !== undefined : false,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the filter component matches the given event fields.
|
|
||||||
* @param {String} room_id the room_id for the event being checked
|
|
||||||
* @param {String} sender the sender of the event being checked
|
|
||||||
* @param {String} event_type the type of the event being checked
|
|
||||||
* @param {String} contains_url whether the event contains a content.url field
|
|
||||||
* @return {bool} true if the event fields match the filter
|
|
||||||
*/
|
|
||||||
FilterComponent.prototype._checkFields =
|
|
||||||
function(room_id, sender, event_type, contains_url) {
|
|
||||||
const literal_keys = {
|
|
||||||
"rooms": function(v) {
|
|
||||||
return room_id === v;
|
|
||||||
},
|
|
||||||
"senders": function(v) {
|
|
||||||
return sender === v;
|
|
||||||
},
|
|
||||||
"types": function(v) {
|
|
||||||
return _matches_wildcard(event_type, v);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const self = this;
|
|
||||||
for (let n=0; n < Object.keys(literal_keys).length; n++) {
|
|
||||||
const name = Object.keys(literal_keys)[n];
|
|
||||||
const match_func = literal_keys[name];
|
|
||||||
const not_name = "not_" + name;
|
|
||||||
const disallowed_values = self[not_name];
|
|
||||||
if (disallowed_values.filter(match_func).length > 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const allowed_values = self[name];
|
|
||||||
if (allowed_values && allowed_values.length > 0) {
|
|
||||||
const anyMatch = allowed_values.some(match_func);
|
|
||||||
if (!anyMatch) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const contains_url_filter = this.filter_json.contains_url;
|
|
||||||
if (contains_url_filter !== undefined) {
|
|
||||||
if (contains_url_filter !== contains_url) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters a list of events down to those which match this filter component
|
|
||||||
* @param {MatrixEvent[]} events Events to be checked againt the filter component
|
|
||||||
* @return {MatrixEvent[]} events which matched the filter component
|
|
||||||
*/
|
|
||||||
FilterComponent.prototype.filter = function(events) {
|
|
||||||
return events.filter(this.check, this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the limit field for a given filter component, providing a default of
|
|
||||||
* 10 if none is otherwise specified. Cargo-culted from Synapse.
|
|
||||||
* @return {Number} the limit for this filter component.
|
|
||||||
*/
|
|
||||||
FilterComponent.prototype.limit = function() {
|
|
||||||
return this.filter_json.limit !== undefined ? this.filter_json.limit : 10;
|
|
||||||
};
|
|
||||||
146
src/filter-component.ts
Normal file
146
src/filter-component.ts
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 - 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MatrixEvent } from "./models/event";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module filter-component
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a value matches a given field value, which may be a * terminated
|
||||||
|
* wildcard pattern.
|
||||||
|
* @param {String} actualValue The value to be compared
|
||||||
|
* @param {String} filterValue The filter pattern to be compared
|
||||||
|
* @return {bool} true if the actualValue matches the filterValue
|
||||||
|
*/
|
||||||
|
function matchesWildcard(actualValue: string, filterValue: string): boolean {
|
||||||
|
if (filterValue.endsWith("*")) {
|
||||||
|
const typePrefix = filterValue.slice(0, -1);
|
||||||
|
return actualValue.substr(0, typePrefix.length) === typePrefix;
|
||||||
|
} else {
|
||||||
|
return actualValue === filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
export interface IFilterComponent {
|
||||||
|
types?: string[];
|
||||||
|
not_types?: string[];
|
||||||
|
rooms?: string[];
|
||||||
|
not_rooms?: string[];
|
||||||
|
senders?: string[];
|
||||||
|
not_senders?: string[];
|
||||||
|
contains_url?: boolean;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FilterComponent is a section of a Filter definition which defines the
|
||||||
|
* types, rooms, senders filters etc to be applied to a particular type of resource.
|
||||||
|
* This is all ported over from synapse's Filter object.
|
||||||
|
*
|
||||||
|
* N.B. that synapse refers to these as 'Filters', and what js-sdk refers to as
|
||||||
|
* 'Filters' are referred to as 'FilterCollections'.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} filterJson the definition of this filter JSON, e.g. { 'contains_url': true }
|
||||||
|
*/
|
||||||
|
export class FilterComponent {
|
||||||
|
constructor(private filterJson: IFilterComponent) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks with the filter component matches the given event
|
||||||
|
* @param {MatrixEvent} event event to be checked against the filter
|
||||||
|
* @return {bool} true if the event matches the filter
|
||||||
|
*/
|
||||||
|
check(event: MatrixEvent): boolean {
|
||||||
|
return this.checkFields(
|
||||||
|
event.getRoomId(),
|
||||||
|
event.getSender(),
|
||||||
|
event.getType(),
|
||||||
|
event.getContent() ? event.getContent().url !== undefined : false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the filter component matches the given event fields.
|
||||||
|
* @param {String} roomId the roomId for the event being checked
|
||||||
|
* @param {String} sender the sender of the event being checked
|
||||||
|
* @param {String} eventType the type of the event being checked
|
||||||
|
* @param {boolean} containsUrl whether the event contains a content.url field
|
||||||
|
* @return {boolean} true if the event fields match the filter
|
||||||
|
*/
|
||||||
|
private checkFields(roomId: string, sender: string, eventType: string, containsUrl: boolean): boolean {
|
||||||
|
const literalKeys = {
|
||||||
|
"rooms": function(v: string): boolean {
|
||||||
|
return roomId === v;
|
||||||
|
},
|
||||||
|
"senders": function(v: string): boolean {
|
||||||
|
return sender === v;
|
||||||
|
},
|
||||||
|
"types": function(v: string): boolean {
|
||||||
|
return matchesWildcard(eventType, v);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let n = 0; n < Object.keys(literalKeys).length; n++) {
|
||||||
|
const name = Object.keys(literalKeys)[n];
|
||||||
|
const matchFunc = literalKeys[name];
|
||||||
|
const notName = "not_" + name;
|
||||||
|
const disallowedValues = this[notName];
|
||||||
|
if (disallowedValues.filter(matchFunc).length > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedValues = this[name];
|
||||||
|
if (allowedValues && allowedValues.length > 0) {
|
||||||
|
const anyMatch = allowedValues.some(matchFunc);
|
||||||
|
if (!anyMatch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const containsUrlFilter = this.filterJson.contains_url;
|
||||||
|
if (containsUrlFilter !== undefined) {
|
||||||
|
if (containsUrlFilter !== containsUrl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters a list of events down to those which match this filter component
|
||||||
|
* @param {MatrixEvent[]} events Events to be checked againt the filter component
|
||||||
|
* @return {MatrixEvent[]} events which matched the filter component
|
||||||
|
*/
|
||||||
|
filter(events: MatrixEvent[]): MatrixEvent[] {
|
||||||
|
return events.filter(this.check, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the limit field for a given filter component, providing a default of
|
||||||
|
* 10 if none is otherwise specified. Cargo-culted from Synapse.
|
||||||
|
* @return {Number} the limit for this filter component.
|
||||||
|
*/
|
||||||
|
limit(): number {
|
||||||
|
return this.filterJson.limit !== undefined ? this.filterJson.limit : 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
199
src/filter.js
199
src/filter.js
@@ -1,199 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module filter
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { FilterComponent } from "./filter-component";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} obj
|
|
||||||
* @param {string} keyNesting
|
|
||||||
* @param {*} val
|
|
||||||
*/
|
|
||||||
function setProp(obj, keyNesting, val) {
|
|
||||||
const nestedKeys = keyNesting.split(".");
|
|
||||||
let currentObj = obj;
|
|
||||||
for (let i = 0; i < (nestedKeys.length - 1); i++) {
|
|
||||||
if (!currentObj[nestedKeys[i]]) {
|
|
||||||
currentObj[nestedKeys[i]] = {};
|
|
||||||
}
|
|
||||||
currentObj = currentObj[nestedKeys[i]];
|
|
||||||
}
|
|
||||||
currentObj[nestedKeys[nestedKeys.length - 1]] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new Filter.
|
|
||||||
* @constructor
|
|
||||||
* @param {string} userId The user ID for this filter.
|
|
||||||
* @param {string=} filterId The filter ID if known.
|
|
||||||
* @prop {string} userId The user ID of the filter
|
|
||||||
* @prop {?string} filterId The filter ID
|
|
||||||
*/
|
|
||||||
export function Filter(userId, filterId) {
|
|
||||||
this.userId = userId;
|
|
||||||
this.filterId = filterId;
|
|
||||||
this.definition = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Filter.LAZY_LOADING_MESSAGES_FILTER = {
|
|
||||||
lazy_load_members: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the ID of this filter on your homeserver (if known)
|
|
||||||
* @return {?Number} The filter ID
|
|
||||||
*/
|
|
||||||
Filter.prototype.getFilterId = function() {
|
|
||||||
return this.filterId;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the JSON body of the filter.
|
|
||||||
* @return {Object} The filter definition
|
|
||||||
*/
|
|
||||||
Filter.prototype.getDefinition = function() {
|
|
||||||
return this.definition;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the JSON body of the filter
|
|
||||||
* @param {Object} definition The filter definition
|
|
||||||
*/
|
|
||||||
Filter.prototype.setDefinition = function(definition) {
|
|
||||||
this.definition = definition;
|
|
||||||
|
|
||||||
// This is all ported from synapse's FilterCollection()
|
|
||||||
|
|
||||||
// definitions look something like:
|
|
||||||
// {
|
|
||||||
// "room": {
|
|
||||||
// "rooms": ["!abcde:example.com"],
|
|
||||||
// "not_rooms": ["!123456:example.com"],
|
|
||||||
// "state": {
|
|
||||||
// "types": ["m.room.*"],
|
|
||||||
// "not_rooms": ["!726s6s6q:example.com"],
|
|
||||||
// "lazy_load_members": true,
|
|
||||||
// },
|
|
||||||
// "timeline": {
|
|
||||||
// "limit": 10,
|
|
||||||
// "types": ["m.room.message"],
|
|
||||||
// "not_rooms": ["!726s6s6q:example.com"],
|
|
||||||
// "not_senders": ["@spam:example.com"]
|
|
||||||
// "contains_url": true
|
|
||||||
// },
|
|
||||||
// "ephemeral": {
|
|
||||||
// "types": ["m.receipt", "m.typing"],
|
|
||||||
// "not_rooms": ["!726s6s6q:example.com"],
|
|
||||||
// "not_senders": ["@spam:example.com"]
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// "presence": {
|
|
||||||
// "types": ["m.presence"],
|
|
||||||
// "not_senders": ["@alice:example.com"]
|
|
||||||
// },
|
|
||||||
// "event_format": "client",
|
|
||||||
// "event_fields": ["type", "content", "sender"]
|
|
||||||
// }
|
|
||||||
|
|
||||||
const room_filter_json = definition.room;
|
|
||||||
|
|
||||||
// consider the top level rooms/not_rooms filter
|
|
||||||
const room_filter_fields = {};
|
|
||||||
if (room_filter_json) {
|
|
||||||
if (room_filter_json.rooms) {
|
|
||||||
room_filter_fields.rooms = room_filter_json.rooms;
|
|
||||||
}
|
|
||||||
if (room_filter_json.rooms) {
|
|
||||||
room_filter_fields.not_rooms = room_filter_json.not_rooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._include_leave = room_filter_json.include_leave || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._room_filter = new FilterComponent(room_filter_fields);
|
|
||||||
this._room_timeline_filter = new FilterComponent(
|
|
||||||
room_filter_json ? (room_filter_json.timeline || {}) : {},
|
|
||||||
);
|
|
||||||
|
|
||||||
// don't bother porting this from synapse yet:
|
|
||||||
// this._room_state_filter =
|
|
||||||
// new FilterComponent(room_filter_json.state || {});
|
|
||||||
// this._room_ephemeral_filter =
|
|
||||||
// new FilterComponent(room_filter_json.ephemeral || {});
|
|
||||||
// this._room_account_data_filter =
|
|
||||||
// new FilterComponent(room_filter_json.account_data || {});
|
|
||||||
// this._presence_filter =
|
|
||||||
// new FilterComponent(definition.presence || {});
|
|
||||||
// this._account_data_filter =
|
|
||||||
// new FilterComponent(definition.account_data || {});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the room.timeline filter component of the filter
|
|
||||||
* @return {FilterComponent} room timeline filter component
|
|
||||||
*/
|
|
||||||
Filter.prototype.getRoomTimelineFilterComponent = function() {
|
|
||||||
return this._room_timeline_filter;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter the list of events based on whether they are allowed in a timeline
|
|
||||||
* based on this filter
|
|
||||||
* @param {MatrixEvent[]} events the list of events being filtered
|
|
||||||
* @return {MatrixEvent[]} the list of events which match the filter
|
|
||||||
*/
|
|
||||||
Filter.prototype.filterRoomTimeline = function(events) {
|
|
||||||
return this._room_timeline_filter.filter(this._room_filter.filter(events));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the max number of events to return for each room's timeline.
|
|
||||||
* @param {Number} limit The max number of events to return for each room.
|
|
||||||
*/
|
|
||||||
Filter.prototype.setTimelineLimit = function(limit) {
|
|
||||||
setProp(this.definition, "room.timeline.limit", limit);
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.setLazyLoadMembers = function(enabled) {
|
|
||||||
setProp(this.definition, "room.state.lazy_load_members", !!enabled);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control whether left rooms should be included in responses.
|
|
||||||
* @param {boolean} includeLeave True to make rooms the user has left appear
|
|
||||||
* in responses.
|
|
||||||
*/
|
|
||||||
Filter.prototype.setIncludeLeaveRooms = function(includeLeave) {
|
|
||||||
setProp(this.definition, "room.include_leave", includeLeave);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a filter from existing data.
|
|
||||||
* @static
|
|
||||||
* @param {string} userId
|
|
||||||
* @param {string} filterId
|
|
||||||
* @param {Object} jsonObj
|
|
||||||
* @return {Filter}
|
|
||||||
*/
|
|
||||||
Filter.fromJson = function(userId, filterId, jsonObj) {
|
|
||||||
const filter = new Filter(userId, filterId);
|
|
||||||
filter.setDefinition(jsonObj);
|
|
||||||
return filter;
|
|
||||||
};
|
|
||||||
226
src/filter.ts
Normal file
226
src/filter.ts
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 - 2021 Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module filter
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FilterComponent, IFilterComponent } from "./filter-component";
|
||||||
|
import { MatrixEvent } from "./models/event";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} obj
|
||||||
|
* @param {string} keyNesting
|
||||||
|
* @param {*} val
|
||||||
|
*/
|
||||||
|
function setProp(obj: object, keyNesting: string, val: any) {
|
||||||
|
const nestedKeys = keyNesting.split(".");
|
||||||
|
let currentObj = obj;
|
||||||
|
for (let i = 0; i < (nestedKeys.length - 1); i++) {
|
||||||
|
if (!currentObj[nestedKeys[i]]) {
|
||||||
|
currentObj[nestedKeys[i]] = {};
|
||||||
|
}
|
||||||
|
currentObj = currentObj[nestedKeys[i]];
|
||||||
|
}
|
||||||
|
currentObj[nestedKeys[nestedKeys.length - 1]] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
interface IFilterDefinition {
|
||||||
|
event_fields?: string[];
|
||||||
|
event_format?: "client" | "federation";
|
||||||
|
presence?: IFilterComponent;
|
||||||
|
account_data?: IFilterComponent;
|
||||||
|
room?: IRoomFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRoomEventFilter extends IFilterComponent {
|
||||||
|
lazy_load_members?: boolean;
|
||||||
|
include_redundant_members?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStateFilter extends IRoomEventFilter {}
|
||||||
|
|
||||||
|
interface IRoomFilter {
|
||||||
|
not_rooms?: string[];
|
||||||
|
rooms?: string[];
|
||||||
|
ephemeral?: IRoomEventFilter;
|
||||||
|
include_leave?: boolean;
|
||||||
|
state?: IStateFilter;
|
||||||
|
timeline?: IRoomEventFilter;
|
||||||
|
account_data?: IRoomEventFilter;
|
||||||
|
}
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Filter.
|
||||||
|
* @constructor
|
||||||
|
* @param {string} userId The user ID for this filter.
|
||||||
|
* @param {string=} filterId The filter ID if known.
|
||||||
|
* @prop {string} userId The user ID of the filter
|
||||||
|
* @prop {?string} filterId The filter ID
|
||||||
|
*/
|
||||||
|
export class Filter {
|
||||||
|
static LAZY_LOADING_MESSAGES_FILTER = {
|
||||||
|
lazy_load_members: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a filter from existing data.
|
||||||
|
* @static
|
||||||
|
* @param {string} userId
|
||||||
|
* @param {string} filterId
|
||||||
|
* @param {Object} jsonObj
|
||||||
|
* @return {Filter}
|
||||||
|
*/
|
||||||
|
static fromJson(userId: string, filterId: string, jsonObj: IFilterDefinition): Filter {
|
||||||
|
const filter = new Filter(userId, filterId);
|
||||||
|
filter.setDefinition(jsonObj);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private definition: IFilterDefinition = {};
|
||||||
|
private roomFilter: FilterComponent;
|
||||||
|
private roomTimelineFilter: FilterComponent;
|
||||||
|
|
||||||
|
constructor(public readonly userId: string, public readonly filterId: string) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ID of this filter on your homeserver (if known)
|
||||||
|
* @return {?string} The filter ID
|
||||||
|
*/
|
||||||
|
getFilterId(): string | null {
|
||||||
|
return this.filterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the JSON body of the filter.
|
||||||
|
* @return {Object} The filter definition
|
||||||
|
*/
|
||||||
|
getDefinition(): IFilterDefinition {
|
||||||
|
return this.definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the JSON body of the filter
|
||||||
|
* @param {Object} definition The filter definition
|
||||||
|
*/
|
||||||
|
setDefinition(definition: IFilterDefinition) {
|
||||||
|
this.definition = definition;
|
||||||
|
|
||||||
|
// This is all ported from synapse's FilterCollection()
|
||||||
|
|
||||||
|
// definitions look something like:
|
||||||
|
// {
|
||||||
|
// "room": {
|
||||||
|
// "rooms": ["!abcde:example.com"],
|
||||||
|
// "not_rooms": ["!123456:example.com"],
|
||||||
|
// "state": {
|
||||||
|
// "types": ["m.room.*"],
|
||||||
|
// "not_rooms": ["!726s6s6q:example.com"],
|
||||||
|
// "lazy_load_members": true,
|
||||||
|
// },
|
||||||
|
// "timeline": {
|
||||||
|
// "limit": 10,
|
||||||
|
// "types": ["m.room.message"],
|
||||||
|
// "not_rooms": ["!726s6s6q:example.com"],
|
||||||
|
// "not_senders": ["@spam:example.com"]
|
||||||
|
// "contains_url": true
|
||||||
|
// },
|
||||||
|
// "ephemeral": {
|
||||||
|
// "types": ["m.receipt", "m.typing"],
|
||||||
|
// "not_rooms": ["!726s6s6q:example.com"],
|
||||||
|
// "not_senders": ["@spam:example.com"]
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "presence": {
|
||||||
|
// "types": ["m.presence"],
|
||||||
|
// "not_senders": ["@alice:example.com"]
|
||||||
|
// },
|
||||||
|
// "event_format": "client",
|
||||||
|
// "event_fields": ["type", "content", "sender"]
|
||||||
|
// }
|
||||||
|
|
||||||
|
const roomFilterJson = definition.room;
|
||||||
|
|
||||||
|
// consider the top level rooms/not_rooms filter
|
||||||
|
const roomFilterFields: IRoomFilter = {};
|
||||||
|
if (roomFilterJson) {
|
||||||
|
if (roomFilterJson.rooms) {
|
||||||
|
roomFilterFields.rooms = roomFilterJson.rooms;
|
||||||
|
}
|
||||||
|
if (roomFilterJson.rooms) {
|
||||||
|
roomFilterFields.not_rooms = roomFilterJson.not_rooms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.roomFilter = new FilterComponent(roomFilterFields);
|
||||||
|
this.roomTimelineFilter = new FilterComponent(
|
||||||
|
roomFilterJson ? (roomFilterJson.timeline || {}) : {},
|
||||||
|
);
|
||||||
|
|
||||||
|
// don't bother porting this from synapse yet:
|
||||||
|
// this._room_state_filter =
|
||||||
|
// new FilterComponent(roomFilterJson.state || {});
|
||||||
|
// this._room_ephemeral_filter =
|
||||||
|
// new FilterComponent(roomFilterJson.ephemeral || {});
|
||||||
|
// this._room_account_data_filter =
|
||||||
|
// new FilterComponent(roomFilterJson.account_data || {});
|
||||||
|
// this._presence_filter =
|
||||||
|
// new FilterComponent(definition.presence || {});
|
||||||
|
// this._account_data_filter =
|
||||||
|
// new FilterComponent(definition.account_data || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the room.timeline filter component of the filter
|
||||||
|
* @return {FilterComponent} room timeline filter component
|
||||||
|
*/
|
||||||
|
getRoomTimelineFilterComponent(): FilterComponent {
|
||||||
|
return this.roomTimelineFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the list of events based on whether they are allowed in a timeline
|
||||||
|
* based on this filter
|
||||||
|
* @param {MatrixEvent[]} events the list of events being filtered
|
||||||
|
* @return {MatrixEvent[]} the list of events which match the filter
|
||||||
|
*/
|
||||||
|
filterRoomTimeline(events: MatrixEvent[]): MatrixEvent[] {
|
||||||
|
return this.roomTimelineFilter.filter(this.roomFilter.filter(events));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the max number of events to return for each room's timeline.
|
||||||
|
* @param {Number} limit The max number of events to return for each room.
|
||||||
|
*/
|
||||||
|
setTimelineLimit(limit: number) {
|
||||||
|
setProp(this.definition, "room.timeline.limit", limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLazyLoadMembers(enabled: boolean) {
|
||||||
|
setProp(this.definition, "room.state.lazy_load_members", !!enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control whether left rooms should be included in responses.
|
||||||
|
* @param {boolean} includeLeave True to make rooms the user has left appear
|
||||||
|
* in responses.
|
||||||
|
*/
|
||||||
|
setIncludeLeaveRooms(includeLeave: boolean) {
|
||||||
|
setProp(this.definition, "room.include_leave", includeLeave);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user