school21_api_sdk 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2f53a4ed9751f4ad38c62dff08811e164694e1b84903847ce98392aa39ae9234
4
+ data.tar.gz: 46344c76969f24f6cd33d4b7ef9e1983e36e133c6bb258162b94dcb7ded7cc88
5
+ SHA512:
6
+ metadata.gz: d7bf6101d76b1a93a5510335e0f69a39eac1b8643eb0bbebd716a9b1dace589a1443bc4ef7ee6576c4b1b8e721746bf0b01eaf2888e21c541804bf7b58cfc43e
7
+ data.tar.gz: fb4698307bc50ef4b896bda5277f556b5146e293042e9dbfec3a52b3a773792514d558c9f2235975813adace83d2ab3e426a250a9bcd1e1d7025b308c4e4ec59
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ # Version 2, December 2004
3
+ #
4
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
5
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
6
+ #
7
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
8
+ #
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # School21 API SDK
2
+
3
+ ![](https://github.com/ikael21/school21_api_sdk/actions/workflows/test.yml/badge.svg)
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)
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add school21_api_sdk
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install school21_api_sdk
16
+
17
+ ## Usage
18
+
19
+ There are multiple API's method according to School21 OpenAPI Specification. Check https://edu.21-school.ru/docs
20
+
21
+ ```ruby
22
+ require 'school21'
23
+
24
+ login = 'your_login_here'
25
+ password = 'your_password_here'
26
+
27
+ client = School21::Client.new(login: login, password: password)
28
+
29
+ # Example of getting base info about specific School21 participant
30
+ participants_api = client.participants_api
31
+ response = participants_api.participants('ikael@student.21-school.ru')
32
+
33
+ if response.success?
34
+ puts response.data
35
+ else
36
+ # Error handling
37
+ end
38
+ ```
39
+
40
+ ## Development
41
+
42
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
43
+
44
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
45
+
46
+ ## Contributing
47
+
48
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ikael21/school21_api_sdk.
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'school21'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require 'irb'
11
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class AuthApi < BaseApi
5
+ def token(login:, password:)
6
+ new_request = new_request_builder(HttpMethod::POST, '/token', :auth)
7
+ .form_param(new_parameter(login, key: :username))
8
+ .form_param(new_parameter(password, key: :password))
9
+ .form_param(new_parameter('password', key: :grant_type))
10
+ .form_param(new_parameter('s21-open-api', key: :client_id))
11
+
12
+ new_api_call_builder
13
+ .request(new_request)
14
+ .response(new_response_handler)
15
+ .execute
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class BaseApi
5
+ include CoreLibrary
6
+
7
+ SINGLE_AUTH_PARTICIPANT = :global
8
+
9
+ def self.base_uri(server)
10
+ case server
11
+ when :api_v1
12
+ 'https://edu-api.21-school.ru/services/21-school/api/v1'
13
+ when :auth
14
+ 'https://auth.sberclass.ru/auth/realms/EduPowerKeycloak/protocol/openid-connect'
15
+ end
16
+ end
17
+
18
+ def self.response_convertor(api_response)
19
+ api_response.data.deep_transform_keys! do |key|
20
+ key.underscore.to_sym
21
+ end
22
+
23
+ api_response
24
+ end
25
+
26
+ def initialize(global_configuration)
27
+ @global_configuration = global_configuration
28
+ @api_call = ApiCall.new(@global_configuration)
29
+ end
30
+
31
+ def new_api_call_builder = @api_call.new_builder
32
+
33
+ def new_response_handler
34
+ ResponseHandler.new
35
+ .deserializer(ApiHelper.method(:json_deserialize))
36
+ .is_api_response(true)
37
+ .convertor(self.class.method(:response_convertor))
38
+ end
39
+
40
+ def new_request_builder(http_method, path, server)
41
+ RequestBuilder.new
42
+ .http_method(http_method)
43
+ .path(path)
44
+ .server(server)
45
+ end
46
+
47
+ def new_parameter(value, key: nil)
48
+ Parameter.new
49
+ .key(key)
50
+ .value(value)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class ParticipantsApi < BaseApi
5
+ def participants(login)
6
+ path = "/participants/#{login}"
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 participants_projects(login, options: {})
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
23
+
24
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
25
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
26
+
27
+ parameters.each do |parameter|
28
+ new_request.query_param(parameter)
29
+ end
30
+
31
+ new_api_call_builder
32
+ .request(new_request)
33
+ .response(new_response_handler)
34
+ .execute
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class ProjectsApi < BaseApi
5
+ def projects(project_id)
6
+ path = "/projects/#{project_id}"
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 projects_participants(project_id, options: {})
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
23
+
24
+ new_request = new_request_builder(HttpMethod::GET, path, :api_v1)
25
+ .auth(CoreLibrary::Single.new(SINGLE_AUTH_PARTICIPANT))
26
+
27
+ parameters.each do |parameter|
28
+ new_request.query_param(parameter)
29
+ end
30
+
31
+ new_api_call_builder
32
+ .request(new_request)
33
+ .response(new_response_handler)
34
+ .execute
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class AccessToken
5
+ attr_reader :access_token
6
+
7
+ def initialize(access_token, expires_in)
8
+ @access_token = access_token
9
+ @expires_at = Time.now + expires_in
10
+ end
11
+
12
+ def expired?
13
+ Time.now >= @expires_at
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class AuthorizationHeader < CoreLibrary::HeaderAuth
5
+ def error_message
6
+ 'BearerAuth: access_token is undefined.'
7
+ end
8
+
9
+ def initialize(bearer_auth_credentials)
10
+ 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?
16
+
17
+ super(auth_params)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class BearerAuthCredentials
5
+ attr_reader :access_token
6
+
7
+ def initialize(access_token:)
8
+ raise ArgumentError, 'access_token cannot be nil' if access_token.nil?
9
+
10
+ @access_token = access_token.access_token
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ class Client
5
+ include CoreLibrary
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)
14
+
15
+ @login = login
16
+ @password = password
17
+
18
+ @config = GlobalConfiguration
19
+ .new(client_configuration:)
20
+ .base_uri_executor(BaseApi.method(:base_uri))
21
+
22
+ initialize_auth!
23
+ end
24
+
25
+ def auth_api = @auth_api ||= AuthApi.new(@config)
26
+
27
+ def participants_api
28
+ initialize_auth! if @access_token.expired?
29
+
30
+ ParticipantsApi.new(@config)
31
+ end
32
+
33
+ def projects_api
34
+ initialize_auth! if @access_token.expired?
35
+
36
+ ProjectsApi.new(@config)
37
+ end
38
+
39
+ private
40
+
41
+ def initialize_auth!
42
+ @access_token = request_access_token!
43
+
44
+ initialize_auth_managers
45
+ end
46
+
47
+ def initialize_auth_managers
48
+ auth_managers = {}
49
+
50
+ creds = BearerAuthCredentials.new(access_token: @access_token)
51
+ auth_managers[BaseApi::SINGLE_AUTH_PARTICIPANT] = AuthorizationHeader.new(creds)
52
+
53
+ @config.auth_managers(auth_managers)
54
+ end
55
+
56
+ def request_access_token!
57
+ auth_api_response = auth_api.token(login: @login, password: @password)
58
+ raise 'Access Token Error' unless auth_api_response.success?
59
+
60
+ AccessToken.new(*auth_api_response.data.values_at(:access_token, :expires_in))
61
+ end
62
+
63
+ def logging_configuration
64
+ 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)
67
+
68
+ ApiLoggingConfiguration.new(nil, nil, api_request_config, api_response_config, false)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module School21
4
+ VERSION = '0.1.0'
5
+ end
data/lib/school21.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apimatic_core'
4
+ require 'apimatic_faraday_client_adapter'
5
+
6
+ require 'active_support/all'
7
+
8
+ require_relative 'school21/auth/access_token'
9
+ require_relative 'school21/auth/authorization_header'
10
+ require_relative 'school21/auth/bearer_auth_credentials'
11
+
12
+ require_relative 'school21/api/base_api'
13
+ require_relative 'school21/api/participants_api'
14
+ require_relative 'school21/api/auth_api'
15
+ require_relative 'school21/api/projects_api'
16
+
17
+ require_relative 'school21/client'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ require 'simplecov-cobertura'
5
+
6
+ SimpleCov.start
7
+ SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
8
+
9
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
10
+
11
+ require 'school21'
12
+ require 'minitest/autorun'
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: school21_api_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Anton Yudin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-08-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: apimatic_core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: apimatic_core_interfaces
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: apimatic_faraday_client_adapter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: base64
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: ''
84
+ email:
85
+ - ikael.fess@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - LICENSE
91
+ - README.md
92
+ - bin/console
93
+ - bin/setup
94
+ - lib/school21.rb
95
+ - lib/school21/api/auth_api.rb
96
+ - lib/school21/api/base_api.rb
97
+ - lib/school21/api/participants_api.rb
98
+ - lib/school21/api/projects_api.rb
99
+ - lib/school21/auth/access_token.rb
100
+ - lib/school21/auth/authorization_header.rb
101
+ - lib/school21/auth/bearer_auth_credentials.rb
102
+ - lib/school21/client.rb
103
+ - lib/school21/version.rb
104
+ - test/test_helper.rb
105
+ homepage: https://github.com/ikael21/school21_api_sdk
106
+ licenses:
107
+ - Nonstandard
108
+ metadata:
109
+ rubygems_mfa_required: 'true'
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '3.3'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubygems_version: 3.5.11
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: School21 API SDK
129
+ test_files: []