discourse_api 0.44.0 → 0.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +13 -17
- data/.gitignore +0 -19
- data/CHANGELOG.md +38 -7
- data/discourse_api.gemspec +5 -5
- data/examples/bookmark_topic.rb +15 -0
- data/examples/category.rb +3 -0
- data/examples/invite_users.rb +20 -2
- data/examples/manage_api_keys.rb +42 -0
- data/examples/notifications.rb +18 -0
- data/examples/topic_lists.rb +3 -0
- data/lib/discourse_api/api/api_key.rb +15 -9
- data/lib/discourse_api/api/categories.rb +41 -13
- data/lib/discourse_api/api/invite.rb +67 -2
- data/lib/discourse_api/api/notifications.rb +5 -2
- data/lib/discourse_api/api/private_messages.rb +10 -3
- data/lib/discourse_api/api/search.rb +1 -1
- data/lib/discourse_api/api/topics.rb +37 -2
- data/lib/discourse_api/api/users.rb +1 -1
- data/lib/discourse_api/client.rb +13 -1
- data/lib/discourse_api/error.rb +3 -0
- data/lib/discourse_api/version.rb +1 -1
- data/spec/discourse_api/api/api_key_spec.rb +59 -35
- data/spec/discourse_api/api/categories_spec.rb +90 -0
- data/spec/discourse_api/api/invite_spec.rb +123 -0
- data/spec/discourse_api/api/private_messages_spec.rb +4 -4
- data/spec/discourse_api/api/search_spec.rb +2 -2
- data/spec/discourse_api/api/topics_spec.rb +71 -0
- data/spec/discourse_api/client_spec.rb +15 -0
- data/spec/fixtures/api_key.json +12 -0
- data/spec/fixtures/list_api_keys.json +14 -0
- data/spec/fixtures/notification_success.json +3 -0
- data/spec/fixtures/retrieve_invite.json +116 -0
- data/spec/fixtures/top.json +108 -0
- data/spec/fixtures/topic_posts.json +1 -0
- metadata +24 -13
- data/spec/fixtures/api.json +0 -12
- data/spec/fixtures/generate_master_key.json +0 -7
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe DiscourseApi::API::Invite do
|
5
|
+
subject { DiscourseApi::Client.new("#{host}", "test_d7fd0429940", "test_user") }
|
6
|
+
|
7
|
+
describe "#invite_user" do
|
8
|
+
before do
|
9
|
+
stub_post("#{host}/invites").to_return(body: fixture("topic_invite_user.json"), headers: { content_type: "application/json" })
|
10
|
+
end
|
11
|
+
|
12
|
+
it "requests the correct resource" do
|
13
|
+
subject.invite_user(email: "fake_user@example.com", group_ids: "41,42")
|
14
|
+
expect(a_post("#{host}/invites")).to have_been_made
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns success" do
|
18
|
+
response = subject.invite_user(email: "fake_user@example.com", group_ids: "41,42")
|
19
|
+
expect(response).to be_a Hash
|
20
|
+
expect(response['success']).to be_truthy
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#update_invite" do
|
25
|
+
before do
|
26
|
+
stub_put("#{host}/invites/27").to_return(body: fixture("topic_invite_user.json"), headers: { content_type: "application/json" })
|
27
|
+
end
|
28
|
+
|
29
|
+
it "updates invite" do
|
30
|
+
subject.update_invite(27, email: "namee@example.com")
|
31
|
+
expect(a_put("#{host}/invites/27")).to have_been_made
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#retrieve_invite" do
|
36
|
+
before do
|
37
|
+
stub_get("#{host}/invites/retrieve.json?email=foo@bar.com").to_return(body: fixture("retrieve_invite.json"), headers: { content_type: "application/json" })
|
38
|
+
end
|
39
|
+
|
40
|
+
it "requests the correct resource" do
|
41
|
+
subject.retrieve_invite(email: "foo@bar.com")
|
42
|
+
expect(a_get("#{host}/invites/retrieve.json?email=foo@bar.com")).to have_been_made
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns the requested topics" do
|
46
|
+
invites = subject.retrieve_invite(email: "foo@bar.com")
|
47
|
+
expect(invites).to be_an Hash
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns the requested invite" do
|
51
|
+
invites = subject.retrieve_invite(email: "foo@bar.com")
|
52
|
+
expect(invites["email"]).to eq("foo@bar.com")
|
53
|
+
expect(invites).to have_key("invite_key")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#destroy_all_expired_invites" do
|
58
|
+
let(:url) { "#{host}/invites/destroy-all-expired" }
|
59
|
+
|
60
|
+
before do
|
61
|
+
stub_post(url)
|
62
|
+
.to_return(
|
63
|
+
body: '{"success": "OK"}',
|
64
|
+
headers: { content_type: "application/json" }
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "destroys all expired invites" do
|
69
|
+
subject.destroy_all_expired_invites
|
70
|
+
expect(a_post(url)).to have_been_made
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#resend_all_invites" do
|
75
|
+
let(:url) { "#{host}/invites/reinvite-all" }
|
76
|
+
|
77
|
+
before do
|
78
|
+
stub_post(url)
|
79
|
+
.to_return(
|
80
|
+
body: '{"success": "OK"}',
|
81
|
+
headers: { content_type: "application/json" }
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "resends all invites" do
|
86
|
+
subject.resend_all_invites
|
87
|
+
expect(a_post(url)).to have_been_made
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#resend_invite" do
|
92
|
+
let(:url) { "#{host}/invites/reinvite" }
|
93
|
+
|
94
|
+
before do
|
95
|
+
stub_post(url)
|
96
|
+
.to_return(
|
97
|
+
body: '{"success": "OK"}',
|
98
|
+
headers: { content_type: "application/json" }
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "resends invite" do
|
103
|
+
subject.resend_invite("foo@bar.com")
|
104
|
+
expect(a_post(url)).to have_been_made
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#destroy_invite" do
|
109
|
+
let(:url) { "#{host}/invites?id=27" }
|
110
|
+
|
111
|
+
before do
|
112
|
+
stub_delete(url).to_return(
|
113
|
+
body: '{"success": "OK"}',
|
114
|
+
headers: { content_type: "application/json" }
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "destroys the invite" do
|
119
|
+
subject.destroy_invite(27)
|
120
|
+
expect(a_delete(url)).to have_been_made
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -36,19 +36,19 @@ describe DiscourseApi::API::PrivateMessages do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
describe '#
|
39
|
+
describe '#create_pm' do
|
40
40
|
before do
|
41
41
|
stub_post("#{host}/posts")
|
42
|
-
subject.
|
42
|
+
subject.create_pm(
|
43
43
|
title: "Confidential: Hello World!",
|
44
44
|
raw: "This is the raw markdown for my private message",
|
45
|
-
|
45
|
+
target_recipients: "user1,user2"
|
46
46
|
)
|
47
47
|
end
|
48
48
|
|
49
49
|
it "makes a create private message request" do
|
50
50
|
expect(a_post("#{host}/posts").with(body:
|
51
|
-
'archetype=private_message&raw=This+is+the+raw+markdown+for+my+private+message&
|
51
|
+
'archetype=private_message&raw=This+is+the+raw+markdown+for+my+private+message&target_recipients=user1%2Cuser2&title=Confidential%3A+Hello+World%21')
|
52
52
|
).to have_been_made
|
53
53
|
end
|
54
54
|
end
|
@@ -6,12 +6,12 @@ describe DiscourseApi::API::Search do
|
|
6
6
|
|
7
7
|
describe "#search" do
|
8
8
|
before do
|
9
|
-
stub_get("#{host}/search
|
9
|
+
stub_get("#{host}/search").with(query: { q: "test" }).to_return(body: fixture("search.json"), headers: { content_type: "application/json" })
|
10
10
|
end
|
11
11
|
|
12
12
|
it "requests the correct resource" do
|
13
13
|
subject.search("test")
|
14
|
-
expect(a_get("#{host}/search
|
14
|
+
expect(a_get("#{host}/search").with(query: { q: "test" })).to have_been_made
|
15
15
|
end
|
16
16
|
|
17
17
|
it "returns the requested search" do
|
@@ -25,6 +25,11 @@ describe DiscourseApi::API::Topics do
|
|
25
25
|
expect(a_post("#{host}/t/12/invite")).to have_been_made
|
26
26
|
end
|
27
27
|
|
28
|
+
it "requests the correct resource with new method 'invite_to_topic'" do
|
29
|
+
subject.invite_to_topic(12, email: "fake_user@example.com")
|
30
|
+
expect(a_post("#{host}/t/12/invite")).to have_been_made
|
31
|
+
end
|
32
|
+
|
28
33
|
it "returns success" do
|
29
34
|
response = subject.invite_user_to_topic(email: "fake_user@example.com", topic_id: 12)
|
30
35
|
expect(response).to be_a Hash
|
@@ -55,6 +60,29 @@ describe DiscourseApi::API::Topics do
|
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
63
|
+
describe "#top_topics" do
|
64
|
+
before do
|
65
|
+
stub_get("#{host}/top.json").to_return(body: fixture("top.json"), headers: { content_type: "application/json" })
|
66
|
+
end
|
67
|
+
|
68
|
+
it "requests the correct resource" do
|
69
|
+
subject.top_topics
|
70
|
+
expect(a_get("#{host}/top.json")).to have_been_made
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns the requested topics" do
|
74
|
+
topics = subject.top_topics
|
75
|
+
expect(topics).to be_an Array
|
76
|
+
expect(topics.first).to be_a Hash
|
77
|
+
end
|
78
|
+
|
79
|
+
it "can take a hash param" do
|
80
|
+
topics = subject.top_topics({})
|
81
|
+
expect(topics).to be_an Array
|
82
|
+
expect(topics.first).to be_a Hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
58
86
|
describe "#new_topics" do
|
59
87
|
before do
|
60
88
|
stub_get("#{host}/new.json").to_return(body: fixture("new.json"), headers: { content_type: "application/json" })
|
@@ -147,6 +175,14 @@ describe DiscourseApi::API::Topics do
|
|
147
175
|
expect(body['post_stream']['posts']).to be_an Array
|
148
176
|
expect(body['post_stream']['posts'].first).to be_a Hash
|
149
177
|
end
|
178
|
+
|
179
|
+
it "can retrieve a topic posts' raw attribute" do
|
180
|
+
body = subject.topic_posts(57, [123], { include_raw: true })
|
181
|
+
expect(body).to be_a Hash
|
182
|
+
expect(body['post_stream']['posts']).to be_an Array
|
183
|
+
expect(body['post_stream']['posts'].first).to be_a Hash
|
184
|
+
expect(body['post_stream']['posts'].first['raw']).to be_an Array
|
185
|
+
end
|
150
186
|
end
|
151
187
|
|
152
188
|
describe "#create_topic_with_tags" do
|
@@ -166,4 +202,39 @@ describe DiscourseApi::API::Topics do
|
|
166
202
|
end
|
167
203
|
end
|
168
204
|
|
205
|
+
describe "#topic_set_user_notification_level" do
|
206
|
+
before do
|
207
|
+
stub_post("#{host}/t/1/notifications").to_return(body: fixture("notification_success.json"), headers: { content_type: "application/json" })
|
208
|
+
end
|
209
|
+
|
210
|
+
it "makes the post request" do
|
211
|
+
response = subject.topic_set_user_notification_level(1, notification_level: 3)
|
212
|
+
expect(a_post("#{host}/t/1/notifications").with(body: "notification_level=3")).to have_been_made
|
213
|
+
expect(response['success']).to eq('OK')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "#bookmark_topic" do
|
218
|
+
before do
|
219
|
+
stub_put("#{host}/t/1/bookmark.json").to_return(body: "", headers: { content_type: "application/json" })
|
220
|
+
end
|
221
|
+
|
222
|
+
it "makes the put request" do
|
223
|
+
response = subject.bookmark_topic(1)
|
224
|
+
expect(a_put("#{host}/t/1/bookmark.json")).to have_been_made
|
225
|
+
expect(response.body).to eq(nil)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "#remove_topic_bookmark" do
|
230
|
+
before do
|
231
|
+
stub_put("#{host}/t/1/remove_bookmarks.json").to_return(body: "", headers: { content_type: "application/json" })
|
232
|
+
end
|
233
|
+
|
234
|
+
it "makes the put request" do
|
235
|
+
response = subject.remove_topic_bookmark(1)
|
236
|
+
expect(a_put("#{host}/t/1/remove_bookmarks.json")).to have_been_made
|
237
|
+
expect(response.body).to eq(nil)
|
238
|
+
end
|
239
|
+
end
|
169
240
|
end
|
@@ -28,6 +28,21 @@ describe DiscourseApi::Client do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
describe "#timeout" do
|
32
|
+
context 'custom timeout' do
|
33
|
+
it "is set to Faraday connection" do
|
34
|
+
expect(subject.send(:connection).options.timeout).to eq(30)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'default timeout' do
|
39
|
+
it "is set to Faraday connection" do
|
40
|
+
subject.timeout = 25
|
41
|
+
expect(subject.send(:connection).options.timeout).to eq(25)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
31
46
|
describe "#api_key" do
|
32
47
|
it "is publically accessible" do
|
33
48
|
subject.api_key = "test_d7fd0429940"
|
@@ -0,0 +1,116 @@
|
|
1
|
+
{
|
2
|
+
"id": 26,
|
3
|
+
"invite_key": "CGUHjNC4Na",
|
4
|
+
"link": "http://localhost:3000/invites/CGUHjNC4Na",
|
5
|
+
"email": "foo@bar.com",
|
6
|
+
"emailed": true,
|
7
|
+
"custom_message": null,
|
8
|
+
"created_at": "2021-05-07T20:48:14.278Z",
|
9
|
+
"updated_at": "2021-05-07T20:48:14.278Z",
|
10
|
+
"expires_at": "2021-06-06T20:48:14.278Z",
|
11
|
+
"expired": false,
|
12
|
+
"topics": [
|
13
|
+
{
|
14
|
+
"id": 1,
|
15
|
+
"title": "About the Site Feedback category",
|
16
|
+
"fancy_title": "About the Site Feedback category",
|
17
|
+
"slug": "about-the-site-feedback-category",
|
18
|
+
"posts_count": 1
|
19
|
+
}
|
20
|
+
],
|
21
|
+
"groups": [
|
22
|
+
{
|
23
|
+
"id": 1,
|
24
|
+
"automatic": true,
|
25
|
+
"name": "admins",
|
26
|
+
"display_name": "admins",
|
27
|
+
"user_count": 1,
|
28
|
+
"mentionable_level": 0,
|
29
|
+
"messageable_level": 0,
|
30
|
+
"visibility_level": 1,
|
31
|
+
"primary_group": false,
|
32
|
+
"title": null,
|
33
|
+
"grant_trust_level": null,
|
34
|
+
"incoming_email": null,
|
35
|
+
"has_messages": true,
|
36
|
+
"flair_url": null,
|
37
|
+
"flair_bg_color": null,
|
38
|
+
"flair_color": null,
|
39
|
+
"bio_raw": "",
|
40
|
+
"bio_cooked": null,
|
41
|
+
"bio_excerpt": null,
|
42
|
+
"public_admission": false,
|
43
|
+
"public_exit": false,
|
44
|
+
"allow_membership_requests": false,
|
45
|
+
"full_name": null,
|
46
|
+
"default_notification_level": 3,
|
47
|
+
"membership_request_template": null,
|
48
|
+
"members_visibility_level": 0,
|
49
|
+
"can_see_members": true,
|
50
|
+
"can_admin_group": true,
|
51
|
+
"publish_read_state": false
|
52
|
+
},
|
53
|
+
{
|
54
|
+
"id": 2,
|
55
|
+
"automatic": true,
|
56
|
+
"name": "moderators",
|
57
|
+
"display_name": "moderators",
|
58
|
+
"user_count": 1,
|
59
|
+
"mentionable_level": 0,
|
60
|
+
"messageable_level": 99,
|
61
|
+
"visibility_level": 1,
|
62
|
+
"primary_group": false,
|
63
|
+
"title": null,
|
64
|
+
"grant_trust_level": null,
|
65
|
+
"incoming_email": null,
|
66
|
+
"has_messages": true,
|
67
|
+
"flair_url": null,
|
68
|
+
"flair_bg_color": null,
|
69
|
+
"flair_color": null,
|
70
|
+
"bio_raw": null,
|
71
|
+
"bio_cooked": null,
|
72
|
+
"bio_excerpt": null,
|
73
|
+
"public_admission": false,
|
74
|
+
"public_exit": false,
|
75
|
+
"allow_membership_requests": false,
|
76
|
+
"full_name": null,
|
77
|
+
"default_notification_level": 2,
|
78
|
+
"membership_request_template": null,
|
79
|
+
"members_visibility_level": 0,
|
80
|
+
"can_see_members": true,
|
81
|
+
"can_admin_group": true,
|
82
|
+
"publish_read_state": false
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"id": 3,
|
86
|
+
"automatic": true,
|
87
|
+
"name": "staff",
|
88
|
+
"display_name": "staff",
|
89
|
+
"user_count": 2,
|
90
|
+
"mentionable_level": 0,
|
91
|
+
"messageable_level": 0,
|
92
|
+
"visibility_level": 1,
|
93
|
+
"primary_group": false,
|
94
|
+
"title": null,
|
95
|
+
"grant_trust_level": null,
|
96
|
+
"incoming_email": null,
|
97
|
+
"has_messages": false,
|
98
|
+
"flair_url": null,
|
99
|
+
"flair_bg_color": null,
|
100
|
+
"flair_color": null,
|
101
|
+
"bio_raw": null,
|
102
|
+
"bio_cooked": null,
|
103
|
+
"bio_excerpt": null,
|
104
|
+
"public_admission": false,
|
105
|
+
"public_exit": false,
|
106
|
+
"allow_membership_requests": false,
|
107
|
+
"full_name": null,
|
108
|
+
"default_notification_level": 3,
|
109
|
+
"membership_request_template": null,
|
110
|
+
"members_visibility_level": 0,
|
111
|
+
"can_see_members": true,
|
112
|
+
"can_admin_group": true,
|
113
|
+
"publish_read_state": false
|
114
|
+
}
|
115
|
+
]
|
116
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
{
|
2
|
+
"topic_list": {
|
3
|
+
"can_create_topic": false,
|
4
|
+
"more_topics_url": "/latest.json?page=1",
|
5
|
+
"draft": null,
|
6
|
+
"draft_key": "new_topic",
|
7
|
+
"draft_sequence": null,
|
8
|
+
"topics": [
|
9
|
+
{
|
10
|
+
"id": 1,
|
11
|
+
"title": "Test topic #1",
|
12
|
+
"fancy_title": "Test topic #1",
|
13
|
+
"slug": "test-topic-1",
|
14
|
+
"posts_count": 1,
|
15
|
+
"reply_count": 0,
|
16
|
+
"highest_post_number": 1,
|
17
|
+
"image_url": null,
|
18
|
+
"created_at": "2013-02-04T15:26:25.977-05:00",
|
19
|
+
"last_posted_at": "2013-02-05T12:14:17.364-05:00",
|
20
|
+
"bumped": true,
|
21
|
+
"bumped_at": "2013-02-07T13:43:11.191-05:00",
|
22
|
+
"unseen": false,
|
23
|
+
"pinned": true,
|
24
|
+
"excerpt": "Welcome! \n\nTry is a sandbox, a safe place to play with Discourse and its features.\n\nThis site is reset every day (or even more often). Any accounts or posts you create here will not exist tomorrow! \n\nFeel free to experim…",
|
25
|
+
"visible": true,
|
26
|
+
"closed": false,
|
27
|
+
"archived": false,
|
28
|
+
"views": 268,
|
29
|
+
"like_count": 14,
|
30
|
+
"has_best_of": false,
|
31
|
+
"archetype": "regular",
|
32
|
+
"last_poster_username": "test_user",
|
33
|
+
"category_id": 1,
|
34
|
+
"posters": [
|
35
|
+
{
|
36
|
+
"extras": null,
|
37
|
+
"description": "Original Poster, Most Recent Poster",
|
38
|
+
"user_id": 1
|
39
|
+
}
|
40
|
+
]
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"id": 1,
|
44
|
+
"title": "Test topic #2",
|
45
|
+
"fancy_title": "Test topic #2",
|
46
|
+
"slug": "test-topic-1",
|
47
|
+
"posts_count": 1,
|
48
|
+
"reply_count": 0,
|
49
|
+
"highest_post_number": 2,
|
50
|
+
"image_url": null,
|
51
|
+
"created_at": "2013-11-06T13:57:47.984-05:00",
|
52
|
+
"last_posted_at": "2013-11-06T13:57:48.111-05:00",
|
53
|
+
"bumped": true,
|
54
|
+
"bumped_at": "2013-11-06T13:57:48.111-05:00",
|
55
|
+
"unseen": false,
|
56
|
+
"pinned": false,
|
57
|
+
"visible": true,
|
58
|
+
"closed": false,
|
59
|
+
"archived": false,
|
60
|
+
"views": 1,
|
61
|
+
"like_count": 0,
|
62
|
+
"has_best_of": false,
|
63
|
+
"archetype": "regular",
|
64
|
+
"last_poster_username": "test_user",
|
65
|
+
"category_id": 1,
|
66
|
+
"posters": [
|
67
|
+
{
|
68
|
+
"extras": null,
|
69
|
+
"description": "Original Poster, Most Recent Poster",
|
70
|
+
"user_id": 1
|
71
|
+
}
|
72
|
+
]
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"id": 1,
|
76
|
+
"title": "Test topic #3",
|
77
|
+
"fancy_title": "Test topic #3",
|
78
|
+
"slug": "test-topic-3",
|
79
|
+
"posts_count": 1,
|
80
|
+
"reply_count": 0,
|
81
|
+
"highest_post_number": 1,
|
82
|
+
"image_url": null,
|
83
|
+
"created_at": "2013-02-04T21:46:58.194-05:00",
|
84
|
+
"last_posted_at": "2013-11-06T13:56:27.753-05:00",
|
85
|
+
"bumped": true,
|
86
|
+
"bumped_at": "2013-11-06T13:56:27.753-05:00",
|
87
|
+
"unseen": false,
|
88
|
+
"pinned": false,
|
89
|
+
"visible": true,
|
90
|
+
"closed": false,
|
91
|
+
"archived": false,
|
92
|
+
"views": 82,
|
93
|
+
"like_count": 10,
|
94
|
+
"has_best_of": false,
|
95
|
+
"archetype": "regular",
|
96
|
+
"last_poster_username": "test_user",
|
97
|
+
"category_id": 1,
|
98
|
+
"posters": [
|
99
|
+
{
|
100
|
+
"extras": null,
|
101
|
+
"description": "Original Poster, Most Recent Poster",
|
102
|
+
"user_id": 1
|
103
|
+
}
|
104
|
+
]
|
105
|
+
}
|
106
|
+
]
|
107
|
+
}
|
108
|
+
}
|