From d7678ded299935ab56def62fcb3ba30be83590f0 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 20 Nov 2019 15:53:58 +0100 Subject: [PATCH] Discourse: remove update mode 1 --- .../__snapshots__/fetch.test.js.snap | 169 --- src/plugins/discourse/fetch.js | 48 - src/plugins/discourse/fetch.test.js | 26 - src/plugins/discourse/mirror.js | 83 +- src/plugins/discourse/mirror.test.js | 932 ++++--------- src/plugins/discourse/mirrorRepository.js | 24 - ...mdyb3VwL2xhdGVzdC5qc29uP29yZGVyPWNyZWF0ZWQ | 1191 ----------------- ...XRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLmpzb24 | 697 ---------- ...3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLzE0Lmpzb24 | 53 - .../update_discourse_api_snapshots.sh | 11 +- 10 files changed, 278 insertions(+), 2956 deletions(-) delete mode 100644 src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL2xhdGVzdC5qc29uP29yZGVyPWNyZWF0ZWQ delete mode 100644 src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLmpzb24 delete mode 100644 src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLzE0Lmpzb24 diff --git a/src/plugins/discourse/__snapshots__/fetch.test.js.snap b/src/plugins/discourse/__snapshots__/fetch.test.js.snap index f06db1c36..a102c095d 100644 --- a/src/plugins/discourse/__snapshots__/fetch.test.js.snap +++ b/src/plugins/discourse/__snapshots__/fetch.test.js.snap @@ -1,18 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`plugins/discourse/fetch snapshot testing loads a particular post from snapshot 1`] = ` -Object { - "authorUsername": "d11", - "cooked": "

This is a test post.

-

EDIT: This test post was edited on October 24, 2019.

", - "id": 14, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1564744349476, - "topicId": 11, -} -`; - exports[`plugins/discourse/fetch snapshot testing loads a particular topic from snapshot 1`] = ` Object { "posts": Array [ @@ -299,162 +286,6 @@ Needing at least > 20 posts.

", } `; -exports[`plugins/discourse/fetch snapshot testing loads latest posts from snapshot 1`] = ` -Array [ - Object { - "authorUsername": "d11", - "cooked": "

Here is a mention: @dl-proto
-Here is a topic reference: 123 a post with numbers in slug
-Here is a post reference with a slug: My First Test Post

", - "id": 29, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1571855191281, - "topicId": 21, - }, - Object { - "authorUsername": "d11", - "cooked": "

Oh the post won’t be empty I assure you.

", - "id": 28, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1570420159922, - "topicId": 20, - }, - Object { - "authorUsername": "d11", - "cooked": "

I’m replying to a wiki.

", - "id": 27, - "indexWithinTopic": 2, - "replyToPostIndex": null, - "timestampMs": 1570049836311, - "topicId": 19, - }, - Object { - "authorUsername": "d11", - "cooked": "

So I’m starting the wiki content.

-

No remove that line.

-

Ah now I’ve added another line.

", - "id": 26, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1570049491743, - "topicId": 19, - }, - Object { - "authorUsername": "d11", - "cooked": "

Testing a poll. Let’s see how it works.

-
-
-
-
    -
  • One
  • -
  • Two
  • -
  • Three
  • -
  • Four
  • -
  • Five
  • -
-
-
-

-0 -voters -

-
-
-
", - "id": 25, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1570049410625, - "topicId": 18, - }, - Object { - "authorUsername": "d11", - "cooked": "

Adding another post, after having deleted a whole thread.

", - "id": 22, - "indexWithinTopic": 3, - "replyToPostIndex": null, - "timestampMs": 1564951839667, - "topicId": 11, - }, - Object { - "authorUsername": "d11", - "cooked": " -

Excellent link. I’ve quoted you.

", - "id": 18, - "indexWithinTopic": 2, - "replyToPostIndex": null, - "timestampMs": 1564744591313, - "topicId": 13, - }, - Object { - "authorUsername": "dl-proto", - "cooked": "

Here is a link to another discourse thread: My First Test Post

-

Here is a link to a GitHub issue: https://github.com/sourcecred-test/example-github/issues/1

", - "id": 17, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1564744553905, - "topicId": 13, - }, - Object { - "authorUsername": "dl-proto", - "cooked": "

Ah, an excellent post. I will like it and reply.

", - "id": 16, - "indexWithinTopic": 2, - "replyToPostIndex": null, - "timestampMs": 1564744496285, - "topicId": 11, - }, - Object { - "authorUsername": "d11", - "cooked": "

This is a test post.

-

EDIT: This test post was edited on October 24, 2019.

", - "id": 14, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1564744349476, - "topicId": 11, - }, - Object { - "authorUsername": "system", - "cooked": "

This is a test instance.
-The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It’s important!

-

Edit this into a brief description of your community:

- -

-

You may want to close this topic via the admin \\":wrench:\\" (at the upper right and bottom), so that replies don’t pile up on an announcement.

", - "id": 10, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1554236412933, - "topicId": 7, - }, - Object { - "authorUsername": "system", - "cooked": "

Discussion about this site, its organization, how it works, and how we can improve it.

", - "id": 1, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 1554236409844, - "topicId": 1, - }, -] -`; - exports[`plugins/discourse/fetch snapshot testing loads topic IDs that are category definition topics 1`] = ` Set { 24, diff --git a/src/plugins/discourse/fetch.js b/src/plugins/discourse/fetch.js index 2f73dde22..1423427d3 100644 --- a/src/plugins/discourse/fetch.js +++ b/src/plugins/discourse/fetch.js @@ -10,7 +10,6 @@ * on the results to simplify it to data that is relevant for us. */ -import stringify from "json-stable-stringify"; import fetch from "isomorphic-fetch"; import Bottleneck from "bottleneck"; import * as NullUtil from "../../util/null"; @@ -93,27 +92,12 @@ export type LikeAction = {| * testing. */ export interface Discourse { - // Get the `id` of the latest topic on the server. - // Vital so that we can then enumerate and fetch every Topic we haven't seen yet. - // May reject on not OK status like 404 or 403. - latestTopicId(): Promise; // Retrieve the Topic with Posts for a given id. // Will resolve to null if the response status is 403 or 404. 403 because the // topic may be hidden from the API user; 404 because we sometimes see // 404s in prod and want to ignore those topic ids. (Not sure why it happens.) // May reject if the status is not OK and is not 404 or 403. topicWithPosts(id: TopicId): Promise; - // Retrieve an individual Post by its id. - // Will resolve to null if the response status is 403 or 404. 403 because the - // topic may be hidden from the API user; 404 because we sometimes see - // 404s in prod and want to ignore those topic ids. (Not sure why it happens.) - // May reject if the status is not OK and is not 404 or 403. - post(id: PostId): Promise; - // Retrieve the latest posts from the server. - // Vital so that we can then enumerate and fetch every Post that we haven't - // encountered. - // May reject on not OK status like 404 or 403. - latestPosts(): Promise; /** * Retrieves the like actions that were initiated by the target user. @@ -245,26 +229,6 @@ export class Fetcher implements Discourse { return new Set(ids); } - async latestTopicId(): Promise { - const response = await this._fetch("/latest.json?order=created"); - failIfMissing(response); - failForNotOk(response); - const json = await response.json(); - if (json.topic_list.topics.length === 0) { - throw new Error(`no topics! got ${stringify(json)} as latest topics.`); - } - - return json.topic_list.topics[0].id; - } - - async latestPosts(): Promise { - const response = await this._fetch("/posts.json"); - failIfMissing(response); - failForNotOk(response); - const json = await response.json(); - return json.latest_posts.map(parsePost); - } - async topicWithPosts(id: TopicId): Promise { const response = await this._fetch(`/t/${id}.json`); const {status} = response; @@ -300,18 +264,6 @@ export class Fetcher implements Discourse { return {topic, posts}; } - async post(id: PostId): Promise { - const response = await this._fetch(`/posts/${id}.json`); - const {status} = response; - if (status === 403 || status === 404 || status === 410) { - // The post is hidden, deleted, or otherwise missing. - return null; - } - failForNotOk(response); - const json = await response.json(); - return parsePost(json); - } - async likesByUser( username: string, offset: number diff --git a/src/plugins/discourse/fetch.test.js b/src/plugins/discourse/fetch.test.js index f19c41e5e..6d2d19d8d 100644 --- a/src/plugins/discourse/fetch.test.js +++ b/src/plugins/discourse/fetch.test.js @@ -5,22 +5,12 @@ import {options, snapshotFetcher} from "./mockSnapshotFetcher"; describe("plugins/discourse/fetch", () => { describe("snapshot testing", () => { - it("loads LatestTopicId from snapshot", async () => { - const topicId = await snapshotFetcher().latestTopicId(); - expect(topicId).toMatchInlineSnapshot(`57`); - }); - it("loads latest posts from snapshot", async () => { - expect(await snapshotFetcher().latestPosts()).toMatchSnapshot(); - }); it("loads a particular topic from snapshot", async () => { expect(await snapshotFetcher().topicWithPosts(11)).toMatchSnapshot(); }); it("loads a topic with pagination from snapshot", async () => { expect(await snapshotFetcher().topicWithPosts(26)).toMatchSnapshot(); }); - it("loads a particular post from snapshot", async () => { - expect(await snapshotFetcher().post(14)).toMatchSnapshot(); - }); it("loads user likes from snapshot", async () => { expect( await snapshotFetcher().likesByUser("dl-proto", 0) @@ -55,22 +45,8 @@ describe("plugins/discourse/fetch", () => { return result.catch((e) => expect(e.message).toMatch(String(status))); }); } - expectError("latestTopicId", (x) => x.latestTopicId(), 404); - expectError("latestTopicId", (x) => x.latestTopicId(), 403); - expectError("latestTopicId", (x) => x.latestTopicId(), 429); - - expectError("latestPosts", (x) => x.latestPosts(), 404); - expectError("latestPosts", (x) => x.latestPosts(), 403); - expectError("latestPosts", (x) => x.latestPosts(), 429); expectError("topicWithPosts", (x) => x.topicWithPosts(14), 429); - expectError("post", (x) => x.post(14), 429); - expectError( - "categoryDefinitionTopicIds", - (x) => x.categoryDefinitionTopicIds(), - 429 - ); - expectError("topicsBumpedSince", (x) => x.topicsBumpedSince(0), 429); expectError( "categoryDefinitionTopicIds", @@ -90,8 +66,6 @@ describe("plugins/discourse/fetch", () => { expectNull("topicWithPosts", (x) => x.topicWithPosts(14), 404); expectNull("topicWithPosts", (x) => x.topicWithPosts(14), 403); - expectNull("post", (x) => x.post(14), 404); - expectNull("post", (x) => x.post(14), 403); }); describe("fetch headers", () => { diff --git a/src/plugins/discourse/mirror.js b/src/plugins/discourse/mirror.js index ddad1c935..ca3f48397 100644 --- a/src/plugins/discourse/mirror.js +++ b/src/plugins/discourse/mirror.js @@ -63,8 +63,7 @@ export class Mirror { repo: MirrorRepository, fetcher: Discourse, serverUrl: string, - options?: $Shape, - mode?: number + options?: $Shape ) { this._repo = repo; this._fetcher = fetcher; @@ -73,23 +72,12 @@ export class Mirror { ...defaultOptions, ...(options || {}), }; - this._mode = mode || 2; } async update(reporter: TaskReporter) { reporter.start("discourse"); - switch (this._mode) { - case 1: - await this._updateTopics(reporter); - await this._updateLikes(reporter); - break; - case 2: - await this._updateTopicsV2(reporter); - await this._updateLikes(reporter); - break; - default: - throw new Error(`Invalid mode ${this._mode}, expecting 1 or 2`); - } + await this._updateTopicsV2(reporter); + await this._updateLikes(reporter); reporter.finish("discourse"); } @@ -176,71 +164,6 @@ export class Mirror { reporter.finish("discourse/topics"); } - async _updateTopics(reporter: TaskReporter) { - // Local functions add the warning and tracking semantics we want from them. - const encounteredPostIds = new Set(); - - const addPost = (post) => { - try { - encounteredPostIds.add(post.id); - return this._repo.addPost(post); - } catch (e) { - const url = `${this._serverUrl}/t/${post.topicId}/${post.indexWithinTopic}`; - console.warn( - `Warning: Encountered error '${e.message}' while adding post ${url}.` - ); - return {changes: 0, lastInsertRowid: -1}; - } - }; - - const { - maxPostId: lastLocalPostId, - maxTopicId: lastLocalTopicId, - } = this._repo.maxIds(); - - reporter.start("discourse/topics"); - const latestTopicId = await this._fetcher.latestTopicId(); - for ( - let topicId = lastLocalTopicId + 1; - topicId <= latestTopicId; - topicId++ - ) { - const topicWithPosts = await this._fetcher.topicWithPosts(topicId); - if (topicWithPosts != null) { - const {topic, posts} = topicWithPosts; - // TODO: Quick hack, as TopicView does not include bumpedMs. - // This should be resolved in the new sync logic. - const workaroundTopic: Topic = {...topic, bumpedMs: topic.timestampMs}; - this._repo.addTopic(workaroundTopic); - for (const post of posts) { - addPost(post); - } - } - } - reporter.finish("discourse/topics"); - - reporter.start("discourse/posts"); - const latestPosts = await this._fetcher.latestPosts(); - for (const post of latestPosts) { - if (!encounteredPostIds.has(post.id) && post.id > lastLocalPostId) { - addPost(post); - } - } - - const latestPost = latestPosts[0]; - const latestPostId = latestPost == null ? 0 : latestPost.id; - for (let postId = lastLocalPostId + 1; postId <= latestPostId; postId++) { - if (encounteredPostIds.has(postId)) { - continue; - } - const post = await this._fetcher.post(postId); - if (post != null) { - addPost(post); - } - } - reporter.finish("discourse/posts"); - } - async _updateLikes(reporter: TaskReporter) { const addLike = (like) => { try { diff --git a/src/plugins/discourse/mirror.test.js b/src/plugins/discourse/mirror.test.js index b7880e268..e3649cd81 100644 --- a/src/plugins/discourse/mirror.test.js +++ b/src/plugins/discourse/mirror.test.js @@ -46,22 +46,6 @@ class MockFetcher implements Discourse { this._likes = []; } - async latestTopicId(): Promise { - return this._latestTopicId; - } - - async latestPosts(): Promise { - const latestPost = this._post(this._latestPostId - 1); - if (latestPost == null) { - return []; - } - return [latestPost]; - } - - async post(id: PostId): Promise { - return this._post(id); - } - async topicWithPosts(id: TopicId): Promise { const postIds = this._topicToPostIds.get(id); if (postIds == null || postIds.length === 0) { @@ -246,14 +230,6 @@ class MockFetcher implements Discourse { } } -function normalizeMode1Topics(topics: Topic[]): Topic[] { - return topics.map((topic) => ({ - ...topic, - // Mode 1 didn't support bumpMs handling. - bumpedMs: topic.timestampMs, - })); -} - describe("plugins/discourse/mirror", () => { function spyWarn(): JestMockFn<[string], void> { return ((console.warn: any): JestMockFn); @@ -269,7 +245,7 @@ describe("plugins/discourse/mirror", () => { } }); - const exampleMode = (mode: number) => ( + const exampleMode = (_: number) => ( optionOverrides?: $Shape ) => { // Explicitly set all options, so we know what to expect in tests. @@ -281,380 +257,14 @@ describe("plugins/discourse/mirror", () => { const db = new Database(":memory:"); const url = "http://example.com"; const repo = new SqliteMirrorRepository(db, url); - const mirror = new Mirror( - repo, - fetcher, - url, - { - ...options, - ...(optionOverrides || {}), - }, - mode - ); + const mirror = new Mirror(repo, fetcher, url, { + ...options, + ...(optionOverrides || {}), + }); const reporter = new TestTaskReporter(); return {fetcher, mirror, reporter, url, repo}; }; - describe("mirror mode 1", () => { - const example = exampleMode(1); - it("mirrors topics from the fetcher", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(2, null); - fetcher.addPost(3, null); - const topic2 = fetcher._topic(2); - const topic3 = fetcher._topic(3); - await mirror.update(reporter); - expect(repo.topics()).toEqual(normalizeMode1Topics([topic2, topic3])); - }); - - it("mirrors posts from the fetcher", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const p1 = fetcher.addPost(2, null); - const p2 = fetcher.addPost(3, null); - const p3 = fetcher.addPost(3, 1); - await mirror.update(reporter); - const posts = [fetcher._post(p1), fetcher._post(p2), fetcher._post(p3)]; - expect(repo.posts()).toEqual(posts); - }); - - it("provides usernames for all active users", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(2, null, "alpha"); - fetcher.addPost(3, null, "beta"); - fetcher.addPost(3, 1, "alpha"); - await mirror.update(reporter); - // credbot appears because it is the nominal author of all topics - expect( - repo - .users() - .slice() - .sort() - ).toEqual(["alpha", "beta", "credbot"]); - }); - - function expectLikesSorted(as, bs) { - const s = (ls) => - sortBy( - ls, - (x) => x.username, - (x) => x.postId - ); - expect(s(as)).toEqual(s(bs)); - } - - it("provides all the likes by users that have posted", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null, "alpha"); - fetcher.addPost(2, null, "alpha"); - fetcher.addPost(3, null, "beta"); - const l1 = fetcher.addLike("beta", 1, 5); - const l2 = fetcher.addLike("beta", 2, 6); - const l3 = fetcher.addLike("beta", 3, 7); - const l4 = fetcher.addLike("alpha", 1, 8); - await mirror.update(reporter); - expectLikesSorted(repo.likes(), [l1, l2, l3, l4]); - const l5 = fetcher.addLike("alpha", 2, 9); - fetcher.addPost(4, null, "credbot"); - const l6 = fetcher.addLike("credbot", 2, 10); - const l7 = fetcher.addLike("beta", 4, 11); - await mirror.update(reporter); - expectLikesSorted(repo.likes(), [l1, l2, l3, l4, l5, l6, l7]); - }); - - it("doesn't find likes of users that never posted", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addLike("nope", 1, 1); - await mirror.update(reporter); - expect(repo.likes()).toEqual([]); - }); - - it("only fetches new topics on `update`", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addPost(2, null); - await mirror.update(reporter); - fetcher.addPost(3, null); - const fetchTopicWithPosts = jest.spyOn(fetcher, "topicWithPosts"); - await mirror.update(reporter); - expect(fetchTopicWithPosts).toHaveBeenCalledTimes(1); - expect(fetchTopicWithPosts).toHaveBeenCalledWith(3); - expect(repo.topics().map((x) => x.id)).toEqual([1, 2, 3]); - }); - - it("gets new posts on old topics on update", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addPost(2, null); - await mirror.update(reporter); - const id = fetcher.addPost(1, 1); - fetcher.addPost(3, null); - await mirror.update(reporter); - const latestPosts = await fetcher.latestPosts(); - // The post added to the old topic wasn't retrieved by latest post - expect(latestPosts.map((x) => x.id)).not.toContain(id); - const allPostIds = repo.posts().map((x) => x.id); - // The post was still included, meaning the mirror scanned for new posts by id - expect(allPostIds).toContain(id); - }); - - it("skips null/missing topics", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addPost(3, null); - await mirror.update(reporter); - expect(repo.topics().map((x) => x.id)).toEqual([1, 3]); - }); - - it("skips null/missing posts", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const p1 = fetcher.addPost(1, null); - fetcher._latestPostId += 2; - const p2 = fetcher.addPost(3, null); - await mirror.update(reporter); - expect(repo.posts().map((x) => x.id)).toEqual([p1, p2]); - }); - - it("queries explicitly for posts that are not present in topicWithPosts.posts", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const p1 = fetcher.addPost(1, null); - const p2 = fetcher.addPost(1, 1); - const p3 = fetcher.addPost(1, 1); - const fetchPost = jest.spyOn(fetcher, "post"); - await mirror.update(reporter); - const getId = (x) => x.id; - - const postsFromTopic = NullUtil.get(await fetcher.topicWithPosts(1)) - .posts; - expect(postsFromTopic.map(getId)).toEqual([p1, p2, p3]); - - const postsFromLatest = await fetcher.latestPosts(); - expect(postsFromLatest.map(getId)).toEqual([p3]); - - expect(fetchPost).toHaveBeenCalledTimes(0); - - expect(repo.posts().map(getId)).toEqual([p1, p2, p3]); - }); - - it("does not explicitly query for posts that were in topicWithPosts.posts", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null); - const fetchPost = jest.spyOn(fetcher, "post"); - await mirror.update(reporter); - expect(fetchPost).not.toHaveBeenCalled(); - }); - - it("does not explicitly query for posts that were provided in latest posts", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - await mirror.update(reporter); - const id = fetcher.addPost(1, 1); - const fetchPost = jest.spyOn(fetcher, "post"); - await mirror.update(reporter); - expect(fetchPost).not.toHaveBeenCalled(); - expect(repo.posts().map((x) => x.id)).toContain(id); - }); - - it("does not query for topics at all if there were no new topics", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null); - await mirror.update(reporter); - const fetchTopic = jest.spyOn(fetcher, "topicWithPosts"); - await mirror.update(reporter); - expect(fetchTopic).not.toHaveBeenCalled(); - }); - - it("queries for likes for every user", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "alpha"); - const fetchLikes = jest.spyOn(fetcher, "likesByUser"); - await mirror.update(reporter); - expect(fetchLikes).toHaveBeenCalledTimes(2); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); - expect(fetchLikes).toHaveBeenCalledWith("alpha", 0); - }); - - it("queries with offset, as needed", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "credbot"); - fetcher.addPost(2, null, "credbot"); - fetcher.addPost(3, null, "credbot"); - fetcher.addLike("credbot", 1, 1); - fetcher.addLike("credbot", 2, 2); - fetcher.addLike("credbot", 3, 3); - const fetchLikes = jest.spyOn(fetcher, "likesByUser"); - await mirror.update(reporter); - expect(fetchLikes).toHaveBeenCalledTimes(2); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 2); - }); - - it("ceases querying once it has found all the new likes", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "credbot"); - fetcher.addPost(2, null, "credbot"); - fetcher.addPost(3, null, "credbot"); - fetcher.addLike("credbot", 1, 1); - fetcher.addLike("credbot", 2, 2); - await mirror.update(reporter); - fetcher.addLike("credbot", 3, 3); - const fetchLikes = jest.spyOn(fetcher, "likesByUser"); - await mirror.update(reporter); - expect(fetchLikes).toHaveBeenCalledTimes(1); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); - }); - - it("warns if one of the latest posts has no topic", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const pid1 = fetcher.addPost(1, null, "credbot"); - const pid2 = fetcher.addPost(2, null, "credbot"); - // Verify that the problem post is one of the latest posts - const latestPostIds = (await fetcher.latestPosts()).map((x) => x.id); - expect(latestPostIds).toContain(pid2); - // Force the fetcher not to return topic 2 - fetcher._latestTopicId--; - await mirror.update(reporter); - const topics = normalizeMode1Topics([fetcher._topic(1)]); - expect(repo.topics()).toEqual(topics); - const posts = [fetcher._post(pid1)]; - expect(repo.posts()).toEqual(posts); - expect(console.warn).toHaveBeenCalledWith( - "Warning: Encountered error 'FOREIGN KEY constraint failed' " + - "while adding post http://example.com/t/2/1." - ); - expect(console.warn).toHaveBeenCalledTimes(1); - spyWarn().mockReset(); - }); - - it("warns if it finds a (non-latest) post with no topic", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const pid1 = fetcher.addPost(1, null, "credbot"); - const pid2 = fetcher.addPost(2, null, "credbot"); - const pid3 = fetcher.addPost(1, null, "credbot"); - // Verify that the problem post is not one of the latest posts - const latestPostIds = (await fetcher.latestPosts()).map((x) => x.id); - expect(latestPostIds).not.toContain(pid2); - // Force the fetcher not to return topic 2 - fetcher._latestTopicId--; - await mirror.update(reporter); - const topics = normalizeMode1Topics([fetcher._topic(1)]); - expect(repo.topics()).toEqual(topics); - const posts = [pid1, pid3].map((x) => fetcher._post(x)); - expect(repo.posts()).toEqual(posts); - expect(console.warn).toHaveBeenCalledWith( - "Warning: Encountered error 'FOREIGN KEY constraint failed' " + - "while adding post http://example.com/t/2/1." - ); - expect(console.warn).toHaveBeenCalledTimes(1); - spyWarn().mockReset(); - }); - - it("warns if it gets a like that doesn't correspond to any post", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const pid = fetcher.addPost(1, null, "credbot"); - const badLike = {username: "credbot", postId: 37, timestampMs: 0}; - fetcher._likes.push(badLike); - await mirror.update(reporter); - const topics = normalizeMode1Topics([fetcher._topic(1)]); - expect(repo.topics()).toEqual(topics); - expect(repo.posts()).toEqual([fetcher._post(pid)]); - expect(repo.likes()).toEqual([]); - expect(console.warn).toHaveBeenCalledWith( - "Warning: Encountered error 'FOREIGN KEY constraint failed' " + - "on a like by credbot on post id 37." - ); - expect(console.warn).toHaveBeenCalledTimes(1); - spyWarn().mockReset(); - }); - - it("warns if a user's likes are missing", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const pid = fetcher.addPost(1, null, "credbot"); - (fetcher: any).likesByUser = async () => null; - await mirror.update(reporter); - expect(repo.topics()).toEqual(normalizeMode1Topics([fetcher._topic(1)])); - expect(repo.posts()).toEqual([fetcher._post(pid)]); - expect(repo.likes()).toEqual([]); - }); - - it("inserts other likes if one user's likes are missing", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const p1 = fetcher.addPost(1, null, "credbot"); - const p2 = fetcher.addPost(1, 1, "otheruser"); - const l1 = fetcher.addLike("otheruser", 1, 123); - const _likesByUser = fetcher.likesByUser.bind(fetcher); - (fetcher: any).likesByUser = async ( - targetUsername: string, - offset: number - ) => { - if (targetUsername == "credbot") return null; - return await _likesByUser(targetUsername, offset); - }; - await mirror.update(reporter); - expect(repo.topics()).toEqual(normalizeMode1Topics([fetcher._topic(1)])); - expect(repo.posts()).toEqual([fetcher._post(p1), fetcher._post(p2)]); - expect(repo.likes()).toEqual([l1]); - }); - - it("sends the right tasks to the TaskReporter", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "credbot"); - await mirror.update(reporter); - expect(reporter.activeTasks()).toEqual([]); - expect(reporter.entries()).toEqual([ - {type: "START", taskId: "discourse"}, - {type: "START", taskId: "discourse/topics"}, - {type: "FINISH", taskId: "discourse/topics"}, - {type: "START", taskId: "discourse/posts"}, - {type: "FINISH", taskId: "discourse/posts"}, - {type: "START", taskId: "discourse/likes"}, - {type: "FINISH", taskId: "discourse/likes"}, - {type: "FINISH", taskId: "discourse"}, - ]); - }); - - describe("findPostInTopic", () => { - it("works for the first post in a topic", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const id = fetcher.addPost(5, null); - const post = NullUtil.get(fetcher._post(id)); - expect(post.topicId).toEqual(5); - expect(post.indexWithinTopic).toEqual(1); - await mirror.update(reporter); - expect(repo.findPostInTopic(5, 1)).toEqual(id); - }); - - it("works for the second post in a topic", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - const id = fetcher.addPost(1, 1); - const post = NullUtil.get(fetcher._post(id)); - expect(post.indexWithinTopic).toEqual(2); - await mirror.update(reporter); - expect(repo.findPostInTopic(1, 2)).toEqual(id); - }); - - it("returns undefined for a post with too high an index", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - await mirror.update(reporter); - expect(repo.findPostInTopic(1, 2)).toBe(undefined); - }); - - it("returns undefined for topic that doesnt exist", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - await mirror.update(reporter); - expect(repo.findPostInTopic(2, 1)).toBe(undefined); - }); - - it("returns undefined for a mirror that never updated", async () => { - const {repo} = example(); - expect(repo.findPostInTopic(1, 1)).toBe(undefined); - }); - }); - }); - describe("mirror mode 2", () => { const example = exampleMode(2); it("mirrors topics from the fetcher", async () => { @@ -813,304 +423,306 @@ describe("plugins/discourse/mirror", () => { expect(repo.likes()).toEqual([]); }); - it("mirrors category definition topics only after it's interval", async () => { - const {mirror, fetcher, reporter, repo} = example(); - - fetcher.addCategory(4); - const topic4 = fetcher._categoryDefinitionTopic(4); - await mirror.update(reporter); - const firstTopics = repo.topics(); + describe("update semantics", () => { + it("mirrors category definition topics only after it's interval", async () => { + const {mirror, fetcher, reporter, repo} = example(); - fetcher.addCategory(5); - await mirror.update(reporter); - const laterTopics = repo.topics(); + fetcher.addCategory(4); + const topic4 = fetcher._categoryDefinitionTopic(4); + await mirror.update(reporter); + const firstTopics = repo.topics(); - expect(firstTopics).toEqual([topic4]); - expect(laterTopics).toEqual([topic4]); - }); + fetcher.addCategory(5); + await mirror.update(reporter); + const laterTopics = repo.topics(); - it("mirrors respects recheckCategoryDefinitionsAfterMs option", async () => { - const {mirror, fetcher, reporter, repo} = example({ - recheckCategoryDefinitionsAfterMs: 0, + expect(firstTopics).toEqual([topic4]); + expect(laterTopics).toEqual([topic4]); }); - fetcher.addCategory(4); - const topic4 = fetcher._categoryDefinitionTopic(4); - await mirror.update(reporter); - const firstTopics = repo.topics(); + it("mirrors respects recheckCategoryDefinitionsAfterMs option", async () => { + const {mirror, fetcher, reporter, repo} = example({ + recheckCategoryDefinitionsAfterMs: 0, + }); - fetcher.addCategory(5); - const topic5 = fetcher._categoryDefinitionTopic(5); - await mirror.update(reporter); - const laterTopics = repo.topics(); + fetcher.addCategory(4); + const topic4 = fetcher._categoryDefinitionTopic(4); + await mirror.update(reporter); + const firstTopics = repo.topics(); - expect(firstTopics).toEqual([topic4]); - expect(laterTopics).toEqual([topic4, topic5]); - }); + fetcher.addCategory(5); + const topic5 = fetcher._categoryDefinitionTopic(5); + await mirror.update(reporter); + const laterTopics = repo.topics(); - it("mirrors respects recheckTopicsInCategories option", async () => { - const {mirror, fetcher, reporter, repo} = example({ - recheckTopicsInCategories: [4], + expect(firstTopics).toEqual([topic4]); + expect(laterTopics).toEqual([topic4, topic5]); }); - const cooked = "

New content, without bump

"; - - // Adds a category description #4. - // And a topic 5 which is a member of the #4 category. - const p1 = fetcher.addPost(1, null); - fetcher.addPost(2, null); - fetcher.addPost(3, null); - fetcher.addCategory(4); - const p5 = fetcher.addPost(5, null); - fetcher.setTopicCategory(5, 4); - - // See we're trying to update #4 and #5. - const topicsCall = jest.spyOn(fetcher, "topicWithPosts"); - await mirror.update(reporter); - fetcher.editPost(p1, {cooked}); - fetcher.editPost(p5, {cooked}); - const earlyCalls = [...topicsCall.mock.calls]; - topicsCall.mockClear(); + it("mirrors respects recheckTopicsInCategories option", async () => { + const {mirror, fetcher, reporter, repo} = example({ + recheckTopicsInCategories: [4], + }); + const cooked = "

New content, without bump

"; + + // Adds a category description #4. + // And a topic 5 which is a member of the #4 category. + const p1 = fetcher.addPost(1, null); + fetcher.addPost(2, null); + fetcher.addPost(3, null); + fetcher.addCategory(4); + const p5 = fetcher.addPost(5, null); + fetcher.setTopicCategory(5, 4); + + // See we're trying to update #4 and #5. + const topicsCall = jest.spyOn(fetcher, "topicWithPosts"); + await mirror.update(reporter); - await mirror.update(reporter); - const laterPosts = repo.posts(); - - expect(fetcher._topic(4)).toMatchObject({id: 4, categoryId: 4}); - expect(fetcher._topic(5)).toMatchObject({id: 5, categoryId: 4}); - expect(fetcher._post(p5)).toMatchObject({id: 5, cooked}); - // The initial load has strict order requirements. - expect(earlyCalls).toEqual([[1], [2], [3], [5], [4]]); - // The update does not. - expect(topicsCall).toHaveBeenCalledTimes(2); - expect(topicsCall).toHaveBeenCalledWith(4); - expect(topicsCall).toHaveBeenCalledWith(5); - expect(laterPosts).toMatchInlineSnapshot(` - Array [ - Object { - "authorUsername": "credbot", - "cooked": "

Hello World

", - "id": 1, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 2001, - "topicId": 1, - }, - Object { - "authorUsername": "credbot", - "cooked": "

Hello World

", - "id": 2, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 2002, - "topicId": 2, - }, - Object { - "authorUsername": "credbot", - "cooked": "

Hello World

", - "id": 3, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 2003, - "topicId": 3, - }, - Object { - "authorUsername": "credbot", - "cooked": "

Hello World

", - "id": 4, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 2004, - "topicId": 4, - }, - Object { - "authorUsername": "credbot", - "cooked": "

New content, without bump

", - "id": 5, - "indexWithinTopic": 1, - "replyToPostIndex": null, - "timestampMs": 2005, - "topicId": 5, - }, - ] - `); - }); + fetcher.editPost(p1, {cooked}); + fetcher.editPost(p5, {cooked}); + const earlyCalls = [...topicsCall.mock.calls]; + topicsCall.mockClear(); - it("mirrors supports the uncategorized category in recheckTopicsInCategories option", async () => { - const {mirror, fetcher, reporter} = example({ - recheckTopicsInCategories: [1], + await mirror.update(reporter); + const laterPosts = repo.posts(); + + expect(fetcher._topic(4)).toMatchObject({id: 4, categoryId: 4}); + expect(fetcher._topic(5)).toMatchObject({id: 5, categoryId: 4}); + expect(fetcher._post(p5)).toMatchObject({id: 5, cooked}); + // The initial load has strict order requirements. + expect(earlyCalls).toEqual([[1], [2], [3], [5], [4]]); + // The update does not. + expect(topicsCall).toHaveBeenCalledTimes(2); + expect(topicsCall).toHaveBeenCalledWith(4); + expect(topicsCall).toHaveBeenCalledWith(5); + expect(laterPosts).toMatchInlineSnapshot(` + Array [ + Object { + "authorUsername": "credbot", + "cooked": "

Hello World

", + "id": 1, + "indexWithinTopic": 1, + "replyToPostIndex": null, + "timestampMs": 2001, + "topicId": 1, + }, + Object { + "authorUsername": "credbot", + "cooked": "

Hello World

", + "id": 2, + "indexWithinTopic": 1, + "replyToPostIndex": null, + "timestampMs": 2002, + "topicId": 2, + }, + Object { + "authorUsername": "credbot", + "cooked": "

Hello World

", + "id": 3, + "indexWithinTopic": 1, + "replyToPostIndex": null, + "timestampMs": 2003, + "topicId": 3, + }, + Object { + "authorUsername": "credbot", + "cooked": "

Hello World

", + "id": 4, + "indexWithinTopic": 1, + "replyToPostIndex": null, + "timestampMs": 2004, + "topicId": 4, + }, + Object { + "authorUsername": "credbot", + "cooked": "

New content, without bump

", + "id": 5, + "indexWithinTopic": 1, + "replyToPostIndex": null, + "timestampMs": 2005, + "topicId": 5, + }, + ] + `); }); - // Adds a category description #4. - // And a topic 5 which is a member of the #4 category. - fetcher.addPost(1, null); - fetcher.addPost(2, null); + it("mirrors supports the uncategorized category in recheckTopicsInCategories option", async () => { + const {mirror, fetcher, reporter} = example({ + recheckTopicsInCategories: [1], + }); - // See we're trying to update #4 and #5. - const topicsCall = jest.spyOn(fetcher, "topicWithPosts"); - await mirror.update(reporter); - const earlyCalls = [...topicsCall.mock.calls]; - topicsCall.mockClear(); - await mirror.update(reporter); + // Adds a category description #4. + // And a topic 5 which is a member of the #4 category. + fetcher.addPost(1, null); + fetcher.addPost(2, null); - // The initial load has strict order requirements. - expect(earlyCalls).toEqual([[1], [2]]); - // The update does not. - expect(topicsCall).toHaveBeenCalledTimes(2); - expect(topicsCall).toHaveBeenCalledWith(1); - expect(topicsCall).toHaveBeenCalledWith(2); - }); + // See we're trying to update #4 and #5. + const topicsCall = jest.spyOn(fetcher, "topicWithPosts"); + await mirror.update(reporter); + const earlyCalls = [...topicsCall.mock.calls]; + topicsCall.mockClear(); + await mirror.update(reporter); - it("doesn't recheck a topic more than once", async () => { - const {mirror, fetcher, reporter} = example({ - recheckTopicsInCategories: [4], + // The initial load has strict order requirements. + expect(earlyCalls).toEqual([[1], [2]]); + // The update does not. + expect(topicsCall).toHaveBeenCalledTimes(2); + expect(topicsCall).toHaveBeenCalledWith(1); + expect(topicsCall).toHaveBeenCalledWith(2); }); - // Adds a category description #4. - // And a topic 5 which is a member of the #4 category. - fetcher.addPost(1, null); - fetcher.addPost(2, null); - fetcher.addPost(3, null); - fetcher.addCategory(4); - fetcher.addPost(5, null); - fetcher.setTopicCategory(5, 4); - await mirror.update(reporter); + it("doesn't recheck a topic more than once", async () => { + const {mirror, fetcher, reporter} = example({ + recheckTopicsInCategories: [4], + }); - const topicsCall = jest.spyOn(fetcher, "topicWithPosts"); - fetcher.addPost(1, 1); - fetcher.addPost(5, 1); - await mirror.update(reporter); + // Adds a category description #4. + // And a topic 5 which is a member of the #4 category. + fetcher.addPost(1, null); + fetcher.addPost(2, null); + fetcher.addPost(3, null); + fetcher.addCategory(4); + fetcher.addPost(5, null); + fetcher.setTopicCategory(5, 4); + await mirror.update(reporter); - // #1 will be updated because of the new post bump. - // #4 will be updated because of the recheck of category. - // #5 will be updated because of the new post bump and recheck of category. - expect(topicsCall).toHaveBeenCalledTimes(3); - expect(topicsCall).toHaveBeenCalledWith(1); - expect(topicsCall).toHaveBeenCalledWith(4); - expect(topicsCall).toHaveBeenCalledWith(5); - }); + const topicsCall = jest.spyOn(fetcher, "topicWithPosts"); + fetcher.addPost(1, 1); + fetcher.addPost(5, 1); + await mirror.update(reporter); - it("only fetches new topics on `update`", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addPost(2, null); - await mirror.update(reporter); - fetcher.addPost(3, null); - const fetchTopicWithPosts = jest.spyOn(fetcher, "topicWithPosts"); - await mirror.update(reporter); - expect(fetchTopicWithPosts).toHaveBeenCalledTimes(1); - expect(fetchTopicWithPosts).toHaveBeenCalledWith(3); - expect(repo.topics().map((x) => x.id)).toEqual([1, 2, 3]); - }); + // #1 will be updated because of the new post bump. + // #4 will be updated because of the recheck of category. + // #5 will be updated because of the new post bump and recheck of category. + expect(topicsCall).toHaveBeenCalledTimes(3); + expect(topicsCall).toHaveBeenCalledWith(1); + expect(topicsCall).toHaveBeenCalledWith(4); + expect(topicsCall).toHaveBeenCalledWith(5); + }); - it("gets new posts on old topics on update", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addPost(2, null); - await mirror.update(reporter); - const id = fetcher.addPost(1, 1); - fetcher.addPost(3, null); - await mirror.update(reporter); - const allPostIds = repo.posts().map((x) => x.id); - expect(allPostIds).toContain(id); - }); + it("only fetches new topics on `update`", async () => { + const {mirror, fetcher, reporter, repo} = example(); + fetcher.addPost(1, null); + fetcher.addPost(2, null); + await mirror.update(reporter); + fetcher.addPost(3, null); + const fetchTopicWithPosts = jest.spyOn(fetcher, "topicWithPosts"); + await mirror.update(reporter); + expect(fetchTopicWithPosts).toHaveBeenCalledTimes(1); + expect(fetchTopicWithPosts).toHaveBeenCalledWith(3); + expect(repo.topics().map((x) => x.id)).toEqual([1, 2, 3]); + }); - it("removes old posts on when removed from topics on update", async () => { - const {mirror, fetcher, reporter, repo} = example(); + it("gets new posts on old topics on update", async () => { + const {mirror, fetcher, reporter, repo} = example(); + fetcher.addPost(1, null); + fetcher.addPost(2, null); + await mirror.update(reporter); + const id = fetcher.addPost(1, 1); + fetcher.addPost(3, null); + await mirror.update(reporter); + const allPostIds = repo.posts().map((x) => x.id); + expect(allPostIds).toContain(id); + }); - const p1 = fetcher.addPost(1, null); - const p2 = fetcher.addPost(1, 1); - await mirror.update(reporter); - const earlyPids = repo.posts().map((p) => p.id); - fetcher.deletePost(p2); - const p3 = fetcher.addPost(1, 1); - await mirror.update(reporter); - const laterPids = repo.posts().map((p) => p.id); + it("removes old posts on when removed from topics on update", async () => { + const {mirror, fetcher, reporter, repo} = example(); - expect(earlyPids).toEqual([p1, p2]); - expect(laterPids).toEqual([p1, p3]); - }); + const p1 = fetcher.addPost(1, null); + const p2 = fetcher.addPost(1, 1); + await mirror.update(reporter); + const earlyPids = repo.posts().map((p) => p.id); + fetcher.deletePost(p2); + const p3 = fetcher.addPost(1, 1); + await mirror.update(reporter); + const laterPids = repo.posts().map((p) => p.id); - it("does not rely on incremental topic IDs", async () => { - const {mirror, fetcher, reporter, repo} = example(); - fetcher.addPost(1, null); - fetcher.addPost(3, null); - await mirror.update(reporter); - expect(repo.topics().map((x) => x.id)).toEqual([1, 3]); - }); + expect(earlyPids).toEqual([p1, p2]); + expect(laterPids).toEqual([p1, p3]); + }); - it("does not rely on incremental post IDs", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const p1 = fetcher.addPost(1, null); - fetcher._latestPostId += 2; - const p2 = fetcher.addPost(3, null); - await mirror.update(reporter); - expect(repo.posts().map((x) => x.id)).toEqual([p1, p2]); - }); + it("does not rely on incremental topic IDs", async () => { + const {mirror, fetcher, reporter, repo} = example(); + fetcher.addPost(1, null); + fetcher.addPost(3, null); + await mirror.update(reporter); + expect(repo.topics().map((x) => x.id)).toEqual([1, 3]); + }); - it("does not query for topics at all if there were no new topics", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null); - await mirror.update(reporter); - const fetchTopic = jest.spyOn(fetcher, "topicWithPosts"); - await mirror.update(reporter); - expect(fetchTopic).not.toHaveBeenCalled(); - }); + it("does not rely on incremental post IDs", async () => { + const {mirror, fetcher, reporter, repo} = example(); + const p1 = fetcher.addPost(1, null); + fetcher._latestPostId += 2; + const p2 = fetcher.addPost(3, null); + await mirror.update(reporter); + expect(repo.posts().map((x) => x.id)).toEqual([p1, p2]); + }); - it("queries for likes for every user", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "alpha"); - const fetchLikes = jest.spyOn(fetcher, "likesByUser"); - await mirror.update(reporter); - expect(fetchLikes).toHaveBeenCalledTimes(2); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); - expect(fetchLikes).toHaveBeenCalledWith("alpha", 0); - }); + it("does not query for topics at all if there were no new topics", async () => { + const {mirror, fetcher, reporter} = example(); + fetcher.addPost(1, null); + await mirror.update(reporter); + const fetchTopic = jest.spyOn(fetcher, "topicWithPosts"); + await mirror.update(reporter); + expect(fetchTopic).not.toHaveBeenCalled(); + }); - it("queries with offset, as needed", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "credbot"); - fetcher.addPost(2, null, "credbot"); - fetcher.addPost(3, null, "credbot"); - fetcher.addLike("credbot", 1, 1); - fetcher.addLike("credbot", 2, 2); - fetcher.addLike("credbot", 3, 3); - const fetchLikes = jest.spyOn(fetcher, "likesByUser"); - await mirror.update(reporter); - expect(fetchLikes).toHaveBeenCalledTimes(2); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 2); - }); + it("queries for likes for every user", async () => { + const {mirror, fetcher, reporter} = example(); + fetcher.addPost(1, null, "alpha"); + const fetchLikes = jest.spyOn(fetcher, "likesByUser"); + await mirror.update(reporter); + expect(fetchLikes).toHaveBeenCalledTimes(2); + expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); + expect(fetchLikes).toHaveBeenCalledWith("alpha", 0); + }); - it("ceases querying once it has found all the new likes", async () => { - const {mirror, fetcher, reporter} = example(); - fetcher.addPost(1, null, "credbot"); - fetcher.addPost(2, null, "credbot"); - fetcher.addPost(3, null, "credbot"); - fetcher.addLike("credbot", 1, 1); - fetcher.addLike("credbot", 2, 2); - await mirror.update(reporter); - fetcher.addLike("credbot", 3, 3); - const fetchLikes = jest.spyOn(fetcher, "likesByUser"); - await mirror.update(reporter); - expect(fetchLikes).toHaveBeenCalledTimes(1); - expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); - }); + it("queries with offset, as needed", async () => { + const {mirror, fetcher, reporter} = example(); + fetcher.addPost(1, null, "credbot"); + fetcher.addPost(2, null, "credbot"); + fetcher.addPost(3, null, "credbot"); + fetcher.addLike("credbot", 1, 1); + fetcher.addLike("credbot", 2, 2); + fetcher.addLike("credbot", 3, 3); + const fetchLikes = jest.spyOn(fetcher, "likesByUser"); + await mirror.update(reporter); + expect(fetchLikes).toHaveBeenCalledTimes(2); + expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); + expect(fetchLikes).toHaveBeenCalledWith("credbot", 2); + }); - it("warns if it gets a like that doesn't correspond to any post", async () => { - const {mirror, fetcher, reporter, repo} = example(); - const pid = fetcher.addPost(1, null, "credbot"); - const badLike = {username: "credbot", postId: 37, timestampMs: 0}; - fetcher._likes.push(badLike); - await mirror.update(reporter); - expect(repo.topics()).toEqual([fetcher._topic(1)]); - expect(repo.posts()).toEqual([fetcher._post(pid)]); - expect(repo.likes()).toEqual([]); - expect(console.warn).toHaveBeenCalledWith( - "Warning: Encountered error 'FOREIGN KEY constraint failed' " + - "on a like by credbot on post id 37." - ); - expect(console.warn).toHaveBeenCalledTimes(1); - spyWarn().mockReset(); + it("ceases querying once it has found all the new likes", async () => { + const {mirror, fetcher, reporter} = example(); + fetcher.addPost(1, null, "credbot"); + fetcher.addPost(2, null, "credbot"); + fetcher.addPost(3, null, "credbot"); + fetcher.addLike("credbot", 1, 1); + fetcher.addLike("credbot", 2, 2); + await mirror.update(reporter); + fetcher.addLike("credbot", 3, 3); + const fetchLikes = jest.spyOn(fetcher, "likesByUser"); + await mirror.update(reporter); + expect(fetchLikes).toHaveBeenCalledTimes(1); + expect(fetchLikes).toHaveBeenCalledWith("credbot", 0); + }); + + it("warns if it gets a like that doesn't correspond to any post", async () => { + const {mirror, fetcher, reporter, repo} = example(); + const pid = fetcher.addPost(1, null, "credbot"); + const badLike = {username: "credbot", postId: 37, timestampMs: 0}; + fetcher._likes.push(badLike); + await mirror.update(reporter); + expect(repo.topics()).toEqual([fetcher._topic(1)]); + expect(repo.posts()).toEqual([fetcher._post(pid)]); + expect(repo.likes()).toEqual([]); + expect(console.warn).toHaveBeenCalledWith( + "Warning: Encountered error 'FOREIGN KEY constraint failed' " + + "on a like by credbot on post id 37." + ); + expect(console.warn).toHaveBeenCalledTimes(1); + spyWarn().mockReset(); + }); }); it("warns if a user's likes are missing", async () => { diff --git a/src/plugins/discourse/mirrorRepository.js b/src/plugins/discourse/mirrorRepository.js index 176c7740b..90a5aab16 100644 --- a/src/plugins/discourse/mirrorRepository.js +++ b/src/plugins/discourse/mirrorRepository.js @@ -67,11 +67,6 @@ export type SyncHeads = {| +topicBumpMs: number, |}; -export type MaxIds = {| - +maxPostId: number, - +maxTopicId: number, -|}; - export type AddResult = {| +changes: number, +lastInsertRowid: number, @@ -79,9 +74,6 @@ export type AddResult = {| // Read-write interface the mirror uses internally. export interface MirrorRepository extends ReadRepository { - maxIds(): MaxIds; - addTopic(topic: Topic): AddResult; - addPost(post: Post): AddResult; addLike(like: LikeAction): AddResult; /** @@ -229,22 +221,6 @@ export class SqliteMirrorRepository } } - maxIds(): MaxIds { - const res = this._db - .prepare( - dedent`\ - SELECT - (SELECT IFNULL(MAX(id), 0) FROM posts) AS max_post, - (SELECT IFNULL(MAX(id), 0) FROM topics) AS max_topic - ` - ) - .get(); - return { - maxPostId: res.max_post, - maxTopicId: res.max_topic, - }; - } - syncHeads(): SyncHeads { const res = this._db .prepare( diff --git a/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL2xhdGVzdC5qc29uP29yZGVyPWNyZWF0ZWQ b/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL2xhdGVzdC5qc29uP29yZGVyPWNyZWF0ZWQ deleted file mode 100644 index 7716646f3..000000000 --- a/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL2xhdGVzdC5qc29uP29yZGVyPWNyZWF0ZWQ +++ /dev/null @@ -1,1191 +0,0 @@ -{ - "users": [ - { - "id": 5, - "username": "beanow.sc-test", - "name": "Beanow", - "avatar_template": "https://avatars.discourse.org/v4/letter/b/7ea924/{size}.png" - } - ], - "primary_groups": [], - "topic_list": { - "can_create_topic": false, - "more_topics_url": "/latest?no_definitions=true&order=created&page=1", - "draft": null, - "draft_key": "new_topic", - "draft_sequence": null, - "per_page": 30, - "topics": [ - { - "id": 57, - "title": "Filler Topic #31", - "fancy_title": "Filler Topic #31", - "slug": "filler-topic-31", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:56:38.902Z", - "last_posted_at": "2019-11-15T17:56:38.964Z", - "bumped": true, - "bumped_at": "2019-11-15T17:56:38.964Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 56, - "title": "Filler Topic #30", - "fancy_title": "Filler Topic #30", - "slug": "filler-topic-30", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:56:30.101Z", - "last_posted_at": "2019-11-15T17:56:30.166Z", - "bumped": true, - "bumped_at": "2019-11-15T17:56:30.166Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 55, - "title": "Filler Topic #29", - "fancy_title": "Filler Topic #29", - "slug": "filler-topic-29", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:56:20.295Z", - "last_posted_at": "2019-11-15T17:56:20.352Z", - "bumped": true, - "bumped_at": "2019-11-15T17:56:20.352Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 54, - "title": "Filler Topic #28", - "fancy_title": "Filler Topic #28", - "slug": "filler-topic-28", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:56:14.124Z", - "last_posted_at": "2019-11-15T17:56:14.181Z", - "bumped": true, - "bumped_at": "2019-11-15T17:56:14.181Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 53, - "title": "Filler Topic #27", - "fancy_title": "Filler Topic #27", - "slug": "filler-topic-27", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:56:07.727Z", - "last_posted_at": "2019-11-15T17:56:07.788Z", - "bumped": true, - "bumped_at": "2019-11-15T17:56:07.788Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 52, - "title": "Filler Topic #26", - "fancy_title": "Filler Topic #26", - "slug": "filler-topic-26", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:56:02.010Z", - "last_posted_at": "2019-11-15T17:56:02.068Z", - "bumped": true, - "bumped_at": "2019-11-15T17:56:02.068Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 51, - "title": "Filler Topic #25", - "fancy_title": "Filler Topic #25", - "slug": "filler-topic-25", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:51.656Z", - "last_posted_at": "2019-11-15T17:55:51.728Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:51.728Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 50, - "title": "Filler Topic #24", - "fancy_title": "Filler Topic #24", - "slug": "filler-topic-24", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:44.797Z", - "last_posted_at": "2019-11-15T17:55:44.868Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:44.868Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 49, - "title": "Filler Topic #23", - "fancy_title": "Filler Topic #23", - "slug": "filler-topic-23", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:38.246Z", - "last_posted_at": "2019-11-15T17:55:38.301Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:38.301Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 48, - "title": "Filler Topic #22", - "fancy_title": "Filler Topic #22", - "slug": "filler-topic-22", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:31.935Z", - "last_posted_at": "2019-11-15T17:55:32.029Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:32.029Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 47, - "title": "Filler Topic #21", - "fancy_title": "Filler Topic #21", - "slug": "filler-topic-21", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:25.656Z", - "last_posted_at": "2019-11-15T17:55:25.734Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:25.734Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 46, - "title": "Filler Topic #20", - "fancy_title": "Filler Topic #20", - "slug": "filler-topic-20", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:16.235Z", - "last_posted_at": "2019-11-15T17:55:16.283Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:16.283Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 45, - "title": "Filler Topic #19", - "fancy_title": "Filler Topic #19", - "slug": "filler-topic-19", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:09.297Z", - "last_posted_at": "2019-11-15T17:55:09.355Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:09.355Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 44, - "title": "Filler Topic #18", - "fancy_title": "Filler Topic #18", - "slug": "filler-topic-18", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:55:02.978Z", - "last_posted_at": "2019-11-15T17:55:03.032Z", - "bumped": true, - "bumped_at": "2019-11-15T17:55:03.032Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 43, - "title": "Filler Topic #17", - "fancy_title": "Filler Topic #17", - "slug": "filler-topic-17", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:56.337Z", - "last_posted_at": "2019-11-15T17:54:56.395Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:56.395Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 42, - "title": "Filler Topic #16", - "fancy_title": "Filler Topic #16", - "slug": "filler-topic-16", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:46.242Z", - "last_posted_at": "2019-11-15T17:54:46.299Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:46.299Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 41, - "title": "Filler Topic #15", - "fancy_title": "Filler Topic #15", - "slug": "filler-topic-15", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:40.538Z", - "last_posted_at": "2019-11-15T17:54:40.604Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:40.604Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 40, - "title": "Filler Topic #14", - "fancy_title": "Filler Topic #14", - "slug": "filler-topic-14", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:34.386Z", - "last_posted_at": "2019-11-15T17:54:34.450Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:34.450Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 39, - "title": "Filler Topic #13", - "fancy_title": "Filler Topic #13", - "slug": "filler-topic-13", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:29.748Z", - "last_posted_at": "2019-11-15T17:54:29.806Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:29.806Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 38, - "title": "Filler Topic #12", - "fancy_title": "Filler Topic #12", - "slug": "filler-topic-12", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:24.152Z", - "last_posted_at": "2019-11-15T17:54:24.212Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:24.212Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 37, - "title": "Filler Topic #11", - "fancy_title": "Filler Topic #11", - "slug": "filler-topic-11", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:54:10.242Z", - "last_posted_at": "2019-11-15T17:54:10.294Z", - "bumped": true, - "bumped_at": "2019-11-15T17:54:10.294Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 36, - "title": "Filler Topic #10", - "fancy_title": "Filler Topic #10", - "slug": "filler-topic-10", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:53:48.677Z", - "last_posted_at": "2019-11-15T17:53:48.729Z", - "bumped": true, - "bumped_at": "2019-11-15T17:53:48.729Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 2, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 35, - "title": "Filler Topic #9", - "fancy_title": "Filler Topic #9", - "slug": "filler-topic-9", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:52:52.613Z", - "last_posted_at": "2019-11-15T17:52:52.677Z", - "bumped": true, - "bumped_at": "2019-11-15T17:52:52.677Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 34, - "title": "Filler Topic #8", - "fancy_title": "Filler Topic #8", - "slug": "filler-topic-8", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:52:46.625Z", - "last_posted_at": "2019-11-15T17:52:46.708Z", - "bumped": true, - "bumped_at": "2019-11-15T17:52:46.708Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 33, - "title": "Filler Topic #7", - "fancy_title": "Filler Topic #7", - "slug": "filler-topic-7", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:52:40.253Z", - "last_posted_at": "2019-11-15T17:52:40.335Z", - "bumped": true, - "bumped_at": "2019-11-15T17:52:40.335Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 32, - "title": "Filler Topic #6", - "fancy_title": "Filler Topic #6", - "slug": "filler-topic-6", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:52:34.599Z", - "last_posted_at": "2019-11-15T17:52:34.669Z", - "bumped": true, - "bumped_at": "2019-11-15T17:52:34.669Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 31, - "title": "Filler Topic #5", - "fancy_title": "Filler Topic #5", - "slug": "filler-topic-5", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:52:28.348Z", - "last_posted_at": "2019-11-15T17:52:28.410Z", - "bumped": true, - "bumped_at": "2019-11-15T17:52:28.410Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 30, - "title": "Filler Topic #4", - "fancy_title": "Filler Topic #4", - "slug": "filler-topic-4", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:52:15.060Z", - "last_posted_at": "2019-11-15T17:52:15.123Z", - "bumped": true, - "bumped_at": "2019-11-15T17:52:15.123Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 29, - "title": "Filler Topic #3", - "fancy_title": "Filler Topic #3", - "slug": "filler-topic-3", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:51:50.488Z", - "last_posted_at": "2019-11-15T17:51:50.550Z", - "bumped": true, - "bumped_at": "2019-11-15T17:51:50.550Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 1, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - }, - { - "id": 28, - "title": "Filler Topic #2", - "fancy_title": "Filler Topic #2", - "slug": "filler-topic-2", - "posts_count": 1, - "reply_count": 0, - "highest_post_number": 1, - "image_url": null, - "created_at": "2019-11-15T17:50:33.177Z", - "last_posted_at": "2019-11-15T17:50:33.231Z", - "bumped": true, - "bumped_at": "2019-11-15T17:50:33.231Z", - "unseen": false, - "pinned": false, - "unpinned": null, - "visible": true, - "closed": false, - "archived": false, - "bookmarked": null, - "liked": null, - "views": 2, - "like_count": 0, - "has_summary": false, - "archetype": "regular", - "last_poster_username": "beanow.sc-test", - "category_id": 5, - "pinned_globally": false, - "featured_link": null, - "has_accepted_answer": false, - "posters": [ - { - "extras": "latest single", - "description": "Original Poster, Most Recent Poster", - "user_id": 5, - "primary_group_id": null - } - ] - } - ] - } -} diff --git a/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLmpzb24 b/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLmpzb24 deleted file mode 100644 index 429d9b3f8..000000000 --- a/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLmpzb24 +++ /dev/null @@ -1,697 +0,0 @@ -{ - "latest_posts": [ - { - "id": 29, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-10-23T18:26:31.281Z", - "cooked": "

Here is a mention: @dl-proto
\nHere is a topic reference: 123 a post with numbers in slug
\nHere is a post reference with a slug: My First Test Post

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-10-23T18:26:31.281Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 1, - "reads": 1, - "readers_count": 0, - "score": 5.2, - "yours": false, - "topic_id": 21, - "topic_slug": "a-post-with-references", - "topic_title": "A Post With References", - "topic_html_title": "A Post With References", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Here is a mention: @dl-proto\nHere is a topic reference: https://sourcecred-test.discourse.group/t/123-a-post-with-numbers-in-slug/20/\nHere is a post reference with a slug: https://sourcecred-test.discourse.group/t/my-first-test-post/11/4", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 28, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-10-07T03:49:19.922Z", - "cooked": "

Oh the post won’t be empty I assure you.

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-10-07T03:49:19.922Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 1, - "readers_count": 0, - "score": 0.2, - "yours": false, - "topic_id": 20, - "topic_slug": "123-a-post-with-numbers-in-slug", - "topic_title": "123 a post with numbers in slug", - "topic_html_title": "123 a post with numbers in slug", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Oh the post won't be empty I assure you.", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 27, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-10-02T20:57:16.311Z", - "cooked": "

I’m replying to a wiki.

", - "post_number": 2, - "post_type": 1, - "updated_at": "2019-10-02T20:57:16.311Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 1, - "readers_count": 0, - "score": 0.2, - "yours": false, - "topic_id": 19, - "topic_slug": "this-post-will-be-a-wiki", - "topic_title": "This post will be a wiki", - "topic_html_title": "This post will be a wiki", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "I'm replying to a wiki.", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 26, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-10-02T20:51:31.743Z", - "cooked": "

So I’m starting the wiki content.

\n

No remove that line.

\n

Ah now I’ve added another line.

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-10-02T20:53:28.182Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 2, - "readers_count": 1, - "score": 0.4, - "yours": false, - "topic_id": 19, - "topic_slug": "this-post-will-be-a-wiki", - "topic_title": "This post will be a wiki", - "topic_html_title": "This post will be a wiki", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 3, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "So I'm starting the wiki content.\n\nNo remove that line.\n\nAh now I've added another line.", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": true, - "last_wiki_edit": "2019-10-02T20:53:28.194Z", - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 25, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-10-02T20:50:10.625Z", - "cooked": "

Testing a poll. Let’s see how it works.

\n
\n
\n
\n
    \n
  • One
  • \n
  • Two
  • \n
  • Three
  • \n
  • Four
  • \n
  • Five
  • \n
\n
\n
\n

\n0\nvoters\n

\n
\n
\n
", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-10-02T20:50:10.625Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 2, - "readers_count": 1, - "score": 0.4, - "yours": false, - "topic_id": 18, - "topic_slug": "test-poll-please-ignore", - "topic_title": "Test Poll Please Ignore", - "topic_html_title": "Test Poll Please Ignore", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Testing a poll. Let's see how it works.\n[poll type=multiple results=always min=1 max=5 public=true]\n* One\n* Two\n* Three\n* Four\n* Five\n[/poll]", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false, - "polls": [ - { - "name": "poll", - "type": "multiple", - "status": "open", - "public": true, - "results": "always", - "min": 1, - "max": 5, - "options": [ - { - "id": "159d8e412be4679f2d98fb5f0d0cce91", - "html": "One", - "votes": 0 - }, - { - "id": "2cbb44549228f1cf22e44fba86b6db21", - "html": "Two", - "votes": 1 - }, - { - "id": "7016bd7a00c7caff922822b2910a564a", - "html": "Three", - "votes": 2 - }, - { - "id": "d2bb44ccb6b19c98cc57f5b8bb87effe", - "html": "Four", - "votes": 1 - }, - { - "id": "c677eae47d33ca9b527e7ea7bb29612c", - "html": "Five", - "votes": 0 - } - ], - "voters": 2, - "preloaded_voters": { - "2cbb44549228f1cf22e44fba86b6db21": [ - { - "id": 2, - "username": "d11", - "name": "D", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "title": null - } - ], - "7016bd7a00c7caff922822b2910a564a": [ - { - "id": 2, - "username": "d11", - "name": "D", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "title": null - }, - { - "id": 3, - "username": "dl-proto", - "name": "dandelion protocol acct", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/8797f3/{size}.png", - "title": null - } - ], - "d2bb44ccb6b19c98cc57f5b8bb87effe": [ - { - "id": 3, - "username": "dl-proto", - "name": "dandelion protocol acct", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/8797f3/{size}.png", - "title": null - } - ] - } - } - ] - }, - { - "id": 22, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-08-04T20:50:39.667Z", - "cooked": "

Adding another post, after having deleted a whole thread.

", - "post_number": 3, - "post_type": 1, - "updated_at": "2019-08-04T20:50:39.667Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 2, - "readers_count": 1, - "score": 0.4, - "yours": false, - "topic_id": 11, - "topic_slug": "my-first-test-post", - "topic_title": "My First Test Post", - "topic_html_title": "My First Test Post", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Adding another post, after having deleted a whole thread.", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 18, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-08-02T11:16:31.313Z", - "cooked": "\n

Excellent link. I’ve quoted you.

", - "post_number": 2, - "post_type": 1, - "updated_at": "2019-08-02T11:17:12.745Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 1, - "incoming_link_count": 0, - "reads": 1, - "readers_count": 0, - "score": 0.2, - "yours": false, - "topic_id": 13, - "topic_slug": "a-thread-with-links", - "topic_title": "A Thread With Links", - "topic_html_title": "A Thread With Links", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 3, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "[quote=\"dl-proto, post:1, topic:13\"]\nHere is a link to another discourse thread:\n[/quote]\n\nExcellent link. I've quoted you.", - "actions_summary": [], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 17, - "name": "dandelion protocol acct", - "username": "dl-proto", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/8797f3/{size}.png", - "created_at": "2019-08-02T11:15:53.905Z", - "cooked": "

Here is a link to another discourse thread: My First Test Post

\n

Here is a link to a GitHub issue: https://github.com/sourcecred-test/example-github/issues/1

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-08-02T11:15:53.905Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 2, - "readers_count": 1, - "score": 0.4, - "yours": false, - "topic_id": 13, - "topic_slug": "a-thread-with-links", - "topic_title": "A Thread With Links", - "topic_html_title": "A Thread With Links", - "category_id": 1, - "display_username": "dandelion protocol acct", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Here is a link to another discourse thread: https://sourcecred-test.discourse.group/t/my-first-test-post/11/3\n\nHere is a link to a GitHub issue: https://github.com/sourcecred-test/example-github/issues/1", - "actions_summary": [], - "moderator": false, - "admin": false, - "staff": false, - "user_id": 3, - "hidden": false, - "trust_level": 1, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 16, - "name": "dandelion protocol acct", - "username": "dl-proto", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/8797f3/{size}.png", - "created_at": "2019-08-02T11:14:56.285Z", - "cooked": "

Ah, an excellent post. I will like it and reply.

", - "post_number": 2, - "post_type": 1, - "updated_at": "2019-08-02T11:14:56.285Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 2, - "readers_count": 1, - "score": 0.4, - "yours": false, - "topic_id": 11, - "topic_slug": "my-first-test-post", - "topic_title": "My First Test Post", - "topic_html_title": "My First Test Post", - "category_id": 1, - "display_username": "dandelion protocol acct", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Ah, an excellent post. I will like it and reply.", - "actions_summary": [], - "moderator": false, - "admin": false, - "staff": false, - "user_id": 3, - "hidden": false, - "trust_level": 1, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 14, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-08-02T11:12:29.476Z", - "cooked": "

This is a test post.

\n

EDIT: This test post was edited on October 24, 2019.

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-10-24T16:51:12.095Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 1, - "reads": 2, - "readers_count": 1, - "score": 20.4, - "yours": false, - "topic_id": 11, - "topic_slug": "my-first-test-post", - "topic_title": "My First Test Post", - "topic_html_title": "My First Test Post", - "category_id": 1, - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 2, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "This is a test post.\n\nEDIT: This test post was edited on October 24, 2019.", - "actions_summary": [ - { - "id": 2, - "count": 1 - } - ], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 10, - "name": "system", - "username": "system", - "avatar_template": "/user_avatar/sourcecred-test.discourse.group/system/{size}/1_2.png", - "created_at": "2019-04-02T20:20:12.933Z", - "cooked": "

This is a test instance.
\nThe first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It’s important!

\n

Edit this into a brief description of your community:

\n
    \n
  • Who is it for?
  • \n
  • What can they find here?
  • \n
  • Why should they come here?
  • \n
  • Where can they read more (links, resources, etc)?
  • \n
\n

\n

You may want to close this topic via the admin \":wrench:\" (at the upper right and bottom), so that replies don’t pile up on an announcement.

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-04-10T23:16:19.366Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 2, - "readers_count": 1, - "score": 0.4, - "yours": false, - "topic_id": 7, - "topic_slug": "welcome-to-discourse", - "topic_title": "Welcome to Discourse", - "topic_html_title": "Welcome to Discourse", - "category_id": 1, - "display_username": "system", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 2, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "This is a test instance.\nThe first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important!\n\n**Edit this** into a brief description of your community:\n\n- Who is it for?\n- What can they find here?\n- Why should they come here?\n- Where can they read more (links, resources, etc)?\n\n\n\nYou may want to close this topic via the admin :wrench: (at the upper right and bottom), so that replies don't pile up on an announcement.", - "actions_summary": [], - "moderator": true, - "admin": true, - "staff": true, - "user_id": -1, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - }, - { - "id": 1, - "name": "system", - "username": "system", - "avatar_template": "/user_avatar/sourcecred-test.discourse.group/system/{size}/1_2.png", - "created_at": "2019-04-02T20:20:09.844Z", - "cooked": "

Discussion about this site, its organization, how it works, and how we can improve it.

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-04-02T20:20:09.844Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 0, - "reads": 1, - "readers_count": 0, - "score": 0.2, - "yours": false, - "topic_id": 1, - "topic_slug": "about-the-site-feedback-category", - "topic_title": "About the Site Feedback category", - "topic_html_title": "About the Site Feedback category", - "category_id": 2, - "display_username": "system", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 1, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "Discussion about this site, its organization, how it works, and how we can improve it.", - "actions_summary": [], - "moderator": true, - "admin": true, - "staff": true, - "user_id": -1, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false - } - ] -} diff --git a/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLzE0Lmpzb24 b/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLzE0Lmpzb24 deleted file mode 100644 index d84d5cf21..000000000 --- a/src/plugins/discourse/snapshots/aHR0cHM6Ly9zb3VyY2VjcmVkLXRlc3QuZGlzY291cnNlLmdyb3VwL3Bvc3RzLzE0Lmpzb24 +++ /dev/null @@ -1,53 +0,0 @@ -{ - "id": 14, - "name": "D", - "username": "d11", - "avatar_template": "https://avatars.discourse.org/v4/letter/d/47e85d/{size}.png", - "created_at": "2019-08-02T11:12:29.476Z", - "cooked": "

This is a test post.

\n

EDIT: This test post was edited on October 24, 2019.

", - "post_number": 1, - "post_type": 1, - "updated_at": "2019-10-24T16:51:12.095Z", - "reply_count": 0, - "reply_to_post_number": null, - "quote_count": 0, - "incoming_link_count": 1, - "reads": 2, - "readers_count": 1, - "score": 20.4, - "yours": false, - "topic_id": 11, - "topic_slug": "my-first-test-post", - "display_username": "D", - "primary_group_name": null, - "primary_group_flair_url": null, - "primary_group_flair_bg_color": null, - "primary_group_flair_color": null, - "version": 2, - "can_edit": false, - "can_delete": false, - "can_recover": false, - "can_wiki": false, - "user_title": null, - "raw": "This is a test post.\n\nEDIT: This test post was edited on October 24, 2019.", - "actions_summary": [ - { - "id": 2, - "count": 1 - } - ], - "moderator": false, - "admin": true, - "staff": true, - "user_id": 2, - "hidden": false, - "trust_level": 4, - "deleted_at": null, - "user_deleted": false, - "edit_reason": null, - "can_view_edit_history": true, - "wiki": false, - "can_accept_answer": false, - "can_unaccept_answer": false, - "accepted_answer": false -} diff --git a/src/plugins/discourse/update_discourse_api_snapshots.sh b/src/plugins/discourse/update_discourse_api_snapshots.sh index 7abb310c5..89be45675 100755 --- a/src/plugins/discourse/update_discourse_api_snapshots.sh +++ b/src/plugins/discourse/update_discourse_api_snapshots.sh @@ -24,17 +24,12 @@ fetch() { rm -r "${snapshots_dir}" mkdir "${snapshots_dir}" -fetch "/latest.json?order=created" -fetch "/posts.json" -fetch "/t/11.json" -fetch "/t/21.json" -fetch "/posts/14.json" -fetch "/user_actions.json?username=dl-proto&filter=1&offset=0" - -# New API loading style. fetch "/latest.json?order=activity&ascending=false&page=0" fetch "/latest.json?order=activity&ascending=false&page=1" fetch "/categories.json?show_subcategory_list=true" fetch "/categories.json?show_subcategory_list=true&parent_category_id=5" +fetch "/t/11.json" +fetch "/t/21.json" fetch "/t/26.json" fetch "/t/26.json?page=2" +fetch "/user_actions.json?username=dl-proto&filter=1&offset=0"