school21_api_sdk 0.4.0 → 0.5.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: a8b8fc46a01614de5e5b6cfb19de30d5471eb154d293a02d7eab835f8c2042bd
4
- data.tar.gz: ef32e49acfbb13fc44384c0b58b26b3633c1878a6a7c8e5ab86f9eb9efbd1287
3
+ metadata.gz: 8c369d9fa76c0c36cb3142d0807256d9be76d9b706aedc32207899f355721d0b
4
+ data.tar.gz: 3b314e7f8a1235eadfe9ce7cd5147bc0889c4926169a3a29740613f72f2aeb94
5
5
  SHA512:
6
- metadata.gz: becf9958c2bc4dcc57fb0ecb8d6b0b5473c47b800375c6e70e92c209cb47c569c5759e79d887a3a423cfeac01b3e072936221ce4570daf01302c35fc1f010ef7
7
- data.tar.gz: a2fdb94e72a53583d147732ba4971653335c1f9ed2cb6ef0bc74b2a73d42b2632415d327198f3d3e7abb2865bcd1ab5f1fc8289c6162e6bd8c5c030d7bd874f8
6
+ metadata.gz: ddaecba86f46485941eb2a9d508ff6a2961db296657bbc28cf3b31dee962af1986648d1226cf1e46425475ef48935b2716810d4d74b34a627eba5e637d00cb4c
7
+ data.tar.gz: cf9e4fc8918d2b64e4361cf45a19bc8a6fc6f6e2c520f476e71b3e8c5025222bea1074a303971ff3f24ddd00e9c57b2e5d04f032bfd650c269b358e137fc9ebc
data/README.md CHANGED
@@ -4,6 +4,16 @@
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
5
  ![rubocop](https://github.com/ikael21/school21_api_sdk/actions/workflows/rubocop.yml/badge.svg)
6
6
 
7
+ > [!NOTE]
8
+ > Development is still in progress, implementation may change in future versions.
9
+
10
+ > [!WARNING]
11
+ > **Do not store your login and password as raw string values, use environment variables instead!**
12
+ > Currently platform provides only one way to authorize API calls with `login:password` pair
13
+ > you're using for the school everyday tasks.
14
+ > As soon as other types of authorization will be added (such as using API token), they'll be implemented for this gem as well.
15
+
16
+
7
17
  ## Installation
8
18
 
9
19
  Install the gem and add to the application's Gemfile by executing:
@@ -30,23 +40,18 @@ require 'school21'
30
40
  login = 'your_login_here'
31
41
  password = 'your_password_here'
32
42
 
33
- client = School21::Client.configure do |config|
43
+ School21.configure do |config|
34
44
  config.credentials = { login: login, password: password }
35
45
 
36
46
  # If you want to log client's requests and responses (turned off by default)
37
47
  config.enable_logging = true
38
48
  end
39
-
40
- # Request access token from the API server.
41
- # Access token is stored inside client object and reused for API requests.
42
- # If access token is expired client will automatically request a new one.
43
- client.authenticate!
44
49
  ```
45
50
 
46
51
  - 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`
47
52
 
48
53
  ```ruby
49
- participants_api = client.participants_api
54
+ participants_api = School21.participants_api
50
55
  response = participants_api.participant('peer_nickname')
51
56
 
52
57
  if response.success?
@@ -9,7 +9,10 @@ module School21
9
9
  .form_param(new_parameter('password', key: :grant_type))
10
10
  .form_param(new_parameter('s21-open-api', key: :client_id))
11
11
 
12
- execute_request(new_request)
12
+ new_api_call_builder
13
+ .request(new_request)
14
+ .response(new_response_handler)
15
+ .execute
13
16
  end
14
17
  end
15
18
  end
@@ -4,7 +4,7 @@ module School21
4
4
  class BaseApi
5
5
  include CoreLibrary
6
6
 
7
- SINGLE_AUTH_PARTICIPANT = :global
7
+ PLATFORM_AUTH_PARTICIPANT = :platform
8
8
 
9
9
  def self.base_uri(server)
10
10
  case server
@@ -16,6 +16,8 @@ module School21
16
16
  end
17
17
 
18
18
  def self.response_convertor(api_response)
19
+ return api_response unless api_response.data.present? && api_response.data.is_a?(Hash)
20
+
19
21
  api_response.data.deep_transform_keys! do |key|
20
22
  key.underscore.to_sym
21
23
  end
@@ -23,12 +25,13 @@ module School21
23
25
  api_response
24
26
  end
25
27
 
26
- def initialize(global_configuration)
27
- @global_configuration = global_configuration
28
- @api_call = ApiCall.new(@global_configuration)
28
+ def initialize
29
+ @api_call = ApiCall.new(School21.config)
29
30
  end
30
31
 
31
- def new_api_call_builder = @api_call.new_builder
32
+ def new_api_call_builder
33
+ @api_call.new_builder
34
+ end
32
35
 
33
36
  def new_response_handler
34
37
  ResponseHandler.new
@@ -50,13 +53,15 @@ module School21
50
53
  .value(value)
51
54
  end
52
55
 
53
- def authenticated_request(...)
54
- auth_participant = CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT)
56
+ def request_with_auth_participant(http_method, path, server)
57
+ auth_participant = CoreLibrary::Single.new(PLATFORM_AUTH_PARTICIPANT)
55
58
 
56
- new_request_builder(...).auth(auth_participant)
59
+ new_request_builder(http_method, path, server).auth(auth_participant)
57
60
  end
58
61
 
59
62
  def execute_request(new_request)
63
+ Authenticator.call
64
+
60
65
  new_api_call_builder
61
66
  .request(new_request)
62
67
  .response(new_response_handler)
@@ -3,16 +3,13 @@
3
3
  module School21
4
4
  class CampusesApi < BaseApi
5
5
  def campuses
6
- path = '/campuses'
7
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
8
-
9
- execute_request(new_request)
6
+ execute_request(request_with_auth_participant(HttpMethod::GET, '/campuses', :api_v1))
10
7
  end
11
8
 
12
9
  def campus_participants(campus_id, options: {})
13
- path = "/campuses/#{campus_id}/participants"
10
+ path = ['/campuses/', campus_id, '/participants'].join
14
11
  default_options = { limit: 50, offset: 0 }.merge(options)
15
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
12
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
16
13
 
17
14
  default_options.each do |key, value|
18
15
  new_request.query_param(new_parameter(value, key:))
@@ -22,9 +19,9 @@ module School21
22
19
  end
23
20
 
24
21
  def campus_coalitions(campus_id, options: {})
25
- path = "/campuses/#{campus_id}/coalitions"
22
+ path = ['/campuses/', campus_id, '/coalitions'].join
26
23
  default_options = { limit: 50, offset: 0 }.merge(options)
27
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
24
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
28
25
 
29
26
  default_options.each do |key, value|
30
27
  new_request.query_param(new_parameter(value, key:))
@@ -34,9 +31,9 @@ module School21
34
31
  end
35
32
 
36
33
  def campus_clusters(campus_id, options: {})
37
- path = "/campuses/#{campus_id}/clusters"
34
+ path = ['/campuses/', campus_id, '/clusters'].join
38
35
  default_options = { limit: 50, offset: 0 }.merge(options)
39
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
36
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
40
37
 
41
38
  default_options.each do |key, value|
42
39
  new_request.query_param(new_parameter(value, key:))
@@ -2,10 +2,10 @@
2
2
 
3
3
  module School21
4
4
  class ClustersApi < BaseApi
5
- def cluster_map(cluster_id, options: {})
6
- path = "/clusters/#{cluster_id}/map"
5
+ def map(cluster_id, options: {})
6
+ path = ['/clusters/', cluster_id, '/map'].join
7
7
  default_options = { limit: 50, offset: 0 }.merge(options)
8
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
8
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
9
9
 
10
10
  default_options.each do |key, value|
11
11
  new_request.query_param(new_parameter(value, key:))
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class GraphApi < BaseApi
5
+ def graph
6
+ new_request = request_with_auth_participant(HttpMethod::GET, '/graph', :api_v1)
7
+
8
+ execute_request(new_request)
9
+ end
10
+ end
11
+ end
@@ -3,16 +3,16 @@
3
3
  module School21
4
4
  class ParticipantsApi < BaseApi
5
5
  def participant(login)
6
- path = "/participants/#{login}"
7
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
6
+ path = ['/participants/', login].join
7
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
8
8
 
9
9
  execute_request(new_request)
10
10
  end
11
11
 
12
12
  def participant_projects(login, options: {})
13
- path = "/participants/#{login}/projects"
13
+ path = ['/participants/', login, '/projects'].join
14
14
  default_options = { limit: 10, offset: 0 }.merge(options)
15
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
15
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
16
16
 
17
17
  default_options.each do |key, value|
18
18
  new_request.query_param(new_parameter(value, key:))
@@ -22,8 +22,8 @@ module School21
22
22
  end
23
23
 
24
24
  def participant_project(login, project_id)
25
- path = "/participants/#{login}/projects/#{project_id}"
26
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
25
+ path = ['/participants/', login, '/projects/', project_id].join
26
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
27
27
 
28
28
  execute_request(new_request)
29
29
  end
@@ -3,18 +3,19 @@
3
3
  module School21
4
4
  class ProjectsApi < BaseApi
5
5
  def project(project_id)
6
- path = "/projects/#{project_id}"
7
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
6
+ path = ['/projects/', project_id].join
7
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
8
8
 
9
9
  execute_request(new_request)
10
10
  end
11
11
 
12
12
  def project_participants(project_id, options: {})
13
- path = "/projects/#{project_id}/participants"
14
- default_options = { limit: 10, offset: 0 }.merge(options)
15
- new_request = authenticated_request(HttpMethod::GET, path, :api_v1)
13
+ path = ['/projects/', project_id, '/participants'].join
14
+ default_options = { limit: 10, offset: 0 }
15
+ new_request = request_with_auth_participant(HttpMethod::GET, path, :api_v1)
16
16
 
17
- default_options.each do |key, value|
17
+ options.reverse_merge!(default_options)
18
+ options.each do |key, value|
18
19
  new_request.query_param(new_parameter(value, key:))
19
20
  end
20
21
 
@@ -10,7 +10,7 @@ module School21
10
10
  end
11
11
 
12
12
  def expired?
13
- Time.now >= @expires_at
13
+ access_token.nil? || Time.now >= @expires_at
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ module Authenticator
5
+ def self.call
6
+ return unless School21.config.access_token.expired?
7
+
8
+ auth_api_response = School21.auth_api.token(
9
+ login: School21.config.credentials[:login],
10
+ password: School21.config.credentials[:password]
11
+ )
12
+
13
+ raise 'Access Token Error' unless auth_api_response.success?
14
+
15
+ access_token = AccessToken.new(*auth_api_response.data.values_at(:access_token, :expires_in))
16
+ bearer_auth_credentials = BearerAuthCredentials.new(access_token:)
17
+ auth_header = AuthorizationHeader.new(bearer_auth_credentials)
18
+
19
+ School21.config.access_token = access_token
20
+ School21.config.auth_managers[BaseApi::PLATFORM_AUTH_PARTICIPANT] = auth_header
21
+ end
22
+ end
23
+ end
@@ -7,12 +7,9 @@ module School21
7
7
  end
8
8
 
9
9
  def initialize(bearer_auth_credentials)
10
+ access_token = bearer_auth_credentials.access_token
10
11
  auth_params = {}
11
-
12
- @access_token = bearer_auth_credentials.access_token unless
13
- bearer_auth_credentials.nil? || bearer_auth_credentials.access_token.nil?
14
-
15
- auth_params['Authorization'] = "Bearer #{@access_token}" unless @access_token.nil?
12
+ auth_params['Authorization'] = "Bearer #{access_token}"
16
13
 
17
14
  super(auth_params)
18
15
  end
@@ -2,14 +2,38 @@
2
2
 
3
3
  module School21
4
4
  class GlobalConfig < CoreLibrary::GlobalConfiguration
5
- attr_accessor :auth_managers, :enable_logging, :credentials, :logger
6
- attr_writer :client_configuration
5
+ attr_accessor :auth_managers, :enable_logging, :credentials, :logger, :access_token
7
6
 
8
7
  def initialize(client_configuration: ClientConfig.new)
9
8
  super
10
9
 
11
10
  @enable_logging = false
12
11
  @credentials = {}
12
+ @access_token = AccessToken.new(nil, 0)
13
+
14
+ http_client = CoreLibrary::FaradayClient.new(client_configuration)
15
+ client_configuration.set_http_client(http_client)
16
+ end
17
+
18
+ def initialize_logger
19
+ logger ||= semantic_logger
20
+
21
+ excluded_headers = ['Authorization']
22
+ api_logging_config = School21::ApiLoggingConfig.new(logger, nil, nil, nil, false)
23
+ api_logging_config.request_logging_config =
24
+ CoreLibrary::ApiRequestLoggingConfiguration.new(true, true, excluded_headers, nil, nil, true)
25
+ api_logging_config.response_logging_config =
26
+ CoreLibrary::ApiResponseLoggingConfiguration.new(true, true, nil, nil, nil)
27
+ client_configuration.logging_configuration = api_logging_config
28
+ end
29
+
30
+ private
31
+
32
+ def semantic_logger
33
+ SemanticLogger.default_level = :trace
34
+ SemanticLogger.add_appender(io: $stdout, formatter: :color)
35
+
36
+ SemanticLogger[School21.name]
13
37
  end
14
38
  end
15
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module School21
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
data/lib/school21.rb CHANGED
@@ -9,6 +9,7 @@ require 'active_support/all'
9
9
  require_relative 'school21/auth/access_token'
10
10
  require_relative 'school21/auth/authorization_header'
11
11
  require_relative 'school21/auth/bearer_auth_credentials'
12
+ require_relative 'school21/auth/authenticator'
12
13
 
13
14
  require_relative 'school21/api/base_api'
14
15
  require_relative 'school21/api/participants_api'
@@ -16,9 +17,41 @@ require_relative 'school21/api/auth_api'
16
17
  require_relative 'school21/api/projects_api'
17
18
  require_relative 'school21/api/campuses_api'
18
19
  require_relative 'school21/api/clusters_api'
20
+ require_relative 'school21/api/graph_api'
19
21
 
20
22
  require_relative 'school21/config/api_logging_config'
21
23
  require_relative 'school21/config/client_config'
22
24
  require_relative 'school21/config/global_config'
23
25
 
24
- require_relative 'school21/client'
26
+ module School21
27
+ class << self
28
+ def configure
29
+ yield config
30
+ config.initialize_logger if config.enable_logging
31
+ config
32
+ end
33
+
34
+ def config
35
+ @config ||= GlobalConfig.new.base_uri_executor(BaseApi.method(:base_uri))
36
+ end
37
+
38
+ def reset!
39
+ @config = nil
40
+ end
41
+
42
+ API_CLASSES = {
43
+ auth: AuthApi,
44
+ participants: ParticipantsApi,
45
+ projects: ProjectsApi,
46
+ campuses: CampusesApi,
47
+ clusters: ClustersApi,
48
+ graph: GraphApi
49
+ }.freeze
50
+
51
+ API_CLASSES.each do |name, klass|
52
+ define_method("#{name}_api") do
53
+ klass.new
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ describe 'Auth API Test' do
6
+ include AuthStub
7
+
8
+ with_configured_client do
9
+ let(:auth_api_call) do
10
+ School21.auth_api.token(
11
+ login: School21.config.credentials[:login],
12
+ password: School21.config.credentials[:password]
13
+ )
14
+ end
15
+
16
+ it 'calls stub token success' do
17
+ stub = stub_token_success
18
+
19
+ auth_api_call
20
+
21
+ assert_requested(stub)
22
+ end
23
+
24
+ it 'calls stub token fail' do
25
+ stub = stub_token_fail
26
+
27
+ response = auth_api_call
28
+
29
+ assert_requested(stub)
30
+ assert_equal(500, response.status_code)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ describe 'Configuration test' do
6
+ include SharedData
7
+
8
+ it 'successfully configures client' do
9
+ School21.configure do |config|
10
+ config.credentials = credentials_fixtures
11
+ config.enable_logging = false
12
+ end
13
+
14
+ assert_equal credentials_fixtures, School21.config.credentials
15
+ refute School21.config.enable_logging
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ describe 'Participants API Test' do
6
+ include AuthStub
7
+ include ParticipantsStub
8
+
9
+ with_configured_client do
10
+ let(:login) { 'test_login' }
11
+ let(:participants_api_call) do
12
+ School21.participants_api.participant(login)
13
+ end
14
+
15
+ it 'calls stub participant success' do
16
+ stubs = [
17
+ stub_token_success,
18
+ stub_participant_success
19
+ ]
20
+
21
+ participants_api_call
22
+
23
+ stubs.each { |stub| assert_requested(stub) }
24
+ end
25
+
26
+ it 'calls stub participant fail' do
27
+ stubs = [
28
+ stub_token_success,
29
+ stub_participant_fail
30
+ ]
31
+
32
+ participants_api_call
33
+
34
+ stubs.each { |stub| assert_requested(stub) }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SharedData
4
+ def credentials_fixtures
5
+ { login: 'login', password: 'password' }
6
+ end
7
+ end
@@ -3,18 +3,17 @@
3
3
  module AuthStub
4
4
  include BaseStub
5
5
 
6
- def stub_token
7
- body = {
8
- access_token: 'access_token',
9
- expires_in: 36_000
10
- }
6
+ STUBBED_AUTH_URL = [BASE_AUTH_URL, '/auth/realms/EduPowerKeycloak/protocol/openid-connect/token'].join
11
7
 
12
- stub_request(:post, stubbed_auth_url).to_return_json(body:)
8
+ def stub_token_success
9
+ stub_request(:post, STUBBED_AUTH_URL)
10
+ .to_return_json(body: {
11
+ access_token: 'access_token',
12
+ expires_in: 36_000
13
+ })
13
14
  end
14
15
 
15
- private
16
-
17
- def stubbed_auth_url
18
- [BASE_AUTH_URL, '/auth/realms/EduPowerKeycloak/protocol/openid-connect/token'].join
16
+ def stub_token_fail
17
+ base_stub_fail(:post, STUBBED_AUTH_URL)
19
18
  end
20
19
  end
@@ -3,4 +3,9 @@
3
3
  module BaseStub
4
4
  BASE_AUTH_URL = 'https://auth.sberclass.ru'
5
5
  BASE_API_V1_URL = 'https://edu-api.21-school.ru/services/21-school/api/v1'
6
+
7
+ def base_stub_fail(http_method, url)
8
+ stub_request(http_method, url)
9
+ .to_return(status: [500, 'Internal Server Error'])
10
+ end
6
11
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ParticipantsStub
4
+ include BaseStub
5
+
6
+ TEST_LOGIN = 'test_login'
7
+ STUBBED_PARTICIPANT_URL = [BASE_API_V1_URL, '/participants/', TEST_LOGIN].join
8
+
9
+ def stub_participant_success
10
+ stub_request(:get, STUBBED_PARTICIPANT_URL)
11
+ .to_return_json(body: { login: TEST_LOGIN })
12
+ end
13
+
14
+ def stub_participant_fail
15
+ stub_request(:get, STUBBED_PARTICIPANT_URL)
16
+ .to_return(status: [500, 'Internal Server Error'])
17
+ end
18
+ end
data/test/test_helper.rb CHANGED
@@ -3,9 +3,13 @@
3
3
  require 'simplecov'
4
4
  require 'simplecov-cobertura'
5
5
  require 'webmock/minitest'
6
+ require 'debug'
7
+
8
+ require_relative 'support/shared_data'
6
9
 
7
10
  require_relative 'support/stubs/base_stub'
8
11
  require_relative 'support/stubs/auth_stub'
12
+ require_relative 'support/stubs/participants_stub'
9
13
 
10
14
  SimpleCov.start
11
15
  SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
@@ -17,3 +21,20 @@ require 'minitest/autorun'
17
21
  require 'minitest/reporters'
18
22
 
19
23
  Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
24
+
25
+ module Minitest
26
+ class Spec
27
+ include SharedData
28
+
29
+ def self.with_configured_client(&block)
30
+ describe 'with configured client' do
31
+ before do
32
+ School21.reset!
33
+ School21.configure { |c| c.credentials = credentials_fixtures }
34
+ end
35
+
36
+ class_eval(&block)
37
+ end
38
+ end
39
+ end
40
+ end
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.4.0
4
+ version: 0.5.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-12-15 00:00:00.000000000 Z
11
+ date: 2025-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -110,19 +110,24 @@ files:
110
110
  - lib/school21/api/base_api.rb
111
111
  - lib/school21/api/campuses_api.rb
112
112
  - lib/school21/api/clusters_api.rb
113
+ - lib/school21/api/graph_api.rb
113
114
  - lib/school21/api/participants_api.rb
114
115
  - lib/school21/api/projects_api.rb
115
116
  - lib/school21/auth/access_token.rb
117
+ - lib/school21/auth/authenticator.rb
116
118
  - lib/school21/auth/authorization_header.rb
117
119
  - lib/school21/auth/bearer_auth_credentials.rb
118
- - lib/school21/client.rb
119
120
  - lib/school21/config/api_logging_config.rb
120
121
  - lib/school21/config/client_config.rb
121
122
  - lib/school21/config/global_config.rb
122
123
  - lib/school21/version.rb
123
- - test/client_test.rb
124
+ - test/auth_api_test.rb
125
+ - test/configuration_test.rb
126
+ - test/participants_api_test.rb
127
+ - test/support/shared_data.rb
124
128
  - test/support/stubs/auth_stub.rb
125
129
  - test/support/stubs/base_stub.rb
130
+ - test/support/stubs/participants_stub.rb
126
131
  - test/test_helper.rb
127
132
  homepage: https://github.com/ikael21/school21_api_sdk
128
133
  licenses:
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module School21
4
- class Client
5
- include CoreLibrary
6
-
7
- attr_reader :config, :access_token
8
-
9
- class << self
10
- def configure(&) = new(&)
11
- end
12
-
13
- def initialize(&block)
14
- raise 'A block must be given' unless block_given?
15
- raise 'You must provide block argument that represents config instance' if block.arity != 1
16
-
17
- @config = GlobalConfig.new.base_uri_executor(BaseApi.method(:base_uri))
18
-
19
- yield(@config)
20
-
21
- validate_credentials!
22
-
23
- initialize_logging if @config.enable_logging
24
-
25
- http_client = FaradayClient.new(@config.client_configuration)
26
- @config.client_configuration.set_http_client(http_client)
27
- end
28
-
29
- def authenticate!
30
- @access_token = request_access_token!
31
-
32
- initialize_auth_managers
33
- end
34
-
35
- def auth_api
36
- @auth_api ||= AuthApi.new(config)
37
- end
38
-
39
- def participants_api
40
- authenticate! if access_token.expired?
41
- ParticipantsApi.new(config)
42
- end
43
-
44
- def projects_api
45
- authenticate! if access_token.expired?
46
- ProjectsApi.new(config)
47
- end
48
-
49
- def campuses_api
50
- authenticate! if access_token.expired?
51
- CampusesApi.new(config)
52
- end
53
-
54
- def clusters_api
55
- authenticate! if access_token.expired?
56
- ClustersApi.new(config)
57
- end
58
-
59
- private
60
-
61
- def validate_credentials!
62
- login = config.credentials[:login]
63
- password = config.credentials[:password]
64
-
65
- raise "Login can't be nil or empty" if login.nil? || login.empty?
66
- raise "Password can't be nil or empty" if password.nil? || password.empty?
67
- end
68
-
69
- def initialize_auth_managers
70
- auth_managers = {}
71
- creds = BearerAuthCredentials.new(access_token:)
72
- auth_managers[BaseApi::SINGLE_AUTH_PARTICIPANT] = AuthorizationHeader.new(creds)
73
-
74
- config.auth_managers = auth_managers
75
- end
76
-
77
- def request_access_token!
78
- auth_api_response = auth_api.token(
79
- login: config.credentials[:login],
80
- password: config.credentials[:password]
81
- )
82
-
83
- raise 'Access Token Error' unless auth_api_response.success?
84
-
85
- AccessToken.new(*auth_api_response.data.values_at(:access_token, :expires_in))
86
- end
87
-
88
- def semantic_logger
89
- SemanticLogger.default_level = :trace
90
- SemanticLogger.add_appender(io: $stdout, formatter: :color)
91
-
92
- SemanticLogger[self.class.to_s]
93
- end
94
-
95
- def initialize_logging
96
- logger = if config.logger.nil?
97
- semantic_logger
98
- else
99
- config.logger
100
- end
101
-
102
- headers_to_exclude = ['Authorization']
103
- api_logging_config = ApiLoggingConfig.new(logger, nil, nil, nil, false)
104
- api_logging_config.request_logging_config = ApiRequestLoggingConfiguration.new(true, true, headers_to_exclude,
105
- nil, nil, true)
106
- api_logging_config.response_logging_config = ApiResponseLoggingConfiguration.new(true, true, nil, nil, nil)
107
-
108
- config.client_configuration.logging_configuration = api_logging_config
109
- end
110
- end
111
- end
data/test/client_test.rb DELETED
@@ -1,61 +0,0 @@
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.authenticate!
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