discourse_api 0.39.3 → 0.43.1
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 +54 -0
- data/.gitignore +0 -2
- data/.rubocop.yml +2 -6
- data/CHANGELOG.md +40 -8
- data/README.md +13 -2
- data/discourse_api.gemspec +4 -6
- data/examples/change_topic_status.rb +3 -4
- data/examples/create_topic.rb +10 -0
- data/lib/discourse_api/api/api_key.rb +0 -8
- data/lib/discourse_api/api/categories.rb +5 -0
- data/lib/discourse_api/api/groups.rb +10 -2
- data/lib/discourse_api/api/sso.rb +1 -15
- data/lib/discourse_api/api/topics.rb +8 -2
- data/lib/discourse_api/client.rb +20 -4
- data/lib/discourse_api/single_sign_on.rb +32 -3
- data/lib/discourse_api/version.rb +1 -1
- data/spec/discourse_api/api/api_key_spec.rb +2 -28
- data/spec/discourse_api/api/backups_spec.rb +2 -1
- data/spec/discourse_api/api/badges_spec.rb +2 -1
- data/spec/discourse_api/api/categories_spec.rb +9 -8
- data/spec/discourse_api/api/email_spec.rb +2 -1
- data/spec/discourse_api/api/groups_spec.rb +7 -6
- data/spec/discourse_api/api/notifications_spec.rb +1 -0
- data/spec/discourse_api/api/params_spec.rb +8 -7
- data/spec/discourse_api/api/polls_spec.rb +7 -6
- data/spec/discourse_api/api/posts_spec.rb +1 -0
- data/spec/discourse_api/api/private_messages_spec.rb +1 -0
- data/spec/discourse_api/api/search_spec.rb +4 -3
- data/spec/discourse_api/api/site_settings_spec.rb +2 -1
- data/spec/discourse_api/api/sso_spec.rb +46 -3
- data/spec/discourse_api/api/topics_spec.rb +20 -1
- data/spec/discourse_api/api/uploads_spec.rb +1 -0
- data/spec/discourse_api/api/user_actions_spec.rb +1 -0
- data/spec/discourse_api/api/users_spec.rb +4 -3
- data/spec/discourse_api/client_spec.rb +11 -10
- data/spec/fixtures/create_topic_with_tags.json +65 -0
- data/spec/spec_helper.rb +2 -1
- metadata +17 -45
- data/.travis.yml +0 -11
- data/spec/fixtures/generate_api_key.json +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5b33f1f16a6fe2c48d58ec9b08ed6146789653b4a6c055a1ec7e61d3ec7fee0
|
4
|
+
data.tar.gz: e483916abc304970ac78192ecb0cc1c1ca2b58f1fdac0ea06eec4cdaa624e4ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 118c45cb081fa47d0fd3120c6dfa10b35b169d6620ea3875481a3f4c390ae269cc82b6b234fbe1ef1e7250dd2e7d9a7ab5023e2b3046b22a41de8249fb04607d
|
7
|
+
data.tar.gz: 1ba2f1ee7853b5a65406863bd404d04ef4866a3e7e5164c393f91ef1a7e02a9e1828fc7606957eb18b13db6f58ea3fff59e4e23cf89d44d8c7c7c590ba90a3fd
|
@@ -0,0 +1,54 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
push:
|
6
|
+
branches:
|
7
|
+
- master
|
8
|
+
tags:
|
9
|
+
- v*
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
build:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
|
15
|
+
strategy:
|
16
|
+
matrix:
|
17
|
+
ruby:
|
18
|
+
- 2.5
|
19
|
+
- 2.6
|
20
|
+
- 2.7
|
21
|
+
|
22
|
+
steps:
|
23
|
+
- uses: actions/checkout@v1
|
24
|
+
|
25
|
+
- name: Setup ruby
|
26
|
+
uses: actions/setup-ruby@v1
|
27
|
+
with:
|
28
|
+
ruby-version: ${{ matrix.ruby }}
|
29
|
+
architecture: 'x64'
|
30
|
+
|
31
|
+
- name: Setup bundler
|
32
|
+
run: gem install bundler
|
33
|
+
|
34
|
+
- name: Setup gems
|
35
|
+
run: bundle install
|
36
|
+
|
37
|
+
- name: Rubocop
|
38
|
+
run: bundle exec rubocop
|
39
|
+
|
40
|
+
- name: RSpec
|
41
|
+
run: bundle exec rspec
|
42
|
+
|
43
|
+
publish:
|
44
|
+
if: contains(github.ref, 'refs/tags/v')
|
45
|
+
needs: build
|
46
|
+
runs-on: ubuntu-latest
|
47
|
+
|
48
|
+
steps:
|
49
|
+
- uses: actions/checkout@v2
|
50
|
+
|
51
|
+
- name: Release Gem
|
52
|
+
uses: CvX/publish-rubygems-action@master
|
53
|
+
env:
|
54
|
+
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,43 @@
|
|
1
|
-
#
|
1
|
+
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
|
-
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
|
9
|
+
## [0.43.1] - 2020-11-04
|
10
|
+
### Fixed
|
11
|
+
- tagged verion 0.43.0 got pushed without commmit due to new master branch
|
12
|
+
protections in github. No, code changes here just making sure tags align with
|
13
|
+
commits.
|
14
|
+
|
15
|
+
## [0.43.0] - 2020-11-04
|
16
|
+
### Added
|
17
|
+
- Add pagination to list groups endpoint
|
18
|
+
### Deprecated
|
19
|
+
- `change_topic_status` has been deprecated, use `update_topic_status` instead.
|
20
|
+
|
21
|
+
## [0.42.0] - 2020-07-09
|
22
|
+
### Added
|
23
|
+
- Create topics with tags
|
24
|
+
|
25
|
+
## [0.41.0] - 2020-06-17
|
26
|
+
### Added
|
27
|
+
- Add basic auth support
|
28
|
+
|
29
|
+
### Fixed
|
30
|
+
- Fix SSO custom field prefixes
|
31
|
+
|
32
|
+
### Removed
|
33
|
+
- Obsolete api key endpoints
|
34
|
+
|
35
|
+
## [0.40.0] - 2020-05-07
|
36
|
+
### Fixed
|
37
|
+
- Add missing attributes to `sync_sso`
|
38
|
+
|
39
|
+
### Added
|
40
|
+
- Add delete category method
|
4
41
|
|
5
42
|
## [0.39.3] - 2020-04-30
|
6
43
|
### Fixed
|
@@ -217,7 +254,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
217
254
|
## [0.8.1] - 2016-03-03
|
218
255
|
### Fixed
|
219
256
|
- enable use of discourse_api to make unauthenticated requests to discourse
|
220
|
-
endpoints like /categories and /topics
|
257
|
+
endpoints like /categories and /topics
|
221
258
|
|
222
259
|
## [0.8.0] - 2016-02-28
|
223
260
|
### Added
|
@@ -274,8 +311,3 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
274
311
|
## [0.1.2] - 2014-05-11
|
275
312
|
|
276
313
|
- Release
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
data/README.md
CHANGED
@@ -34,7 +34,6 @@ client.ssl(...) #=> specify SSL connection setti
|
|
34
34
|
|
35
35
|
# Topic endpoints
|
36
36
|
client.latest_topics #=> Gets a list of the latest topics
|
37
|
-
client.hot_topics #=> Gets a list of hot topics
|
38
37
|
client.new_topics #=> Gets a list of new topics
|
39
38
|
client.topics_by("sam") #=> Gets a list of topics created by user "sam"
|
40
39
|
client.topic(57) #=> Gets the topic with id 57
|
@@ -52,7 +51,10 @@ client.sync_sso( #=> Synchronizes the SSO record
|
|
52
51
|
name: "Test Name",
|
53
52
|
username: "test_name",
|
54
53
|
email: "name@example.com",
|
55
|
-
external_id: "2"
|
54
|
+
external_id: "2",
|
55
|
+
custom_fields: {
|
56
|
+
field_1: 'potato'
|
57
|
+
}
|
56
58
|
)
|
57
59
|
|
58
60
|
# Private messages
|
@@ -80,6 +82,15 @@ end
|
|
80
82
|
|
81
83
|
Check out [lib/discourse_api/error.rb](lib/discourse_api/error.rb) and [lib/discourse_api/client.rb](lib/discourse_api/client.rb)'s `handle_error` method for the types of errors raised by the API.
|
82
84
|
|
85
|
+
If your forum has a basic HTTP authentication enabled, set user and password:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
client.basic_auth = {
|
89
|
+
user: "test",
|
90
|
+
password: "secret"
|
91
|
+
}
|
92
|
+
```
|
93
|
+
|
83
94
|
## Contributing
|
84
95
|
|
85
96
|
1. Fork it
|
data/discourse_api.gemspec
CHANGED
@@ -18,21 +18,19 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency 'faraday', '~> 0
|
22
|
-
spec.add_dependency 'faraday_middleware', '~> 0
|
21
|
+
spec.add_dependency 'faraday', '~> 1.0'
|
22
|
+
spec.add_dependency 'faraday_middleware', '~> 1.0'
|
23
23
|
spec.add_dependency 'rack', '>= 1.6'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
26
26
|
spec.add_development_dependency 'guard', '~> 2.14'
|
27
27
|
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
28
|
-
spec.add_development_dependency 'rake', '
|
28
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
29
29
|
spec.add_development_dependency 'rb-inotify', '~> 0.9'
|
30
30
|
spec.add_development_dependency 'rspec', '~> 3.4'
|
31
|
-
spec.add_development_dependency 'rubocop', '~> 0.69'
|
32
31
|
spec.add_development_dependency 'simplecov', '~> 0.11'
|
33
32
|
spec.add_development_dependency 'webmock', '~> 2.0'
|
34
|
-
spec.add_development_dependency 'rubocop-discourse'
|
35
|
-
spec.add_development_dependency 'rubocop-rspec', '~> 1.0'
|
33
|
+
spec.add_development_dependency 'rubocop-discourse'
|
36
34
|
|
37
35
|
spec.required_ruby_version = '>= 2.2.3'
|
38
36
|
end
|
@@ -16,9 +16,8 @@ response = client.create_topic(
|
|
16
16
|
raw: "This is the raw markdown for my post"
|
17
17
|
)
|
18
18
|
|
19
|
-
# get topic_id
|
19
|
+
# get topic_id from response
|
20
20
|
topic_id = response['topic_id']
|
21
|
-
topic_slug = response['topic_slug']
|
22
21
|
|
23
22
|
##
|
24
23
|
# available options (guessing from reading discourse source)
|
@@ -28,8 +27,8 @@ topic_slug = response['topic_slug']
|
|
28
27
|
|
29
28
|
# lock topic (note: api_username determines user that is performing action)
|
30
29
|
params = { status: 'closed', enabled: true, api_username: "YOUR USERNAME/USERS USERNAME" }
|
31
|
-
client.change_topic_status(
|
30
|
+
client.change_topic_status(topic_id, params)
|
32
31
|
|
33
32
|
# unlock topic (note: api_username determines user that is performing action)
|
34
33
|
params = { status: 'closed', enabled: false, api_username: "YOUR USERNAME/USERS USERNAME" }
|
35
|
-
client.change_topic_status(
|
34
|
+
client.change_topic_status(topic_id, params)
|
data/examples/create_topic.rb
CHANGED
@@ -24,3 +24,13 @@ client.create_topic(
|
|
24
24
|
title: "Your Favorite Color?",
|
25
25
|
raw: "[poll name=color]\n- Green\n- Blue\n- Red\n[/poll]"
|
26
26
|
)
|
27
|
+
|
28
|
+
# Create Topic with Tags
|
29
|
+
client.create_topic(
|
30
|
+
category: 1,
|
31
|
+
skip_validations: true,
|
32
|
+
auto_track: false,
|
33
|
+
title: "Concert Master: A new way to choose",
|
34
|
+
raw: "This is the raw markdown for my post"
|
35
|
+
tags: ['asdf', 'fdsa']
|
36
|
+
)
|
@@ -7,14 +7,6 @@ module DiscourseApi
|
|
7
7
|
response.body
|
8
8
|
end
|
9
9
|
|
10
|
-
def generate_user_api_key(user_id)
|
11
|
-
response = post("/admin/users/#{user_id}/generate_api_key.json")
|
12
|
-
end
|
13
|
-
|
14
|
-
def revoke_user_api_key(user_id)
|
15
|
-
response = delete("/admin/users/#{user_id}/revoke_api_key.json")
|
16
|
-
end
|
17
|
-
|
18
10
|
def generate_master_key
|
19
11
|
response = post("/admin/api/key")
|
20
12
|
end
|
@@ -28,6 +28,11 @@ module DiscourseApi
|
|
28
28
|
response['body']['category'] if response['body']
|
29
29
|
end
|
30
30
|
|
31
|
+
def delete_category(id)
|
32
|
+
response = delete("/categories/#{id}")
|
33
|
+
response[:body]['success']
|
34
|
+
end
|
35
|
+
|
31
36
|
def categories(params = {})
|
32
37
|
response = get('/categories.json', params)
|
33
38
|
response[:body]['category_list']['categories']
|
@@ -60,8 +60,16 @@ module DiscourseApi
|
|
60
60
|
put("/groups/#{group_id}", group: args)
|
61
61
|
end
|
62
62
|
|
63
|
-
def groups
|
64
|
-
|
63
|
+
def groups(args = {})
|
64
|
+
params = API.params(args)
|
65
|
+
.optional(:page)
|
66
|
+
.to_h
|
67
|
+
|
68
|
+
url = "/groups.json"
|
69
|
+
if params.include?(:page)
|
70
|
+
url += "?page=#{params[:page]}"
|
71
|
+
end
|
72
|
+
response = get(url)
|
65
73
|
response.body
|
66
74
|
end
|
67
75
|
|
@@ -3,21 +3,7 @@ module DiscourseApi
|
|
3
3
|
module API
|
4
4
|
module SSO
|
5
5
|
def sync_sso(params = {})
|
6
|
-
sso = DiscourseApi::SingleSignOn.
|
7
|
-
sso.sso_secret = params[:sso_secret]
|
8
|
-
sso.name = params[:name]
|
9
|
-
sso.username = params[:username]
|
10
|
-
sso.email = params[:email]
|
11
|
-
sso.external_id = params[:external_id]
|
12
|
-
sso.suppress_welcome_message = params[:suppress_welcome_message] === true
|
13
|
-
sso.avatar_url = params[:avatar_url]
|
14
|
-
sso.title = params[:title]
|
15
|
-
sso.avatar_force_update = params[:avatar_force_update] === true
|
16
|
-
sso.add_groups = params[:add_groups]
|
17
|
-
sso.remove_groups = params[:remove_groups]
|
18
|
-
params.keys.select { |key| key.to_s.start_with?("custom") }.each do |custom_key|
|
19
|
-
sso.custom_fields[custom_key] = params[custom_key]
|
20
|
-
end
|
6
|
+
sso = DiscourseApi::SingleSignOn.parse_hash(params)
|
21
7
|
|
22
8
|
post("/admin/users/sync_sso", sso.payload)
|
23
9
|
end
|
@@ -9,7 +9,7 @@ module DiscourseApi
|
|
9
9
|
def create_topic(args = {})
|
10
10
|
args = API.params(args)
|
11
11
|
.required(:title, :raw)
|
12
|
-
.optional(:skip_validations, :category, :auto_track, :created_at, :api_username)
|
12
|
+
.optional(:skip_validations, :category, :auto_track, :created_at, :api_username, :tags)
|
13
13
|
post("/posts", args.to_h)
|
14
14
|
end
|
15
15
|
|
@@ -42,11 +42,17 @@ module DiscourseApi
|
|
42
42
|
put("/t/#{topic_id}.json", topic_id: topic_id, category_id: category_id)
|
43
43
|
end
|
44
44
|
|
45
|
+
# TODO: Deprecated. Remove after 20201231
|
45
46
|
def change_topic_status(topic_slug, topic_id, params = {})
|
47
|
+
deprecated(__method__, 'update_topic_status')
|
48
|
+
update_topic_status(topic_id, params)
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_topic_status(topic_id, params = {})
|
46
52
|
params = API.params(params)
|
47
53
|
.required(:status, :enabled)
|
48
54
|
.optional(:api_username)
|
49
|
-
put("/t/#{topic_id}/status", params
|
55
|
+
put("/t/#{topic_id}/status", params)
|
50
56
|
end
|
51
57
|
|
52
58
|
def topic(id, params = {})
|
data/lib/discourse_api/client.rb
CHANGED
@@ -28,6 +28,7 @@ require 'discourse_api/api/site_settings'
|
|
28
28
|
module DiscourseApi
|
29
29
|
class Client
|
30
30
|
attr_accessor :api_key
|
31
|
+
attr_accessor :basic_auth
|
31
32
|
attr_reader :host, :api_username
|
32
33
|
|
33
34
|
include DiscourseApi::API::Categories
|
@@ -108,23 +109,38 @@ module DiscourseApi
|
|
108
109
|
@user_agent ||= "DiscourseAPI Ruby Gem #{DiscourseApi::VERSION}"
|
109
110
|
end
|
110
111
|
|
112
|
+
def deprecated(old, new)
|
113
|
+
warn "[DEPRECATED]: `#{old}` is deprecated. Please use `#{new}` instead."
|
114
|
+
end
|
115
|
+
|
111
116
|
private
|
112
117
|
|
113
118
|
def connection
|
114
119
|
@connection ||= Faraday.new connection_options do |conn|
|
115
|
-
# Follow redirects
|
116
|
-
conn.use FaradayMiddleware::FollowRedirects, limit: 5
|
117
120
|
# Allow uploading of files
|
118
121
|
conn.request :multipart
|
122
|
+
|
119
123
|
# Convert request params to "www-form-encoded"
|
120
124
|
conn.request :url_encoded
|
125
|
+
|
126
|
+
# Allow to interact with forums behind basic HTTP authentication
|
127
|
+
if basic_auth
|
128
|
+
conn.request :basic_auth, basic_auth[:user], basic_auth[:password]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Follow redirects
|
132
|
+
conn.response :follow_redirects, limit: 5
|
133
|
+
|
121
134
|
# Parse responses as JSON
|
122
|
-
conn.
|
135
|
+
conn.response :json, content_type: 'application/json'
|
136
|
+
|
123
137
|
# For HTTP debugging, uncomment
|
124
138
|
# conn.response :logger
|
139
|
+
|
125
140
|
# Use Faraday's default HTTP adapter
|
126
141
|
conn.adapter Faraday.default_adapter
|
127
|
-
|
142
|
+
|
143
|
+
# Pass api_key and api_username on every request
|
128
144
|
unless api_username.nil?
|
129
145
|
conn.headers['Api-Key'] = api_key
|
130
146
|
conn.headers['Api-Username'] = api_username
|
@@ -5,7 +5,7 @@ require 'openssl'
|
|
5
5
|
|
6
6
|
module DiscourseApi
|
7
7
|
class SingleSignOn
|
8
|
-
ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, :require_activation,
|
8
|
+
ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :profile_background_url, :card_background_url, :avatar_force_update, :require_activation,
|
9
9
|
:bio, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message, :title,
|
10
10
|
:add_groups, :remove_groups, :groups, :locale, :locale_force_update]
|
11
11
|
FIXNUMS = []
|
@@ -15,6 +15,7 @@ module DiscourseApi
|
|
15
15
|
#NONCE_EXPIRY_TIME = 10.minutes # minutes is a rails method and is causing an error. Is this needed in the api?
|
16
16
|
|
17
17
|
attr_accessor(*ACCESSORS)
|
18
|
+
attr_accessor :custom_fields
|
18
19
|
attr_writer :sso_secret, :sso_url
|
19
20
|
|
20
21
|
def self.sso_secret
|
@@ -25,6 +26,36 @@ module DiscourseApi
|
|
25
26
|
raise RuntimeError, "sso_url not implemented on class, be sure to set it on instance"
|
26
27
|
end
|
27
28
|
|
29
|
+
def self.parse_hash(payload)
|
30
|
+
payload
|
31
|
+
sso = new
|
32
|
+
|
33
|
+
sso.sso_secret = payload.delete(:sso_secret)
|
34
|
+
sso.sso_url = payload.delete(:sso_url)
|
35
|
+
|
36
|
+
ACCESSORS.each do |k|
|
37
|
+
val = payload[k]
|
38
|
+
|
39
|
+
val = val.to_i if FIXNUMS.include? k
|
40
|
+
if BOOLS.include? k
|
41
|
+
val = ["true", "false"].include?(val) ? val == "true" : nil
|
42
|
+
end
|
43
|
+
val = Array(val) if ARRAYS.include?(k) && !val.nil?
|
44
|
+
sso.send("#{k}=", val)
|
45
|
+
end
|
46
|
+
# Set custom_fields
|
47
|
+
sso.custom_fields = payload[:custom_fields]
|
48
|
+
# Add custom_fields (old format)
|
49
|
+
payload.each do |k, v|
|
50
|
+
if field = k[/^custom\.(.+)$/, 1]
|
51
|
+
# Maintain adding of .custom bug
|
52
|
+
sso.custom_fields["custom.#{field}"] = v
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
sso
|
57
|
+
end
|
58
|
+
|
28
59
|
def self.parse(payload, sso_secret = nil)
|
29
60
|
sso = new
|
30
61
|
sso.sso_secret = sso_secret if sso_secret
|
@@ -107,7 +138,5 @@ module DiscourseApi
|
|
107
138
|
|
108
139
|
Rack::Utils.build_query(payload)
|
109
140
|
end
|
110
|
-
|
111
141
|
end
|
112
|
-
|
113
142
|
end
|