discourse_api 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -0
  3. data/examples/invite_users.rb +3 -0
  4. data/examples/sso.rb +14 -0
  5. data/examples/topic_lists.rb +4 -0
  6. data/lib/discourse_api/api/categories.rb +1 -1
  7. data/lib/discourse_api/api/invite.rb +4 -0
  8. data/lib/discourse_api/api/notifications.rb +10 -0
  9. data/lib/discourse_api/api/private_messages.rb +10 -0
  10. data/lib/discourse_api/api/sso.rb +17 -0
  11. data/lib/discourse_api/api/topics.rb +12 -0
  12. data/lib/discourse_api/api/users.rb +3 -3
  13. data/lib/discourse_api/client.rb +6 -0
  14. data/lib/discourse_api/version.rb +1 -1
  15. data/lib/single_sign_on.rb +98 -0
  16. data/spec/discourse_api/api/categories_spec.rb +2 -8
  17. data/spec/discourse_api/api/notifications_spec.rb +24 -0
  18. data/spec/discourse_api/api/private_messages_spec.rb +22 -0
  19. data/spec/discourse_api/api/search_spec.rb +1 -5
  20. data/spec/discourse_api/api/topics_spec.rb +30 -17
  21. data/spec/discourse_api/api/users_spec.rb +48 -12
  22. data/spec/discourse_api/client_spec.rb +4 -0
  23. data/spec/fixtures/categories.json +72 -1
  24. data/spec/fixtures/category_latest_topics.json +92 -1
  25. data/spec/fixtures/hot.json +113 -1
  26. data/spec/fixtures/latest.json +115 -1
  27. data/spec/fixtures/new.json +113 -1
  28. data/spec/fixtures/notifications.json +16 -0
  29. data/spec/fixtures/private_messages.json +69 -0
  30. data/spec/fixtures/search.json +24 -1
  31. data/spec/fixtures/topic.json +739 -1
  32. data/spec/fixtures/topic_invite_user.json +3 -0
  33. data/spec/fixtures/topics_created_by.json +49 -1
  34. data/spec/fixtures/user.json +65 -1
  35. data/spec/fixtures/user_update_user.json +3 -0
  36. data/spec/fixtures/user_update_username.json +3 -0
  37. metadata +21 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b27fccecba3357cb727bb0b241e29613ddf4d6c
4
- data.tar.gz: 9eff8ed55d066031a9ca7b875ecbae247c8f54b7
3
+ metadata.gz: 30c8f8cfc3ece69e96755f29c5765f204d505b10
4
+ data.tar.gz: 80873e28b06c2912282a2a9482d579536d97e250
5
5
  SHA512:
6
- metadata.gz: 2dc325485d107e56f286baa033ffbefaf646c32611cfbea7b285a7d628445be7d6e900d7a0626516f6d1fb428d6e8ac6363803349845f51cebba0dbf66c846df
7
- data.tar.gz: cf520bd3e1baba478c6f4ad7ece1f3419dfccdfdb8fdf6d54cec01a3a1433d06bbf254656b457bfb39e14090e329b05e7a5923518b90af185d105f7065a789e8
6
+ metadata.gz: 4fb815d8b714c4c0a90e931265b4d76a027848303c47bec066dbc79a7c3844026c4c8800b9fe88d89ffe460cf17ce97a67de9ea2dc9711e3a2f4c70f3ada1ba0
7
+ data.tar.gz: eba82e043e294893e8655fa8efd1b0c923657f03aa691daf8455739d0bf6b6841b5b5f10624cd8333248494eaac7fa1e40a64b7578a4963adc5746bcfb50c28f
data/README.md CHANGED
@@ -29,6 +29,8 @@ few endpoints available:
29
29
 
30
30
  ```ruby
31
31
  client = DiscourseApi::Client.new("http://try.discourse.org")
32
+ client.api_key = "YOUR_API_KEY"
33
+ client.api_username = "YOUR_USERNAME"
32
34
 
33
35
  # Topic endpoints
34
36
  client.latest_topics #=> Gets a list of the latest topics
@@ -43,6 +45,15 @@ client.search("sandbox") #=> Gets a list of topics that m
43
45
  # Categories endpoint
44
46
  client.categories #=> Gets a list of categories
45
47
  client.category_latest_posts("category-slug") #=> Gets a list of latest posts in a category
48
+
49
+ # SSO endpoint
50
+ client.sync_sso( #=> Synchronizes the SSO record
51
+ sso_secret: "discourse_sso_rocks",
52
+ name: "Test Name",
53
+ username: "test_name",
54
+ email: "name@example.com",
55
+ external_id: "2"
56
+ )
46
57
  ```
47
58
 
48
59
 
@@ -5,6 +5,9 @@ client = DiscourseApi::Client.new("http://localhost:3000")
5
5
  client.api_key = "YOUR_API_KEY"
6
6
  client.api_username = "YOUR_USERNAME"
7
7
 
8
+ # invite user
9
+ client.invite_user(email: "name@example.com", group_ids: "41,42")
10
+
8
11
  # invite to a topic
9
12
  client.invite_user_to_topic(email: "foo@bar.com", topic_id: 1)
10
13
 
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require File.expand_path('../../lib/discourse_api', __FILE__)
3
+
4
+ client = DiscourseApi::Client.new("http://localhost:3000")
5
+ client.api_key = "YOUR_API_KEY"
6
+ client.api_username = "YOUR_USERNAME"
7
+
8
+ client.sync_sso(
9
+ sso_secret: "discourse_sso_rocks",
10
+ name: "Test Name",
11
+ username: "test_name",
12
+ email: "name@example.com",
13
+ external_id: "2"
14
+ )
@@ -7,5 +7,9 @@ client.api_username = "YOUR_USERNAME"
7
7
 
8
8
  # get latest topics
9
9
  puts client.latest_topics({})
10
+
11
+ # recategorize topic
12
+ puts client.recategorize_topic(topic_id: 108, category_id: 5)
13
+
10
14
  # get all categories
11
15
  puts client.categories({})
@@ -7,7 +7,7 @@ module DiscourseApi
7
7
  end
8
8
 
9
9
  def category_latest_topics(category_slug)
10
- response = get("/category/#{category_slug}.json")
10
+ response = get("/category/#{category_slug}/l/latest.json")
11
11
  response[:body]['topic_list']['topics']
12
12
  end
13
13
  end
@@ -1,6 +1,10 @@
1
1
  module DiscourseApi
2
2
  module API
3
3
  module Invite
4
+ def invite_user(params={})
5
+ post("/invites", params)
6
+ end
7
+
4
8
  def invite_user_to_topic(params={})
5
9
  post("/t/#{params[:topic_id]}/invite", params)
6
10
  end
@@ -0,0 +1,10 @@
1
+ module DiscourseApi
2
+ module API
3
+ module Notifications
4
+ def notifications
5
+ response = get('/notifications.json')
6
+ response[:body]
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module DiscourseApi
2
+ module API
3
+ module PrivateMessages
4
+ def private_messages(username, *args)
5
+ response = get("topics/private-messages/#{username}.json", args)
6
+ response[:body]['topic_list']['topics']
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'single_sign_on'
2
+
3
+ module DiscourseApi
4
+ module API
5
+ module SSO
6
+ def sync_sso(params={})
7
+ sso = SingleSignOn.new
8
+ sso.sso_secret = params[:sso_secret]
9
+ sso.name = params[:name]
10
+ sso.username = params[:username]
11
+ sso.email = params[:email]
12
+ sso.external_id = params[:external_id]
13
+ post("/admin/users/sync_sso/", sso.payload)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -15,6 +15,14 @@ module DiscourseApi
15
15
  response[:body]['topic_list']['topics']
16
16
  end
17
17
 
18
+ def rename_topic(topic_id, title)
19
+ put("/t/#{topic_id}.json", { topic_id: topic_id, title: title })
20
+ end
21
+
22
+ def recategorize_topic(topic_id, category_id)
23
+ put("/t/#{topic_id}.json", { topic_id: topic_id, category_id: category_id })
24
+ end
25
+
18
26
  def topic(id, *args)
19
27
  response = get("/t/#{id}.json", args)
20
28
  response[:body]
@@ -24,6 +32,10 @@ module DiscourseApi
24
32
  response = get("/topics/created-by/#{username}.json", args)
25
33
  response[:body]['topic_list']['topics']
26
34
  end
35
+
36
+ def delete_topic(id)
37
+ delete("/t/#{id}.json")
38
+ end
27
39
  end
28
40
  end
29
41
  end
@@ -27,11 +27,11 @@ module DiscourseApi
27
27
  end
28
28
 
29
29
  # Create a user
30
- def create_user(*args)
30
+ def create_user(args={})
31
31
  # First retrieve the honeypot values
32
32
  response = get("/users/hp.json")
33
- args.first[:password_confirmation] = response[:body]['value']
34
- args.first[:challenge] = response[:body]['challenge'].reverse
33
+ args[:password_confirmation] = response[:body]['value']
34
+ args[:challenge] = response[:body]['challenge'].reverse
35
35
 
36
36
  # POST the args
37
37
  post("/users", args)
@@ -4,9 +4,12 @@ require 'json'
4
4
  require 'discourse_api/version'
5
5
  require 'discourse_api/api/categories'
6
6
  require 'discourse_api/api/search'
7
+ require 'discourse_api/api/sso'
7
8
  require 'discourse_api/api/topics'
8
9
  require 'discourse_api/api/users'
9
10
  require 'discourse_api/api/invite'
11
+ require 'discourse_api/api/private_messages'
12
+ require 'discourse_api/api/notifications'
10
13
 
11
14
  module DiscourseApi
12
15
  class Client
@@ -15,9 +18,12 @@ module DiscourseApi
15
18
 
16
19
  include DiscourseApi::API::Categories
17
20
  include DiscourseApi::API::Search
21
+ include DiscourseApi::API::SSO
18
22
  include DiscourseApi::API::Topics
19
23
  include DiscourseApi::API::Users
20
24
  include DiscourseApi::API::Invite
25
+ include DiscourseApi::API::PrivateMessages
26
+ include DiscourseApi::API::Notifications
21
27
 
22
28
  def initialize(host, api_key=nil, api_username=nil)
23
29
  @host = host
@@ -1,3 +1,3 @@
1
1
  module DiscourseApi
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.4"
3
3
  end
@@ -0,0 +1,98 @@
1
+ require 'base64'
2
+ require 'rack'
3
+ require 'openssl'
4
+
5
+ class SingleSignOn
6
+ ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update,
7
+ :about_me, :external_id]
8
+ FIXNUMS = []
9
+ NONCE_EXPIRY_TIME = 600 # 10 minutes
10
+
11
+ attr_accessor(*ACCESSORS)
12
+ attr_accessor :sso_secret, :sso_url
13
+
14
+ def self.sso_secret
15
+ raise RuntimeError, "sso_secret not implemented on class, be sure to set it on instance"
16
+ end
17
+
18
+ def self.sso_url
19
+ raise RuntimeError, "sso_url not implemented on class, be sure to set it on instance"
20
+ end
21
+
22
+ def self.parse(payload, sso_secret = nil)
23
+ sso = new
24
+ sso.sso_secret = sso_secret if sso_secret
25
+
26
+ parsed = Rack::Utils.parse_query(payload)
27
+ if sso.sign(parsed["sso"]) != parsed["sig"]
28
+ raise RuntimeError, "Bad signature for payload"
29
+ end
30
+
31
+ decoded = Base64.decode64(parsed["sso"])
32
+ decoded_hash = Rack::Utils.parse_query(decoded)
33
+
34
+ ACCESSORS.each do |k|
35
+ val = decoded_hash[k.to_s]
36
+ val = val.to_i if FIXNUMS.include? k
37
+ sso.send("#{k}=", val)
38
+ end
39
+
40
+ decoded_hash.each do |k,v|
41
+ # 1234567
42
+ # custom.
43
+ #
44
+ if k[0..6] == "custom."
45
+ field = k[7..-1]
46
+ sso.custom_fields[field] = v
47
+ end
48
+ end
49
+
50
+ sso
51
+ end
52
+
53
+ def sso_secret
54
+ @sso_secret || self.class.sso_secret
55
+ end
56
+
57
+ def sso_url
58
+ @sso_url || self.class.sso_url
59
+ end
60
+
61
+ def custom_fields
62
+ @custom_fields ||= {}
63
+ end
64
+
65
+
66
+ def sign(payload)
67
+ OpenSSL::HMAC.hexdigest("sha256", sso_secret, payload)
68
+ end
69
+
70
+
71
+ def to_url(base_url=nil)
72
+ base = "#{base_url || sso_url}"
73
+ "#{base}#{base.include?('?') ? '&' : '?'}#{payload}"
74
+ end
75
+
76
+ def payload
77
+ payload = Base64.encode64(unsigned_payload)
78
+ "sso=#{CGI::escape(payload)}&sig=#{sign(payload)}"
79
+ end
80
+
81
+ def unsigned_payload
82
+ payload = {}
83
+ ACCESSORS.each do |k|
84
+ next unless (val = send k)
85
+
86
+ payload[k] = val
87
+ end
88
+
89
+ if @custom_fields
90
+ @custom_fields.each do |k,v|
91
+ payload["custom.#{k}"] = v.to_s
92
+ end
93
+ end
94
+
95
+ Rack::Utils.build_query(payload)
96
+ end
97
+
98
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DiscourseApi::API::Categories do
4
- subject { DiscourseApi::Client.new("http://localhost:3000") }
4
+ subject { DiscourseApi::Client.new("http://localhost:3000", "test_d7fd0429940", "test_user" )}
5
5
 
6
6
  describe "#categories" do
7
7
  before do
@@ -9,15 +9,11 @@ describe DiscourseApi::API::Categories do
9
9
  end
10
10
 
11
11
  it "requests the correct resource" do
12
- subject.api_key = 'test_d7fd0429940'
13
- subject.api_username = 'test_user'
14
12
  subject.categories
15
13
  expect(a_get("http://localhost:3000/categories.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
16
14
  end
17
15
 
18
16
  it "returns the requested categories" do
19
- subject.api_key = 'test_d7fd0429940'
20
- subject.api_username = 'test_user'
21
17
  categories = subject.categories
22
18
  expect(categories).to be_an Array
23
19
  expect(categories.first).to be_a Hash
@@ -26,12 +22,10 @@ describe DiscourseApi::API::Categories do
26
22
 
27
23
  describe '#category_latest_topics' do
28
24
  before do
29
- stub_get("http://localhost:3000/category/category-slug.json?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("category_latest_topics.json"), headers: { content_type: "application/json" })
25
+ stub_get("http://localhost:3000/category/category-slug/l/latest.json?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("category_latest_topics.json"), headers: { content_type: "application/json" })
30
26
  end
31
27
 
32
28
  it "returns the latest topics in a category" do
33
- subject.api_key = 'test_d7fd0429940'
34
- subject.api_username = 'test_user'
35
29
  latest_topics = subject.category_latest_topics('category-slug')
36
30
  expect(latest_topics).to be_an Array
37
31
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe DiscourseApi::API::Notifications do
4
+ subject { DiscourseApi::Client.new("http://localhost:3000", "test_d7fd0429940", "test_user") }
5
+
6
+ describe "#notifications" do
7
+
8
+ before do
9
+ stub_get("http://localhost:3000/notifications.json?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("notifications.json"), headers: { content_type: "application/json" })
10
+ end
11
+
12
+ it "requests the correct resource" do
13
+ subject.notifications
14
+ expect(a_get("http://localhost:3000/notifications.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
15
+ end
16
+
17
+ it "returns the requested notifications" do
18
+ notifications = subject.notifications
19
+ expect(notifications).to be_an Array
20
+ expect(notifications.first).to be_an Hash
21
+ expect(notifications[0]['notification_type']).to eq(9)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe DiscourseApi::API::PrivateMessages do
4
+ subject { DiscourseApi::Client.new("http://localhost:3000", "test_d7fd0429940", "test_user") }
5
+
6
+ describe "#private_messages" do
7
+ before do
8
+ stub_get("http://localhost:3000/topics/private-messages/test_user.json?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("private_messages.json"), headers: { content_type: "application/json" })
9
+ end
10
+
11
+ it "requests the correct resource" do
12
+ subject.private_messages('test_user')
13
+ expect(a_get("http://localhost:3000/topics/private-messages/test_user.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
14
+ end
15
+
16
+ it "returns the requested private messages" do
17
+ private_messages = subject.private_messages('test_user')
18
+ expect(private_messages).to be_an Array
19
+ end
20
+ end
21
+
22
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DiscourseApi::API::Search do
4
- subject { DiscourseApi::Client.new("http://localhost:3000") }
4
+ subject { DiscourseApi::Client.new("http://localhost:3000", "test_d7fd0429940", "test_user" )}
5
5
 
6
6
  describe "#search" do
7
7
  before do
@@ -9,15 +9,11 @@ describe DiscourseApi::API::Search do
9
9
  end
10
10
 
11
11
  it "requests the correct resource" do
12
- subject.api_key = 'test_d7fd0429940'
13
- subject.api_username = 'test_user'
14
12
  subject.search("test")
15
13
  expect(a_get("http://localhost:3000/search.json?api_key=test_d7fd0429940&api_username=test_user").with(query: { term: "test"} )).to have_been_made
16
14
  end
17
15
 
18
16
  it "returns the requested search" do
19
- subject.api_key = 'test_d7fd0429940'
20
- subject.api_username = 'test_user'
21
17
  results = subject.search("test")
22
18
  expect(results).to be_an Array
23
19
  expect(results.first).to be_a Hash
@@ -1,10 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DiscourseApi::API::Topics do
4
- subject { DiscourseApi::Client.new("http://localhost:3000") }
4
+ subject { DiscourseApi::Client.new("http://localhost:3000", "test_d7fd0429940", "test_user") }
5
5
 
6
6
  describe "#invite_user_to_topic" do
7
- it "needs to have a test written for it"
7
+ before do
8
+ stub_post("http://localhost:3000/t/12/invite?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("topic_invite_user.json"), headers: { content_type: "application/json" })
9
+ end
10
+
11
+ it "requests the correct resource" do
12
+ subject.invite_user_to_topic(email: "fake_user@example.com", topic_id: 12)
13
+ expect(a_post("http://localhost:3000/t/12/invite?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
14
+ end
15
+
16
+ it "returns success" do
17
+ response = subject.invite_user_to_topic(email: "fake_user@example.com", topic_id: 12)
18
+ expect(response[:body]['success']).to be_truthy
19
+ end
8
20
  end
9
21
 
10
22
  describe "#latest_topics" do
@@ -13,15 +25,11 @@ describe DiscourseApi::API::Topics do
13
25
  end
14
26
 
15
27
  it "requests the correct resource" do
16
- subject.api_key = 'test_d7fd0429940'
17
- subject.api_username = 'test_user'
18
28
  subject.latest_topics
19
29
  expect(a_get("http://localhost:3000/latest.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
20
30
  end
21
31
 
22
32
  it "returns the requested topics" do
23
- subject.api_key = 'test_d7fd0429940'
24
- subject.api_username = 'test_user'
25
33
  topics = subject.latest_topics
26
34
  expect(topics).to be_an Array
27
35
  expect(topics.first).to be_a Hash
@@ -34,14 +42,11 @@ describe DiscourseApi::API::Topics do
34
42
  end
35
43
 
36
44
  it "requests the correct resource" do
37
- subject.api_key = 'test_d7fd0429940'
38
- subject.api_username = 'test_user'
39
45
  subject.new_topics
40
46
  expect(a_get("http://localhost:3000/new.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
41
47
  end
42
48
 
43
49
  it "returns the requested topics" do
44
- subject.api_key = 'test_d7fd0429940'
45
50
  subject.api_username = 'test_user'
46
51
  topics = subject.new_topics
47
52
  expect(topics).to be_an Array
@@ -55,36 +60,44 @@ describe DiscourseApi::API::Topics do
55
60
  end
56
61
 
57
62
  it "requests the correct resource" do
58
- subject.api_key = 'test_d7fd0429940'
59
- subject.api_username = 'test_user'
60
63
  subject.topic(57)
61
64
  expect(a_get("http://localhost:3000/t/57.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
62
65
  end
63
66
 
64
67
  it "returns the requested topic" do
65
- subject.api_key = 'test_d7fd0429940'
66
- subject.api_username = 'test_user'
67
68
  topic = subject.topic(57)
68
69
  expect(topic).to be_a Hash
69
70
  expect(topic["id"]).to eq(57)
70
71
  end
71
72
  end
72
73
 
74
+ describe "#update_topic" do
75
+ before do
76
+ stub_put("http://localhost:3000/t/57.json?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("topic.json"), headers: { content_type: "application/json" })
77
+ end
78
+
79
+ it "renames the topic" do
80
+ subject.rename_topic(57, "A new title!")
81
+ expect(a_put("http://localhost:3000/t/57.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
82
+ end
83
+
84
+ it "assigns the topic a new category" do
85
+ subject.recategorize_topic(57, 3)
86
+ expect(a_put("http://localhost:3000/t/57.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
87
+ end
88
+ end
89
+
73
90
  describe "#topics_by" do
74
91
  before do
75
92
  stub_get("http://localhost:3000/topics/created-by/test.json?api_key=test_d7fd0429940&api_username=test_user").to_return(body: fixture("topics_created_by.json"), headers: { content_type: "application/json" })
76
93
  end
77
94
 
78
95
  it "requests the correct resource" do
79
- subject.api_key = 'test_d7fd0429940'
80
- subject.api_username = 'test_user'
81
96
  subject.topics_by('test')
82
97
  expect(a_get("http://localhost:3000/topics/created-by/test.json?api_key=test_d7fd0429940&api_username=test_user")).to have_been_made
83
98
  end
84
99
 
85
100
  it "returns the requested topics" do
86
- subject.api_key = 'test_d7fd0429940'
87
- subject.api_username = 'test_user'
88
101
  topics = subject.topics_by('test')
89
102
  expect(topics).to be_an Array
90
103
  expect(topics.first).to be_a Hash