1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-23 17:02:25 +03:00

Implement local relation types filter (#2139)

This commit is contained in:
Germain
2022-01-27 17:47:05 +00:00
committed by GitHub
parent 7d2a5afa6d
commit 67d362fdd9
2 changed files with 50 additions and 6 deletions

View File

@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { RelationType } from "./@types/event";
import { UNSTABLE_FILTER_RELATION_SENDERS, UNSTABLE_FILTER_RELATION_TYPES } from "./filter"; import { UNSTABLE_FILTER_RELATION_SENDERS, UNSTABLE_FILTER_RELATION_TYPES } from "./filter";
import { MatrixEvent } from "./models/event"; import { MatrixEvent } from "./models/event";
@@ -47,6 +48,7 @@ export interface IFilterComponent {
not_senders?: string[]; not_senders?: string[];
contains_url?: boolean; contains_url?: boolean;
limit?: number; limit?: number;
[UNSTABLE_FILTER_RELATION_TYPES.name]?: Array<RelationType | string>;
} }
/* eslint-enable camelcase */ /* eslint-enable camelcase */
@@ -62,7 +64,7 @@ export interface IFilterComponent {
* @param {Object} filterJson the definition of this filter JSON, e.g. { 'contains_url': true } * @param {Object} filterJson the definition of this filter JSON, e.g. { 'contains_url': true }
*/ */
export class FilterComponent { export class FilterComponent {
constructor(private filterJson: IFilterComponent) {} constructor(private filterJson: IFilterComponent, public readonly userId?: string) {}
/** /**
* Checks with the filter component matches the given event * Checks with the filter component matches the given event
@@ -70,11 +72,24 @@ export class FilterComponent {
* @return {boolean} true if the event matches the filter * @return {boolean} true if the event matches the filter
*/ */
public check(event: MatrixEvent): boolean { public check(event: MatrixEvent): boolean {
const bundledRelationships = event.getUnsigned()?.["m.relations"] || {};
const relations: Array<string | RelationType> = Object.keys(bundledRelationships);
// Relation senders allows in theory a look-up of any senders
// however clients can only know about the current user participation status
// as sending a whole list of participants could be proven problematic in terms
// of performance
// This should be improved when bundled relationships solve that problem
const relationSenders = [];
if (this.userId && relations?.[RelationType.Thread]?.current_user_participated) {
relationSenders.push(this.userId);
}
return this.checkFields( return this.checkFields(
event.getRoomId(), event.getRoomId(),
event.getSender(), event.getSender(),
event.getType(), event.getType(),
event.getContent() ? event.getContent().url !== undefined : false, event.getContent() ? event.getContent().url !== undefined : false,
relations,
relationSenders,
); );
} }
@@ -101,9 +116,18 @@ export class FilterComponent {
* @param {String} sender the sender of 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 {String} eventType the type of the event being checked
* @param {boolean} containsUrl whether the event contains a content.url field * @param {boolean} containsUrl whether the event contains a content.url field
* @param {boolean} relationTypes whether has aggregated relation of the given type
* @param {boolean} relationSenders whether one of the relation is sent by the user listed
* @return {boolean} true if the event fields match the filter * @return {boolean} true if the event fields match the filter
*/ */
private checkFields(roomId: string, sender: string, eventType: string, containsUrl: boolean): boolean { private checkFields(
roomId: string,
sender: string,
eventType: string,
containsUrl: boolean,
relationTypes: Array<RelationType | string>,
relationSenders: string[],
): boolean {
const literalKeys = { const literalKeys = {
"rooms": function(v: string): boolean { "rooms": function(v: string): boolean {
return roomId === v; return roomId === v;
@@ -136,15 +160,35 @@ export class FilterComponent {
return false; return false;
} }
const relationTypesFilter = this.filterJson[UNSTABLE_FILTER_RELATION_TYPES.name];
if (relationTypesFilter !== undefined) {
if (!this.arrayMatchesFilter(relationTypesFilter, relationTypes)) {
return false;
}
}
const relationSendersFilter = this.filterJson[UNSTABLE_FILTER_RELATION_SENDERS.name];
if (relationSendersFilter !== undefined) {
if (!this.arrayMatchesFilter(relationSendersFilter, relationSenders)) {
return false;
}
}
return true; return true;
} }
private arrayMatchesFilter(filter: any[], values: any[]): boolean {
return values.length > 0 && values.every(value => {
return filter.includes(value);
});
}
/** /**
* Filters a list of events down to those which match this filter component * Filters a list of events down to those which match this filter component
* @param {MatrixEvent[]} events Events to be checked against the filter component * @param {MatrixEvent[]} events Events to be checked against the filter component
* @return {MatrixEvent[]} events which matched the filter component * @return {MatrixEvent[]} events which matched the filter component
*/ */
filter(events: MatrixEvent[]): MatrixEvent[] { public filter(events: MatrixEvent[]): MatrixEvent[] {
return events.filter(this.check, this); return events.filter(this.check, this);
} }
@@ -153,7 +197,7 @@ export class FilterComponent {
* 10 if none is otherwise specified. Cargo-culted from Synapse. * 10 if none is otherwise specified. Cargo-culted from Synapse.
* @return {Number} the limit for this filter component. * @return {Number} the limit for this filter component.
*/ */
limit(): number { public limit(): number {
return this.filterJson.limit !== undefined ? this.filterJson.limit : 10; return this.filterJson.limit !== undefined ? this.filterJson.limit : 10;
} }
} }

View File

@@ -185,8 +185,8 @@ export class Filter {
} }
} }
this.roomFilter = new FilterComponent(roomFilterFields); this.roomFilter = new FilterComponent(roomFilterFields, this.userId);
this.roomTimelineFilter = new FilterComponent(roomFilterJson?.timeline || {}); this.roomTimelineFilter = new FilterComponent(roomFilterJson?.timeline || {}, this.userId);
// don't bother porting this from synapse yet: // don't bother porting this from synapse yet:
// this._room_state_filter = // this._room_state_filter =