school21_api_sdk 0.1.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f53a4ed9751f4ad38c62dff08811e164694e1b84903847ce98392aa39ae9234
4
- data.tar.gz: 46344c76969f24f6cd33d4b7ef9e1983e36e133c6bb258162b94dcb7ded7cc88
3
+ metadata.gz: e94bb6054dc91242b21c99220f3c30931f0b6b24418ef8f0ba140052f2220fb3
4
+ data.tar.gz: f4fc58b78bfe7a25291cab9f34de83f5361ecd8afc929a500b7bb4958bbb54a2
5
5
  SHA512:
6
- metadata.gz: d7bf6101d76b1a93a5510335e0f69a39eac1b8643eb0bbebd716a9b1dace589a1443bc4ef7ee6576c4b1b8e721746bf0b01eaf2888e21c541804bf7b58cfc43e
7
- data.tar.gz: fb4698307bc50ef4b896bda5277f556b5146e293042e9dbfec3a52b3a773792514d558c9f2235975813adace83d2ab3e426a250a9bcd1e1d7025b308c4e4ec59
6
+ metadata.gz: 379828e0c0f1bc42e3d66751ee73db4163fbaf35232d7200aa7fe552f36c08bf2f31dc702aeeac37cd72d0ea02dff01c0c89937f55284115ca10264d88ce9611
7
+ data.tar.gz: 707c86e1a6fb0bc5b4c92e3f71ed720b3219ddf5c569a5fc4614f7f2c78a96a45356900f6f6df942dad41f89c06ed31cac2e28a6e4caf77f7715bf8ca02657c8
data/README.md CHANGED
@@ -1,22 +1,28 @@
1
1
  # School21 API SDK
2
2
 
3
- ![](https://github.com/ikael21/school21_api_sdk/actions/workflows/test.yml/badge.svg)
3
+ ![test](https://github.com/ikael21/school21_api_sdk/actions/workflows/test.yml/badge.svg)
4
4
  [![codecov](https://codecov.io/github/ikael21/school21_api_sdk/branch/main/graph/badge.svg?token=O7I31Q7N96)](https://codecov.io/github/ikael21/school21_api_sdk)
5
- ![](https://github.com/ikael21/school21_api_sdk/actions/workflows/rubocop.yml/badge.svg)
5
+ ![rubocop](https://github.com/ikael21/school21_api_sdk/actions/workflows/rubocop.yml/badge.svg)
6
6
 
7
7
  ## Installation
8
8
 
9
9
  Install the gem and add to the application's Gemfile by executing:
10
10
 
11
- $ bundle add school21_api_sdk
11
+ ```bash
12
+ bundle add school21_api_sdk
13
+ ```
12
14
 
13
15
  If bundler is not being used to manage dependencies, install the gem by executing:
14
16
 
15
- $ gem install school21_api_sdk
17
+ ```bash
18
+ gem install school21_api_sdk
19
+ ```
16
20
 
17
21
  ## Usage
18
22
 
19
- There are multiple API's method according to School21 OpenAPI Specification. Check https://edu.21-school.ru/docs
23
+ Please check [docs](https://edu.21-school.ru/docs) for more information.
24
+
25
+ - Require the gem and configure client object
20
26
 
21
27
  ```ruby
22
28
  require 'school21'
@@ -24,9 +30,15 @@ require 'school21'
24
30
  login = 'your_login_here'
25
31
  password = 'your_password_here'
26
32
 
27
- client = School21::Client.new(login: login, password: password)
33
+ client = School21::Client.configure do |config|
34
+ config.credentials = { login: login, password: password }
35
+ config.enable_logging = true # false by default
36
+ end
37
+ ```
38
+
39
+ - Select the domain specific API that you want to use. This API has all endpoints related to that domain. Here's an example of `Participant API` and a call to `/participants/:login`
28
40
 
29
- # Example of getting base info about specific School21 participant
41
+ ```ruby
30
42
  participants_api = client.participants_api
31
43
  response = participants_api.participants('ikael@student.21-school.ru')
32
44
 
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class CampusesApi < BaseApi
5
+ def campuses
6
+ path = '/campuses'
7
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
8
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
9
+
10
+ new_api_call_builder
11
+ .request(new_request)
12
+ .response(new_response_handler)
13
+ .execute
14
+ end
15
+
16
+ def campuses_participants(campus_id, options: {})
17
+ path = "/campuses/#{campus_id}/participants"
18
+ default_options = { limit: 50, offset: 0 }.merge(options)
19
+
20
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
21
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
22
+
23
+ default_options.each do |key, value|
24
+ new_request.query_param(new_parameter(value, key:))
25
+ end
26
+
27
+ new_api_call_builder
28
+ .request(new_request)
29
+ .response(new_response_handler)
30
+ .execute
31
+ end
32
+
33
+ def campuses_coalitions(campus_id, options: {})
34
+ path = "/campuses/#{campus_id}/coalitions"
35
+ default_options = { limit: 50, offset: 0 }.merge(options)
36
+
37
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
38
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
39
+
40
+ default_options.each do |key, value|
41
+ new_request.query_param(new_parameter(value, key:))
42
+ end
43
+
44
+ new_api_call_builder
45
+ .request(new_request)
46
+ .response(new_response_handler)
47
+ .execute
48
+ end
49
+
50
+ def campuses_clusters(campus_id, options: {})
51
+ path = "/campuses/#{campus_id}/clusters"
52
+ default_options = { limit: 50, offset: 0 }.merge(options)
53
+
54
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
55
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
56
+
57
+ default_options.each do |key, value|
58
+ new_request.query_param(new_parameter(value, key:))
59
+ end
60
+
61
+ new_api_call_builder
62
+ .request(new_request)
63
+ .response(new_response_handler)
64
+ .execute
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class ClustersApi < BaseApi
5
+ def clusters_map(cluster_id, options: {})
6
+ path = "/clusters/#{cluster_id}/map"
7
+ default_options = { limit: 50, offset: 0, occupied: true }.merge(options)
8
+
9
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
10
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
11
+
12
+ default_options.each do |key, value|
13
+ new_request.query_param(new_parameter(value, key:))
14
+ end
15
+
16
+ new_api_call_builder
17
+ .request(new_request)
18
+ .response(new_response_handler)
19
+ .execute
20
+ end
21
+ end
22
+ end
@@ -15,17 +15,13 @@ module School21
15
15
 
16
16
  def participants_projects(login, options: {})
17
17
  path = "/participants/#{login}/projects"
18
- default_options = { limit: 1000, offset: 0 }.merge(options)
19
-
20
- parameters = default_options.map do |key, value|
21
- new_parameter(value, key:)
22
- end
18
+ default_options = { limit: 10, offset: 0 }.merge(options)
23
19
 
24
20
  new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
25
21
  .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
26
22
 
27
- parameters.each do |parameter|
28
- new_request.query_param(parameter)
23
+ default_options.each do |key, value|
24
+ new_request.query_param(new_parameter(value, key:))
29
25
  end
30
26
 
31
27
  new_api_call_builder
@@ -15,17 +15,13 @@ module School21
15
15
 
16
16
  def projects_participants(project_id, options: {})
17
17
  path = "/projects/#{project_id}/participants"
18
- default_options = { limit: 1000, offset: 0 }.merge(options)
19
-
20
- parameters = default_options.map do |key, value|
21
- new_parameter(value, key:)
22
- end
18
+ default_options = { limit: 10, offset: 0 }.merge(options)
23
19
 
24
20
  new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
25
21
  .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
26
22
 
27
- parameters.each do |parameter|
28
- new_request.query_param(parameter)
23
+ default_options.each do |key, value|
24
+ new_request.query_param(new_parameter(value, key:))
29
25
  end
30
26
 
31
27
  new_api_call_builder
@@ -4,40 +4,64 @@ module School21
4
4
  class Client
5
5
  include CoreLibrary
6
6
 
7
- def initialize(login:, password:)
8
- raise ArgumentError, "login can't be nil or empty" if login.nil? || login.empty?
9
- raise ArgumentError, "password can't be nil or empty" if password.nil? || password.empty?
10
-
11
- client_configuration = HttpClientConfiguration.new(logging_configuration:)
12
- http_client = FaradayClient.new(client_configuration)
13
- client_configuration.set_http_client(http_client)
7
+ def self.configure(&)
8
+ new(&)
9
+ end
14
10
 
15
- @login = login
16
- @password = password
11
+ def initialize(&block)
12
+ raise 'A block must be given' unless block_given?
13
+ raise 'You must provide block argument that represents config instance' if block.arity != 1
17
14
 
18
- @config = GlobalConfiguration
19
- .new(client_configuration:)
15
+ @config = GlobalConfig
16
+ .new
20
17
  .base_uri_executor(BaseApi.method(:base_uri))
21
18
 
19
+ yield(@config)
20
+
21
+ validate_credentials!
22
+
23
+ initialize_logging
24
+
25
+ http_client = FaradayClient.new(@config.client_configuration)
26
+ @config.client_configuration.set_http_client(http_client)
27
+
22
28
  initialize_auth!
23
29
  end
24
30
 
25
- def auth_api = @auth_api ||= AuthApi.new(@config)
31
+ def auth_api
32
+ @auth_api ||= AuthApi.new(@config)
33
+ end
26
34
 
27
35
  def participants_api
28
36
  initialize_auth! if @access_token.expired?
29
-
30
37
  ParticipantsApi.new(@config)
31
38
  end
32
39
 
33
40
  def projects_api
34
41
  initialize_auth! if @access_token.expired?
35
-
36
42
  ProjectsApi.new(@config)
37
43
  end
38
44
 
45
+ def campuses_api
46
+ initialize_auth! if @access_token.expired?
47
+ CampusesApi.new(@config)
48
+ end
49
+
50
+ def clusters_api
51
+ initialize_auth! if @access_token.expired?
52
+ ClustersApi.new(@config)
53
+ end
54
+
39
55
  private
40
56
 
57
+ def validate_credentials!
58
+ login = @config.credentials[:login]
59
+ password = @config.credentials[:password]
60
+
61
+ raise "Login can't be nil or empty" if login.nil? || login.empty?
62
+ raise "Password can't be nil or empty" if password.nil? || password.empty?
63
+ end
64
+
41
65
  def initialize_auth!
42
66
  @access_token = request_access_token!
43
67
 
@@ -50,22 +74,26 @@ module School21
50
74
  creds = BearerAuthCredentials.new(access_token: @access_token)
51
75
  auth_managers[BaseApi::SINGLE_AUTH_PARTICIPANT] = AuthorizationHeader.new(creds)
52
76
 
53
- @config.auth_managers(auth_managers)
77
+ @config.auth_managers = auth_managers
54
78
  end
55
79
 
56
80
  def request_access_token!
57
- auth_api_response = auth_api.token(login: @login, password: @password)
81
+ auth_api_response = auth_api.token(login: @config.credentials[:login], password: @config.credentials[:password])
58
82
  raise 'Access Token Error' unless auth_api_response.success?
59
83
 
60
84
  AccessToken.new(*auth_api_response.data.values_at(:access_token, :expires_in))
61
85
  end
62
86
 
63
- def logging_configuration
87
+ def initialize_logging
88
+ return unless @config.enable_logging
89
+
64
90
  headers_to_exclude = ['Authorization']
65
- api_request_config = ApiRequestLoggingConfiguration.new(true, true, headers_to_exclude, nil, nil, true)
66
- api_response_config = ApiResponseLoggingConfiguration.new(true, true, nil, nil, nil)
91
+ api_logging_config = ApiLoggingConfig.new(nil, nil, nil, nil, false)
92
+ api_logging_config.request_logging_config = ApiRequestLoggingConfiguration.new(true, true, headers_to_exclude,
93
+ nil, nil, true)
94
+ api_logging_config.response_logging_config = ApiResponseLoggingConfiguration.new(true, true, nil, nil, nil)
67
95
 
68
- ApiLoggingConfiguration.new(nil, nil, api_request_config, api_response_config, false)
96
+ @config.client_configuration.logging_configuration = api_logging_config
69
97
  end
70
98
  end
71
99
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class ApiLoggingConfig < CoreLibrary::ApiLoggingConfiguration
5
+ attr_writer :request_logging_config, :response_logging_config
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class ClientConfig < CoreLibrary::HttpClientConfiguration
5
+ attr_writer :logging_configuration, :timeout
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class GlobalConfig < CoreLibrary::GlobalConfiguration
5
+ attr_accessor :auth_managers, :enable_logging, :credentials
6
+ attr_writer :client_configuration
7
+
8
+ def initialize(client_configuration: ClientConfig.new)
9
+ super
10
+
11
+ @enable_logging = false
12
+ @credentials = {}
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module School21
4
- VERSION = '0.1.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/school21.rb CHANGED
@@ -13,5 +13,11 @@ require_relative 'school21/api/base_api'
13
13
  require_relative 'school21/api/participants_api'
14
14
  require_relative 'school21/api/auth_api'
15
15
  require_relative 'school21/api/projects_api'
16
+ require_relative 'school21/api/campuses_api'
17
+ require_relative 'school21/api/clusters_api'
18
+
19
+ require_relative 'school21/config/api_logging_config'
20
+ require_relative 'school21/config/client_config'
21
+ require_relative 'school21/config/global_config'
16
22
 
17
23
  require_relative 'school21/client'
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ describe 'Client Test' do
6
+ include AuthStub
7
+
8
+ before do
9
+ @login = 'login'
10
+ @password = 'password'
11
+ end
12
+
13
+ let(:valid_init_client) do
14
+ School21::Client.configure do |config|
15
+ config.credentials = { login: @login, password: @password }
16
+ config.enable_logging = false
17
+ end
18
+ end
19
+
20
+ let(:init_client_without_login) do
21
+ School21::Client.configure do |config|
22
+ config.credentials = { login: nil, password: @password }
23
+ config.enable_logging = false
24
+ end
25
+ end
26
+
27
+ let(:init_client_without_password) do
28
+ School21::Client.configure do |config|
29
+ config.credentials = { login: @login, password: nil }
30
+ config.enable_logging = false
31
+ end
32
+ end
33
+
34
+ it 'successfully stubs client auth' do
35
+ stub = stub_token
36
+
37
+ valid_init_client
38
+
39
+ assert_requested(stub)
40
+ end
41
+
42
+ it 'raises an exception without login' do
43
+ stub = stub_token
44
+
45
+ assert_raises(RuntimeError, "Login can't be nil or empty") do
46
+ init_client_without_login
47
+ end
48
+
49
+ refute_requested(stub)
50
+ end
51
+
52
+ it 'raises an exception without password' do
53
+ stub = stub_token
54
+
55
+ assert_raises(RuntimeError, "Password can't be nil or empty") do
56
+ init_client_without_password
57
+ end
58
+
59
+ refute_requested(stub)
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuthStub
4
+ include BaseStub
5
+
6
+ def stub_token
7
+ body = {
8
+ access_token: 'access_token',
9
+ expires_in: 36_000
10
+ }
11
+
12
+ stub_request(:post, stubbed_auth_url).to_return_json(body:)
13
+ end
14
+
15
+ private
16
+
17
+ def stubbed_auth_url
18
+ [BASE_AUTH_URL, '/auth/realms/EduPowerKeycloak/protocol/openid-connect/token'].join
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BaseStub
4
+ BASE_AUTH_URL = 'https://auth.sberclass.ru'
5
+ API_V1_URL = 'https://edu-api.21-school.ru/services/21-school/api/v1'
6
+ end
data/test/test_helper.rb CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  require 'simplecov'
4
4
  require 'simplecov-cobertura'
5
+ require 'webmock/minitest'
6
+
7
+ require_relative 'support/stubs/base_stub'
8
+ require_relative 'support/stubs/auth_stub'
5
9
 
6
10
  SimpleCov.start
7
11
  SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
@@ -10,3 +14,6 @@ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
10
14
 
11
15
  require 'school21'
12
16
  require 'minitest/autorun'
17
+ require 'minitest/reporters'
18
+
19
+ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: school21_api_sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Yudin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-03 00:00:00.000000000 Z
11
+ date: 2024-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -94,13 +94,21 @@ files:
94
94
  - lib/school21.rb
95
95
  - lib/school21/api/auth_api.rb
96
96
  - lib/school21/api/base_api.rb
97
+ - lib/school21/api/campuses_api.rb
98
+ - lib/school21/api/clusters_api.rb
97
99
  - lib/school21/api/participants_api.rb
98
100
  - lib/school21/api/projects_api.rb
99
101
  - lib/school21/auth/access_token.rb
100
102
  - lib/school21/auth/authorization_header.rb
101
103
  - lib/school21/auth/bearer_auth_credentials.rb
102
104
  - lib/school21/client.rb
105
+ - lib/school21/config/api_logging_config.rb
106
+ - lib/school21/config/client_config.rb
107
+ - lib/school21/config/global_config.rb
103
108
  - lib/school21/version.rb
109
+ - test/client_test.rb
110
+ - test/support/stubs/auth_stub.rb
111
+ - test/support/stubs/base_stub.rb
104
112
  - test/test_helper.rb
105
113
  homepage: https://github.com/ikael21/school21_api_sdk
106
114
  licenses:
@@ -122,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
130
  - !ruby/object:Gem::Version
123
131
  version: '0'
124
132
  requirements: []
125
- rubygems_version: 3.5.11
133
+ rubygems_version: 3.5.17
126
134
  signing_key:
127
135
  specification_version: 4
128
136
  summary: School21 API SDK