@fedify/botkit 0.3.0-dev.111 → 0.3.0-dev.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bot-impl.d.ts +2 -1
- package/dist/bot-impl.d.ts.map +1 -1
- package/dist/bot-impl.js +80 -2
- package/dist/bot-impl.js.map +1 -1
- package/dist/bot-impl.test.js +247 -1
- package/dist/bot-impl.test.js.map +1 -1
- package/dist/bot.d.ts +15 -1
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +6 -0
- package/dist/bot.js.map +1 -1
- package/dist/components/Message.d.ts +2 -2
- package/dist/deno.js +9 -3
- package/dist/deno.js.map +1 -1
- package/dist/events.d.ts +13 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/mod.d.ts +3 -2
- package/dist/mod.js +1 -1
- package/dist/pages.d.ts +2 -2
- package/dist/poll.d.ts +60 -0
- package/dist/poll.d.ts.map +1 -0
- package/dist/poll.js +4 -0
- package/dist/repository.js.map +1 -1
- package/dist/session-impl.d.ts +5 -3
- package/dist/session-impl.d.ts.map +1 -1
- package/dist/session-impl.js +20 -1
- package/dist/session-impl.js.map +1 -1
- package/dist/session-impl.test.d.ts.map +1 -1
- package/dist/session-impl.test.js +160 -1
- package/dist/session-impl.test.js.map +1 -1
- package/dist/session.d.ts +22 -1
- package/dist/session.d.ts.map +1 -1
- package/package.json +10 -2
package/dist/bot-impl.test.js
CHANGED
|
@@ -8,7 +8,7 @@ import { BotImpl } from "./bot-impl.js";
|
|
|
8
8
|
import { parseSemVer } from "./bot.js";
|
|
9
9
|
import { mention, strong, text } from "./text.js";
|
|
10
10
|
import { MemoryKvStore } from "@fedify/fedify/federation";
|
|
11
|
-
import { Accept, Announce, Article, Create, CryptographicKey, Emoji, EmojiReact, Follow, Image, Like, Mention, Note, PUBLIC_COLLECTION, Person, Place, PropertyValue, Reject, Service, Undo } from "@fedify/fedify/vocab";
|
|
11
|
+
import { Accept, Announce, Article, Collection, Create, CryptographicKey, Emoji, EmojiReact, Follow, Image, Like, Mention, Note, PUBLIC_COLLECTION, Person, Place, PropertyValue, Question, Reject, Service, Undo, Update } from "@fedify/fedify/vocab";
|
|
12
12
|
import assert from "node:assert";
|
|
13
13
|
import { describe, test } from "node:test";
|
|
14
14
|
|
|
@@ -1637,6 +1637,252 @@ function createMockInboxContext(bot, origin, recipient) {
|
|
|
1637
1637
|
};
|
|
1638
1638
|
return ctx;
|
|
1639
1639
|
}
|
|
1640
|
+
test("BotImpl.onVote()", async (t) => {
|
|
1641
|
+
const repository = new MemoryRepository();
|
|
1642
|
+
const bot = new BotImpl({
|
|
1643
|
+
kv: new MemoryKvStore(),
|
|
1644
|
+
repository,
|
|
1645
|
+
username: "bot"
|
|
1646
|
+
});
|
|
1647
|
+
const ctx = createMockInboxContext(bot, "https://example.com", "bot");
|
|
1648
|
+
const pollId = "01950000-0000-7000-8000-000000000000";
|
|
1649
|
+
const poll = new Create({
|
|
1650
|
+
id: new URL(`https://example.com/ap/create/${pollId}`),
|
|
1651
|
+
actor: ctx.getActorUri(bot.identifier),
|
|
1652
|
+
to: PUBLIC_COLLECTION,
|
|
1653
|
+
cc: ctx.getFollowersUri(bot.identifier),
|
|
1654
|
+
object: new Question({
|
|
1655
|
+
id: new URL(`https://example.com/ap/question/${pollId}`),
|
|
1656
|
+
attribution: ctx.getActorUri(bot.identifier),
|
|
1657
|
+
to: PUBLIC_COLLECTION,
|
|
1658
|
+
cc: ctx.getFollowersUri(bot.identifier),
|
|
1659
|
+
content: "What's your favorite color?",
|
|
1660
|
+
inclusiveOptions: [],
|
|
1661
|
+
exclusiveOptions: [
|
|
1662
|
+
new Note({
|
|
1663
|
+
name: "Red",
|
|
1664
|
+
replies: new Collection({ totalItems: 0 })
|
|
1665
|
+
}),
|
|
1666
|
+
new Note({
|
|
1667
|
+
name: "Blue",
|
|
1668
|
+
replies: new Collection({ totalItems: 0 })
|
|
1669
|
+
}),
|
|
1670
|
+
new Note({
|
|
1671
|
+
name: "Green",
|
|
1672
|
+
replies: new Collection({ totalItems: 0 })
|
|
1673
|
+
})
|
|
1674
|
+
],
|
|
1675
|
+
endTime: Temporal.Now.instant().add({ hours: 24 }),
|
|
1676
|
+
voters: 0
|
|
1677
|
+
}),
|
|
1678
|
+
published: Temporal.Now.instant()
|
|
1679
|
+
});
|
|
1680
|
+
await repository.addMessage(pollId, poll);
|
|
1681
|
+
const voter = new Person({
|
|
1682
|
+
id: new URL("https://hollo.social/@alice"),
|
|
1683
|
+
preferredUsername: "alice"
|
|
1684
|
+
});
|
|
1685
|
+
let receivedVote = null;
|
|
1686
|
+
bot.onVote = (_session, vote) => {
|
|
1687
|
+
receivedVote = vote;
|
|
1688
|
+
};
|
|
1689
|
+
await t.test("vote on single choice poll", async () => {
|
|
1690
|
+
ctx.sentActivities = [];
|
|
1691
|
+
ctx.forwardedRecipients = [];
|
|
1692
|
+
receivedVote = null;
|
|
1693
|
+
const voteCreate = new Create({
|
|
1694
|
+
id: new URL("https://example.com/ap/create/vote1"),
|
|
1695
|
+
actor: voter,
|
|
1696
|
+
to: PUBLIC_COLLECTION,
|
|
1697
|
+
object: new Note({
|
|
1698
|
+
id: new URL("https://example.com/ap/note/vote1"),
|
|
1699
|
+
attribution: voter,
|
|
1700
|
+
to: PUBLIC_COLLECTION,
|
|
1701
|
+
name: "Red",
|
|
1702
|
+
replyTarget: poll.objectId,
|
|
1703
|
+
content: "Red"
|
|
1704
|
+
}),
|
|
1705
|
+
published: Temporal.Now.instant()
|
|
1706
|
+
});
|
|
1707
|
+
await bot.onCreated(ctx, voteCreate);
|
|
1708
|
+
assert.ok(receivedVote != null, "onVote should have been called");
|
|
1709
|
+
const vote = receivedVote;
|
|
1710
|
+
assert.deepStrictEqual(vote.actor.id, voter.id);
|
|
1711
|
+
assert.deepStrictEqual(vote.option, "Red");
|
|
1712
|
+
assert.deepStrictEqual(vote.poll.multiple, false);
|
|
1713
|
+
assert.deepStrictEqual(vote.poll.options, [
|
|
1714
|
+
"Red",
|
|
1715
|
+
"Blue",
|
|
1716
|
+
"Green"
|
|
1717
|
+
]);
|
|
1718
|
+
assert.ok(ctx.sentActivities.length > 0, "Update activity should be sent");
|
|
1719
|
+
const updateActivity = ctx.sentActivities.find(({ activity }) => activity instanceof Update);
|
|
1720
|
+
assert.ok(updateActivity != null, "Update activity should be found");
|
|
1721
|
+
assert.ok(updateActivity.activity instanceof Update);
|
|
1722
|
+
assert.deepStrictEqual(updateActivity.activity.objectId, poll.id);
|
|
1723
|
+
const updatedPoll = await repository.getMessage(pollId);
|
|
1724
|
+
assert.ok(updatedPoll instanceof Create);
|
|
1725
|
+
const updatedQuestion = await updatedPoll.getObject(ctx);
|
|
1726
|
+
assert.ok(updatedQuestion instanceof Question);
|
|
1727
|
+
const updatedOptions = await Array.fromAsync(updatedQuestion.getExclusiveOptions(ctx));
|
|
1728
|
+
const redOption = updatedOptions.find((opt) => opt.name?.toString() === "Red");
|
|
1729
|
+
assert.ok(redOption != null);
|
|
1730
|
+
const replies = await redOption.getReplies(ctx);
|
|
1731
|
+
assert.deepStrictEqual(replies?.totalItems, 1);
|
|
1732
|
+
});
|
|
1733
|
+
await t.test("vote on multiple choice poll", async () => {
|
|
1734
|
+
const multiPollId = "01950000-0000-7000-8000-000000000001";
|
|
1735
|
+
const multiPoll = new Create({
|
|
1736
|
+
id: new URL(`https://example.com/ap/create/${multiPollId}`),
|
|
1737
|
+
actor: ctx.getActorUri(bot.identifier),
|
|
1738
|
+
to: PUBLIC_COLLECTION,
|
|
1739
|
+
cc: ctx.getFollowersUri(bot.identifier),
|
|
1740
|
+
object: new Question({
|
|
1741
|
+
id: new URL(`https://example.com/ap/question/${multiPollId}`),
|
|
1742
|
+
attribution: ctx.getActorUri(bot.identifier),
|
|
1743
|
+
to: PUBLIC_COLLECTION,
|
|
1744
|
+
cc: ctx.getFollowersUri(bot.identifier),
|
|
1745
|
+
content: "Which languages do you know?",
|
|
1746
|
+
inclusiveOptions: [
|
|
1747
|
+
new Note({
|
|
1748
|
+
name: "JavaScript",
|
|
1749
|
+
replies: new Collection({ totalItems: 0 })
|
|
1750
|
+
}),
|
|
1751
|
+
new Note({
|
|
1752
|
+
name: "TypeScript",
|
|
1753
|
+
replies: new Collection({ totalItems: 0 })
|
|
1754
|
+
}),
|
|
1755
|
+
new Note({
|
|
1756
|
+
name: "Python",
|
|
1757
|
+
replies: new Collection({ totalItems: 0 })
|
|
1758
|
+
})
|
|
1759
|
+
],
|
|
1760
|
+
exclusiveOptions: [],
|
|
1761
|
+
endTime: Temporal.Now.instant().add({ hours: 24 }),
|
|
1762
|
+
voters: 0
|
|
1763
|
+
}),
|
|
1764
|
+
published: Temporal.Now.instant()
|
|
1765
|
+
});
|
|
1766
|
+
await repository.addMessage(multiPollId, multiPoll);
|
|
1767
|
+
ctx.sentActivities = [];
|
|
1768
|
+
ctx.forwardedRecipients = [];
|
|
1769
|
+
receivedVote = null;
|
|
1770
|
+
const jsVoteCreate = new Create({
|
|
1771
|
+
id: new URL("https://example.com/ap/create/vote2"),
|
|
1772
|
+
actor: voter,
|
|
1773
|
+
to: PUBLIC_COLLECTION,
|
|
1774
|
+
object: new Note({
|
|
1775
|
+
id: new URL("https://example.com/ap/note/vote2"),
|
|
1776
|
+
attribution: voter,
|
|
1777
|
+
to: PUBLIC_COLLECTION,
|
|
1778
|
+
name: "JavaScript",
|
|
1779
|
+
replyTarget: multiPoll.objectId,
|
|
1780
|
+
content: "JavaScript"
|
|
1781
|
+
}),
|
|
1782
|
+
published: Temporal.Now.instant()
|
|
1783
|
+
});
|
|
1784
|
+
await bot.onCreated(ctx, jsVoteCreate);
|
|
1785
|
+
assert.ok(receivedVote != null, "onVote should have been called");
|
|
1786
|
+
const vote = receivedVote;
|
|
1787
|
+
assert.deepStrictEqual(vote.actor.id, voter.id);
|
|
1788
|
+
assert.deepStrictEqual(vote.option, "JavaScript");
|
|
1789
|
+
assert.deepStrictEqual(vote.poll.multiple, true);
|
|
1790
|
+
assert.deepStrictEqual(vote.poll.options, [
|
|
1791
|
+
"JavaScript",
|
|
1792
|
+
"TypeScript",
|
|
1793
|
+
"Python"
|
|
1794
|
+
]);
|
|
1795
|
+
});
|
|
1796
|
+
await t.test("ignore vote from poll author", async () => {
|
|
1797
|
+
ctx.sentActivities = [];
|
|
1798
|
+
ctx.forwardedRecipients = [];
|
|
1799
|
+
receivedVote = null;
|
|
1800
|
+
const selfVoteCreate = new Create({
|
|
1801
|
+
id: new URL("https://example.com/ap/create/vote3"),
|
|
1802
|
+
actor: ctx.getActorUri(bot.identifier),
|
|
1803
|
+
to: PUBLIC_COLLECTION,
|
|
1804
|
+
object: new Note({
|
|
1805
|
+
id: new URL("https://example.com/ap/note/vote3"),
|
|
1806
|
+
attribution: ctx.getActorUri(bot.identifier),
|
|
1807
|
+
to: PUBLIC_COLLECTION,
|
|
1808
|
+
name: "Red",
|
|
1809
|
+
replyTarget: poll.objectId,
|
|
1810
|
+
content: "Red"
|
|
1811
|
+
}),
|
|
1812
|
+
published: Temporal.Now.instant()
|
|
1813
|
+
});
|
|
1814
|
+
await bot.onCreated(ctx, selfVoteCreate);
|
|
1815
|
+
assert.deepStrictEqual(receivedVote, null, "onVote should not be called for poll author");
|
|
1816
|
+
});
|
|
1817
|
+
await t.test("ignore vote on expired poll", async () => {
|
|
1818
|
+
const expiredPollId = "01950000-0000-7000-8000-000000000002";
|
|
1819
|
+
const expiredPoll = new Create({
|
|
1820
|
+
id: new URL(`https://example.com/ap/create/${expiredPollId}`),
|
|
1821
|
+
actor: ctx.getActorUri(bot.identifier),
|
|
1822
|
+
to: PUBLIC_COLLECTION,
|
|
1823
|
+
cc: ctx.getFollowersUri(bot.identifier),
|
|
1824
|
+
object: new Question({
|
|
1825
|
+
id: new URL(`https://example.com/ap/question/${expiredPollId}`),
|
|
1826
|
+
attribution: ctx.getActorUri(bot.identifier),
|
|
1827
|
+
to: PUBLIC_COLLECTION,
|
|
1828
|
+
cc: ctx.getFollowersUri(bot.identifier),
|
|
1829
|
+
content: "Expired poll?",
|
|
1830
|
+
inclusiveOptions: [],
|
|
1831
|
+
exclusiveOptions: [new Note({
|
|
1832
|
+
name: "Yes",
|
|
1833
|
+
replies: new Collection({ totalItems: 0 })
|
|
1834
|
+
}), new Note({
|
|
1835
|
+
name: "No",
|
|
1836
|
+
replies: new Collection({ totalItems: 0 })
|
|
1837
|
+
})],
|
|
1838
|
+
endTime: Temporal.Now.instant().subtract({ hours: 1 }),
|
|
1839
|
+
voters: 0
|
|
1840
|
+
}),
|
|
1841
|
+
published: Temporal.Now.instant()
|
|
1842
|
+
});
|
|
1843
|
+
await repository.addMessage(expiredPollId, expiredPoll);
|
|
1844
|
+
ctx.sentActivities = [];
|
|
1845
|
+
ctx.forwardedRecipients = [];
|
|
1846
|
+
receivedVote = null;
|
|
1847
|
+
const expiredVoteCreate = new Create({
|
|
1848
|
+
id: new URL("https://example.com/ap/create/vote4"),
|
|
1849
|
+
actor: voter,
|
|
1850
|
+
to: PUBLIC_COLLECTION,
|
|
1851
|
+
object: new Note({
|
|
1852
|
+
id: new URL("https://example.com/ap/note/vote4"),
|
|
1853
|
+
attribution: voter,
|
|
1854
|
+
to: PUBLIC_COLLECTION,
|
|
1855
|
+
name: "Yes",
|
|
1856
|
+
replyTarget: expiredPoll.objectId,
|
|
1857
|
+
content: "Yes"
|
|
1858
|
+
}),
|
|
1859
|
+
published: Temporal.Now.instant()
|
|
1860
|
+
});
|
|
1861
|
+
await bot.onCreated(ctx, expiredVoteCreate);
|
|
1862
|
+
assert.deepStrictEqual(receivedVote, null, "onVote should not be called for expired poll");
|
|
1863
|
+
});
|
|
1864
|
+
await t.test("ignore vote with invalid option", async () => {
|
|
1865
|
+
ctx.sentActivities = [];
|
|
1866
|
+
ctx.forwardedRecipients = [];
|
|
1867
|
+
receivedVote = null;
|
|
1868
|
+
const invalidVoteCreate = new Create({
|
|
1869
|
+
id: new URL("https://example.com/ap/create/vote5"),
|
|
1870
|
+
actor: voter,
|
|
1871
|
+
to: PUBLIC_COLLECTION,
|
|
1872
|
+
object: new Note({
|
|
1873
|
+
id: new URL("https://example.com/ap/note/vote5"),
|
|
1874
|
+
attribution: voter,
|
|
1875
|
+
to: PUBLIC_COLLECTION,
|
|
1876
|
+
name: "Purple",
|
|
1877
|
+
replyTarget: poll.objectId,
|
|
1878
|
+
content: "Purple"
|
|
1879
|
+
}),
|
|
1880
|
+
published: Temporal.Now.instant()
|
|
1881
|
+
});
|
|
1882
|
+
await bot.onCreated(ctx, invalidVoteCreate);
|
|
1883
|
+
assert.deepStrictEqual(receivedVote, null, "onVote should not be called for invalid option");
|
|
1884
|
+
});
|
|
1885
|
+
});
|
|
1640
1886
|
|
|
1641
1887
|
//#endregion
|
|
1642
1888
|
//# sourceMappingURL=bot-impl.test.js.map
|