You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-29 16:43:09 +03:00
WIP filtered timelines
This commit is contained in:
119
lib/filter-component.js
Normal file
119
lib/filter-component.js
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* @module filter-component
|
||||||
|
*/
|
||||||
|
|
||||||
|
function _matches_wildcard(actual_value, filter_value) {
|
||||||
|
if (filter_value.endsWith("*")) {
|
||||||
|
type_prefix = filter_value.slice(0, -1);
|
||||||
|
return actual_value.substr(0, type_prefix.length) === type_prefix;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return actual_value === filter_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 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 from synapse's Filter object.
|
||||||
|
*/
|
||||||
|
FilterComponent = function(filter_json) {
|
||||||
|
this.filter_json = filter_json;
|
||||||
|
|
||||||
|
this.types = filter_json.types || null;
|
||||||
|
this.not_types = filter_json.not_types || [];
|
||||||
|
|
||||||
|
self.rooms = filter_json.rooms || null;
|
||||||
|
self.not_rooms = filter_json.not_rooms || [];
|
||||||
|
|
||||||
|
self.senders = filter_json.senders || null;
|
||||||
|
self.not_senders = filter_json.not_senders || [];
|
||||||
|
|
||||||
|
self.contains_url = filter_json.contains_url || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks with the filter component matches the given event
|
||||||
|
*/
|
||||||
|
FilterComponent.prototype.check = function(event) {
|
||||||
|
var sender = event.sender;
|
||||||
|
if (!sender) {
|
||||||
|
// Presence events have their 'sender' in content.user_id
|
||||||
|
if (event.content) {
|
||||||
|
sender = event.content.user_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.checkFields(
|
||||||
|
event.room_id,
|
||||||
|
sender,
|
||||||
|
event.type,
|
||||||
|
event.content ? event.content.url !== undefined : false,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the filter matches the given event fields.
|
||||||
|
*/
|
||||||
|
FilterComponent.prototype.checkFields =
|
||||||
|
function(room_id, sender, event_type, contains_url) {
|
||||||
|
var literal_keys = {
|
||||||
|
"rooms": function(v) { return room_id === v; },
|
||||||
|
"senders": function(v) { return sender === v; },
|
||||||
|
"types": function(v) { return _matches_wildcard(event_type, v); },
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(literal_keys).forEach(function(name) {
|
||||||
|
var match_func = literal_keys[name];
|
||||||
|
var not_name = "not_" + name;
|
||||||
|
var disallowed_values = this[not_name];
|
||||||
|
if (disallowed_values.map(match_func)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowed_values = this[name];
|
||||||
|
if (allowed_values) {
|
||||||
|
if (!allowed_values.map(match_func)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
contains_url_filter = this.filter_json.contains_url;
|
||||||
|
if (contains_url_filter !== undefined) {
|
||||||
|
if (contains_url_filter !== contains_url) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterComponent.prototype.filter = function(events) {
|
||||||
|
return events.filter(this.check);
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterComponent.prototype.limit = function() {
|
||||||
|
return this.filter_json.limit !== undefined ? this.filter_json.limit : 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The FilterComponent class */
|
||||||
|
module.exports = FilterComponent;
|
||||||
@@ -18,6 +18,8 @@ limitations under the License.
|
|||||||
* @module filter
|
* @module filter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var FilterComponent = require("./filter-component");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} obj
|
* @param {Object} obj
|
||||||
* @param {string} keyNesting
|
* @param {string} keyNesting
|
||||||
@@ -63,6 +65,70 @@ Filter.prototype.getDefinition = function() {
|
|||||||
*/
|
*/
|
||||||
Filter.prototype.setDefinition = function(definition) {
|
Filter.prototype.setDefinition = function(definition) {
|
||||||
this.definition = 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"]
|
||||||
|
// },
|
||||||
|
// "timeline": {
|
||||||
|
// "limit": 10,
|
||||||
|
// "types": ["m.room.message"],
|
||||||
|
// "not_rooms": ["!726s6s6q:example.com"],
|
||||||
|
// "not_senders": ["@spam:example.com"]
|
||||||
|
// },
|
||||||
|
// "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"]
|
||||||
|
// }
|
||||||
|
|
||||||
|
var room_filter_json = definition.room;
|
||||||
|
|
||||||
|
// consider the top level rooms/not_rooms filter
|
||||||
|
var 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.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 || {});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the list of events based on whether they are allowed in a timeline
|
||||||
|
* based on this filter
|
||||||
|
*/
|
||||||
|
Filter.prototype.filterRoomTimeline = function(events) {
|
||||||
|
return this._room_timeline_filter.filter(this._room_filter.filter(events));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ function EventTimeline(roomId) {
|
|||||||
this._startState.paginationToken = null;
|
this._startState.paginationToken = null;
|
||||||
this._endState = new RoomState(roomId);
|
this._endState = new RoomState(roomId);
|
||||||
this._endState.paginationToken = null;
|
this._endState.paginationToken = null;
|
||||||
|
this._filter = null;
|
||||||
|
|
||||||
this._prevTimeline = null;
|
this._prevTimeline = null;
|
||||||
this._nextTimeline = null;
|
this._nextTimeline = null;
|
||||||
@@ -58,6 +59,21 @@ EventTimeline.BACKWARDS = "b";
|
|||||||
*/
|
*/
|
||||||
EventTimeline.FORWARDS = "f";
|
EventTimeline.FORWARDS = "f";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the filter object this timeline is filtered on
|
||||||
|
*/
|
||||||
|
EventTimeline.prototype.getFilter = function() {
|
||||||
|
return this._filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the filter object this timeline is filtered on
|
||||||
|
* (passed to the server when paginating via /messages).
|
||||||
|
*/
|
||||||
|
EventTimeline.prototype.setFilter = function(filter) {
|
||||||
|
this._filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the start and end state with the given events
|
* Initialise the start and end state with the given events
|
||||||
*
|
*
|
||||||
@@ -217,6 +233,14 @@ EventTimeline.prototype.setNeighbouringTimeline = function(neighbour, direction)
|
|||||||
EventTimeline.prototype.addEvent = function(event, atStart) {
|
EventTimeline.prototype.addEvent = function(event, atStart) {
|
||||||
var stateContext = atStart ? this._startState : this._endState;
|
var stateContext = atStart ? this._startState : this._endState;
|
||||||
|
|
||||||
|
// manually filter the event if we have a filter, as currently we insert
|
||||||
|
// events incrementally only from the main /sync rather than a filtered
|
||||||
|
// /sync to avoid running multiple redundant /syncs.
|
||||||
|
if (this._filter) {
|
||||||
|
var events = this._filter.filterRoomTimeline([event]);
|
||||||
|
if (!events) return;
|
||||||
|
}
|
||||||
|
|
||||||
setEventMetadata(event, stateContext, atStart);
|
setEventMetadata(event, stateContext, atStart);
|
||||||
|
|
||||||
// modify state
|
// modify state
|
||||||
|
|||||||
Reference in New Issue
Block a user