UniRef: implement DiscourseReferenceDetector (#1530)

Discourse ReferenceDetector detector that relies on database lookups.

(Should be the main way to solve #1479, when UniRef is used by all plugins)
This commit is contained in:
Robin van Boven 2020-01-11 12:59:45 +01:00 committed by GitHub
parent 5cf0fba634
commit 9e8e6845bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 176 additions and 0 deletions

View File

@ -0,0 +1,64 @@
// @flow
import type {NodeAddressT} from "../../core/graph";
import type {ReferenceDetector, URL} from "../../core/references";
import type {ReadRepository} from "./mirrorRepository";
import {topicAddress, userAddress, postAddress} from "./address";
import {linksToReferences} from "./references";
/**
* Discourse ReferenceDetector detector that relies on database lookups.
*/
export class DiscourseReferenceDetector implements ReferenceDetector {
data: ReadRepository;
constructor(data: ReadRepository) {
this.data = data;
}
addressFromUrl(url: URL): ?NodeAddressT {
const [reference] = linksToReferences([url]);
if (!reference) {
return null;
}
switch (reference.type) {
case "TOPIC": {
// Just validating the topic exists.
if (this.data.topicById(reference.topicId)) {
return topicAddress(reference.serverUrl, reference.topicId);
}
break;
}
case "POST": {
// For posts, we need to convert from topicId + index to a post ID.
// We're using it to validate the topic and post index exist as well.
const postId = this.data.findPostInTopic(
reference.topicId,
reference.postIndex
);
if (postId) {
return postAddress(reference.serverUrl, postId);
}
break;
}
case "USER": {
// Look up the username to validate it exists, and make sure we use
// the result. As this should correct our capitalization. See #1479.
const username = this.data.findUsername(reference.username);
if (username) {
return userAddress(reference.serverUrl, username);
}
break;
}
default: {
throw new Error(
`Unexpected reference type: ${(reference.type: empty)}`
);
}
}
}
}

View File

@ -0,0 +1,112 @@
// @flow
import Database from "better-sqlite3";
import type {Topic, Post} from "./fetch";
import {SqliteMirrorRepository} from "./mirrorRepository";
import {DiscourseReferenceDetector} from "./referenceDetector";
import {type NodeAddressT, NodeAddress} from "../../core/graph";
const TEST_URL = "https://example.com";
const emptyRepository = (): SqliteMirrorRepository => {
const db = new Database(":memory:");
return new SqliteMirrorRepository(db, TEST_URL);
};
const maybeToParts = (a: ?NodeAddressT) => {
return a ? NodeAddress.toParts(a) : a;
};
describe("plugins/discourse/referenceDetector", () => {
describe("DiscourseReferenceDetector", () => {
it("should detect user reference", () => {
// Given
const repo = emptyRepository();
const detector = new DiscourseReferenceDetector(repo);
const username = "PascalFan1988";
repo.addUser(username);
// When
const result = detector.addressFromUrl(`${TEST_URL}/u/pascalfan1988`);
// Then
expect(maybeToParts(result)).toMatchInlineSnapshot(`
Array [
"sourcecred",
"discourse",
"user",
"https://example.com",
"PascalFan1988",
]
`);
});
it("should detect topic reference", () => {
// Given
const repo = emptyRepository();
const detector = new DiscourseReferenceDetector(repo);
const topic: Topic = {
id: 123,
categoryId: 1,
title: "Sample topic",
timestampMs: 456789,
bumpedMs: 456999,
authorUsername: "credbot",
};
repo.addTopic(topic);
// When
const result = detector.addressFromUrl(`${TEST_URL}/t/random-slug/123`);
// Then
expect(maybeToParts(result)).toMatchInlineSnapshot(`
Array [
"sourcecred",
"discourse",
"topic",
"https://example.com",
"123",
]
`);
});
it("should detect post reference", () => {
// Given
const repo = emptyRepository();
const detector = new DiscourseReferenceDetector(repo);
const topic: Topic = {
id: 123,
categoryId: 1,
title: "Sample topic",
timestampMs: 456789,
bumpedMs: 456999,
authorUsername: "credbot",
};
const p1: Post = {
id: 100,
topicId: 123,
indexWithinTopic: 1,
replyToPostIndex: null,
timestampMs: 456789,
authorUsername: "credbot",
cooked: "<p>Valid post</p>",
};
repo.addTopic(topic);
repo.addPost(p1);
// When
const result = detector.addressFromUrl(`${TEST_URL}/t/random-slug/123/1`);
// Then
expect(maybeToParts(result)).toMatchInlineSnapshot(`
Array [
"sourcecred",
"discourse",
"post",
"https://example.com",
"100",
]
`);
});
});
});