lessonly-api 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.md +22 -0
- data/README.md +51 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lessonly-api.gemspec +35 -0
- data/lib/lessonly_api.rb +46 -0
- data/lib/lessonly_api/errors.rb +26 -0
- data/lib/lessonly_api/groups.rb +60 -0
- data/lib/lessonly_api/request.rb +11 -0
- data/lib/lessonly_api/resource_type/assignment.rb +19 -0
- data/lib/lessonly_api/resource_type/base.rb +80 -0
- data/lib/lessonly_api/resource_type/group.rb +7 -0
- data/lib/lessonly_api/resource_type/groups.rb +7 -0
- data/lib/lessonly_api/resource_type/lesson.rb +7 -0
- data/lib/lessonly_api/resource_type/user.rb +32 -0
- data/lib/lessonly_api/resource_type/user_assignments.rb +7 -0
- data/lib/lessonly_api/resource_type/user_group.rb +12 -0
- data/lib/lessonly_api/resource_type/users.rb +7 -0
- data/lib/lessonly_api/resource_type/webhook.rb +16 -0
- data/lib/lessonly_api/users.rb +61 -0
- data/lib/lessonly_api/utils/client.rb +130 -0
- data/lib/lessonly_api/utils/custom_field_converter.rb +41 -0
- data/lib/lessonly_api/version.rb +3 -0
- data/lib/lessonly_api/webhook.rb +50 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 685801473282dac177c5b10f4c1a8ed916f7def482c892cb29191f6cf5678941
|
4
|
+
data.tar.gz: 6f0804275927087399b2ad01d93415204ec3c79fd4afc77d7d4cf846f7d047ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aed4cacf823900924aa286c555e531df1c7f18e2666f118fce379964a19bcf2b7f78eb7de520cdb4f42544e3857aba8b85990c03c64ca4cd6768ff4e96690a00
|
7
|
+
data.tar.gz: 6f90abf488d237699dbcf2c687ca1956388f85416e2cc8b8c8c89bbe9a93652cb485a60dd1dc11db23af3592c73c77804b6d0698de72e83ceb6e9a67f11d7d72
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Aptible, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Lessonly Api Ruby Client
|
2
|
+
|
3
|
+
|
4
|
+
Ruby client for [Lesson.ly](http://lesson.ly) API.
|
5
|
+
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add the following line to your application's Gemfile
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'lessonly-api'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then run `bundle install`.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
First, configure your client:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'lessonly'
|
23
|
+
|
24
|
+
LessonlyApi.configure do |config|
|
25
|
+
config.root_url = 'https://api.lesson.ly/api/v1'
|
26
|
+
config.api_key = `LESSONLY API KEY`
|
27
|
+
config.domain = `LESSONLY SUBDOMAIN`
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
This is best done in an application initializer inside `config/initializers`.
|
32
|
+
|
33
|
+
From here, you can interact with the Lessonly API resources however you wish:
|
34
|
+
|
35
|
+
### Users
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
all_users = LessonlyApi::Users.list
|
39
|
+
|
40
|
+
skylar = LessonlyApi::Users.show(user_id)
|
41
|
+
skylar.name # "John Doe"
|
42
|
+
skylar.email # "johndoe@aptible.com"
|
43
|
+
|
44
|
+
frank = LessonlyApi::User.create({ name: 'Frank Macreery', email: 'frank@aptible.com', role: 'learner' })
|
45
|
+
frank.name # "Frank Macreery"
|
46
|
+
```
|
47
|
+
|
48
|
+
## Copyright and License
|
49
|
+
|
50
|
+
MIT License, see [LICENSE](LICENSE.md) for details.
|
51
|
+
|
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'dotenv/load'
|
6
|
+
|
7
|
+
require 'lessonly_api'
|
8
|
+
|
9
|
+
LessonlyApi.configure do |config|
|
10
|
+
config.root_url = ENV['LESSONLY_ROOT_URL']
|
11
|
+
config.api_key = ENV['LESSONLY_API_KEY']
|
12
|
+
config.domain = ENV['LESSONLY_DOMAIN']
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'pry-byebug'
|
16
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
|
7
|
+
require 'lessonly_api/version'
|
8
|
+
|
9
|
+
Gem::Specification.new do |spec|
|
10
|
+
spec.name = 'lessonly-api'
|
11
|
+
spec.version = LessonlyApi::VERSION
|
12
|
+
spec.authors = ['Ilya Kamenko']
|
13
|
+
spec.email = ['ilya.kamenko@gmail.com']
|
14
|
+
spec.description = 'Ruby client for Lesson.ly API'
|
15
|
+
spec.summary = 'Ruby client for Lesson.ly API'
|
16
|
+
spec.homepage = 'https://github.com/toptal/lessonly-api'
|
17
|
+
spec.license = 'MIT'
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(spec)/})
|
21
|
+
end
|
22
|
+
spec.test_files = spec.files.grep(%r{^spec\/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_runtime_dependency 'gem_config'
|
26
|
+
spec.add_runtime_dependency 'activemodel', '>= 3.2'
|
27
|
+
spec.add_runtime_dependency 'faraday', '>= 0.8'
|
28
|
+
spec.add_runtime_dependency 'httpclient', '~> 2.8'
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '>= 2.1.2'
|
31
|
+
spec.add_development_dependency 'dotenv', '~> 2.2'
|
32
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.7'
|
33
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
end
|
data/lib/lessonly_api.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'gem_config'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module LessonlyApi
|
5
|
+
include GemConfig::Base
|
6
|
+
|
7
|
+
with_configuration do
|
8
|
+
has :logger,
|
9
|
+
classes: ::Logger,
|
10
|
+
default: ::Logger.new($stdout)
|
11
|
+
|
12
|
+
has :root_url,
|
13
|
+
classes: String,
|
14
|
+
default: ENV['LESSONLY_ROOT_URL'] || 'https://api.lesson.ly/api/v1.1'
|
15
|
+
|
16
|
+
has :domain,
|
17
|
+
classes: String,
|
18
|
+
default: ENV['LESSONLY_DOMAIN'] || ''
|
19
|
+
|
20
|
+
has :api_key,
|
21
|
+
classes: String,
|
22
|
+
default: ENV['LESSONLY_API_KEY'] || ''
|
23
|
+
|
24
|
+
has :webhook_handler
|
25
|
+
has :webhook_authentication, classes: String
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'lessonly_api/version'
|
30
|
+
require 'lessonly_api/errors'
|
31
|
+
|
32
|
+
require 'lessonly_api/utils/client'
|
33
|
+
require 'lessonly_api/utils/custom_field_converter'
|
34
|
+
require 'lessonly_api/resource_type/base'
|
35
|
+
require 'lessonly_api/request'
|
36
|
+
|
37
|
+
require 'lessonly_api/users'
|
38
|
+
|
39
|
+
require 'lessonly_api/resource_type/users'
|
40
|
+
require 'lessonly_api/resource_type/user'
|
41
|
+
require 'lessonly_api/resource_type/webhook'
|
42
|
+
require 'lessonly_api/resource_type/lesson'
|
43
|
+
require 'lessonly_api/resource_type/user_group'
|
44
|
+
require 'lessonly_api/resource_type/user_assignments'
|
45
|
+
require 'lessonly_api/resource_type/assignment'
|
46
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LessonlyApi::Errors
|
2
|
+
class Base < StandardError; end
|
3
|
+
class ApiTimeoutError < Base; end
|
4
|
+
class InvalidJson < Base; end
|
5
|
+
|
6
|
+
class ApiError < Base
|
7
|
+
attr_reader :body
|
8
|
+
|
9
|
+
def initialize(body)
|
10
|
+
@body = body
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
"#{self.class.name}: #{body['error_info']}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class BadRequest < ApiError; end
|
19
|
+
class Unauthorized < ApiError; end
|
20
|
+
class Forbidden < ApiError; end
|
21
|
+
class NotFound < ApiError; end
|
22
|
+
class MethodNotAllowed < ApiError; end
|
23
|
+
class NotAcceptable < ApiError; end
|
24
|
+
class InternalServerError < ApiError; end
|
25
|
+
class ServiceUnavailable < ApiError; end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module LessonlyApi
|
2
|
+
class Groups < Request
|
3
|
+
class << self
|
4
|
+
def list
|
5
|
+
raw_result = get('/groups')
|
6
|
+
raw_result['groups'].map { |raw_group| ResourceType::Group.new(raw_group) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def show(id)
|
10
|
+
raw_result = get("/groups/#{id}")
|
11
|
+
LessonlyApi::ResourceType::Group.new(raw_result)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(attributes = {})
|
15
|
+
raw_result = post("/users", attributes)
|
16
|
+
ResourceType::User.new(raw_result)
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(id, attributes = {})
|
20
|
+
raw_result = put("/users/#{id}", attributes)
|
21
|
+
ResourceType::User.new(raw_result)
|
22
|
+
end
|
23
|
+
|
24
|
+
def archive(id)
|
25
|
+
raw_result = put("/users/#{id}/archive")
|
26
|
+
ResourceType::User.new(raw_result)
|
27
|
+
end
|
28
|
+
|
29
|
+
def restore(id)
|
30
|
+
raw_result = put("/users/#{id}/restore")
|
31
|
+
ResourceType::User.new(raw_result)
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(id)
|
35
|
+
raw_result = delete("/users/#{id}")
|
36
|
+
ResourceType::User.new(raw_result)
|
37
|
+
end
|
38
|
+
|
39
|
+
def user_groups(id)
|
40
|
+
raw_result = get("/users/#{id}/groups")
|
41
|
+
# ResourceType::User.new(raw_result)
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_user_groups(id)
|
45
|
+
raw_result = get("/users/#{id}/groups")
|
46
|
+
# ResourceType::User.new(raw_result)
|
47
|
+
end
|
48
|
+
|
49
|
+
def user_assignments(id)
|
50
|
+
raw_result = get("/users/#{id}/assignments")
|
51
|
+
#
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_user_assignments(id)
|
55
|
+
raw_result = get("/users/#{id}/assignments")
|
56
|
+
#
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module LessonlyApi
|
2
|
+
module ResourceType
|
3
|
+
class Assignment < LessonlyApi::ResourceType::Base
|
4
|
+
fields(
|
5
|
+
:id,
|
6
|
+
:assignee_id,
|
7
|
+
:ext_id,
|
8
|
+
:assignable_id,
|
9
|
+
:assignable_type,
|
10
|
+
:due_by,
|
11
|
+
:reassigned_at,
|
12
|
+
:completed_at,
|
13
|
+
:updated_at,
|
14
|
+
:status,
|
15
|
+
:score
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module LessonlyApi
|
7
|
+
module ResourceType
|
8
|
+
class Base
|
9
|
+
include ActiveModel::Model
|
10
|
+
include ActiveModel::Dirty
|
11
|
+
include ActiveModel::Serializers::JSON
|
12
|
+
|
13
|
+
class_attribute :fields_names
|
14
|
+
self.fields_names = []
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def from_json(json)
|
18
|
+
parsed_json = json && JSON.parse(json).to_h
|
19
|
+
return new({}) unless parsed_json
|
20
|
+
|
21
|
+
new(parsed_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def fields(*keys_with_types)
|
25
|
+
keys_with_types.each do |name_or_hash|
|
26
|
+
field_name = define_methods_for(name_or_hash)
|
27
|
+
self.fields_names += [field_name]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def load(string)
|
32
|
+
from_json(string)
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump(data_type)
|
36
|
+
data_type.to_json
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def define_methods_for(name_or_hash)
|
42
|
+
if name_or_hash.is_a?(Hash)
|
43
|
+
define_custom_field(*name_or_hash.to_a.first)
|
44
|
+
else
|
45
|
+
define_simple_field(name_or_hash)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def define_custom_field(name, data_type)
|
50
|
+
attr_reader name
|
51
|
+
|
52
|
+
define_method("#{name}=") do |value|
|
53
|
+
value = LessonlyApi::Utils::CustomFieldConverter.new(data_type).convert(value)
|
54
|
+
instance_variable_set("@#{name}", value)
|
55
|
+
end
|
56
|
+
|
57
|
+
name
|
58
|
+
end
|
59
|
+
|
60
|
+
def define_simple_field(name)
|
61
|
+
attr_accessor name
|
62
|
+
name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(attributes = {})
|
67
|
+
defined_attributes = attributes.with_indifferent_access.slice(*fields_names)
|
68
|
+
|
69
|
+
super(defined_attributes)
|
70
|
+
end
|
71
|
+
|
72
|
+
def attributes
|
73
|
+
fields_names.each_with_object({}) do |field, hash|
|
74
|
+
value = public_send(field)
|
75
|
+
hash[field] = value if value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module LessonlyApi
|
2
|
+
module ResourceType
|
3
|
+
class User < LessonlyApi::ResourceType::Base
|
4
|
+
fields(
|
5
|
+
:id,
|
6
|
+
:resource_type,
|
7
|
+
:type,
|
8
|
+
:ext_uid,
|
9
|
+
:email,
|
10
|
+
:name,
|
11
|
+
:role,
|
12
|
+
:role_id,
|
13
|
+
:archived_at,
|
14
|
+
:archived_by_user_id,
|
15
|
+
:job_title,
|
16
|
+
:business_unit,
|
17
|
+
:department,
|
18
|
+
:location,
|
19
|
+
:locale,
|
20
|
+
:hire_date,
|
21
|
+
:manager_name,
|
22
|
+
:mobile_phone_number,
|
23
|
+
:custom_user_field_data,
|
24
|
+
{groups: :user_group}
|
25
|
+
)
|
26
|
+
|
27
|
+
def user_assignments
|
28
|
+
LessonlyApi::Users.user_assignments(self.id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module LessonlyApi
|
2
|
+
module ResourceType
|
3
|
+
class Webhook < LessonlyApi::ResourceType::Base
|
4
|
+
fields(
|
5
|
+
{user: :user},
|
6
|
+
{lesson: :lesson},
|
7
|
+
:score,
|
8
|
+
:score_percent,
|
9
|
+
:started_at,
|
10
|
+
:completed_at,
|
11
|
+
:assigned_at,
|
12
|
+
:report_card_url
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module LessonlyApi
|
2
|
+
class Users < Request
|
3
|
+
class << self
|
4
|
+
def list(page: 1, per_page: 50, **filters)
|
5
|
+
raw_result = get('/users', page: page, per_page: per_page, filter: filters)
|
6
|
+
ResourceType::Users.new(raw_result)
|
7
|
+
end
|
8
|
+
|
9
|
+
def show(id)
|
10
|
+
raw_result = get("/users/#{id}")
|
11
|
+
LessonlyApi::ResourceType::User.new(raw_result)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(attributes = {})
|
15
|
+
raw_result = post("/users", attributes)
|
16
|
+
ResourceType::User.new(raw_result)
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(id, attributes = {})
|
20
|
+
raw_result = put("/users/#{id}", attributes)
|
21
|
+
ResourceType::User.new(raw_result)
|
22
|
+
end
|
23
|
+
|
24
|
+
def archive(id)
|
25
|
+
raw_result = put("/users/#{id}/archive")
|
26
|
+
ResourceType::User.new(raw_result)
|
27
|
+
end
|
28
|
+
|
29
|
+
def restore(id)
|
30
|
+
raw_result = put("/users/#{id}/restore")
|
31
|
+
ResourceType::User.new(raw_result)
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO: i.kamenko method name should be `delete` probably
|
35
|
+
def destroy(id)
|
36
|
+
raw_result = delete("/users/#{id}")
|
37
|
+
ResourceType::User.new(raw_result)
|
38
|
+
end
|
39
|
+
|
40
|
+
def user_groups(id)
|
41
|
+
raw_result = get("/users/#{id}/groups")
|
42
|
+
ResourceType::UserGroup.new(raw_result)
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_user_groups(id, attributes = {})
|
46
|
+
raw_result = put("/users/#{id}/groups", attributes)
|
47
|
+
ResourceType::UserGroup.new(raw_result)
|
48
|
+
end
|
49
|
+
|
50
|
+
def user_assignments(id)
|
51
|
+
raw_result = get("/users/#{id}/assignments")
|
52
|
+
ResourceType::UserAssignments.new(raw_result)
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_user_assignments(id, assignments = [])
|
56
|
+
raw_result = put("/users/#{id}/assignments", assignments: assignments)
|
57
|
+
ResourceType::UserAssignments.new(raw_result)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'faraday'
|
3
|
+
require 'base64'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module LessonlyApi
|
7
|
+
module Utils
|
8
|
+
class Client
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
ERRORS_MAPPING = {
|
12
|
+
400 => LessonlyApi::Errors::BadRequest,
|
13
|
+
401 => LessonlyApi::Errors::Unauthorized,
|
14
|
+
403 => LessonlyApi::Errors::Forbidden,
|
15
|
+
404 => LessonlyApi::Errors::NotFound,
|
16
|
+
405 => LessonlyApi::Errors::MethodNotAllowed,
|
17
|
+
406 => LessonlyApi::Errors::NotAcceptable,
|
18
|
+
500 => LessonlyApi::Errors::InternalServerError,
|
19
|
+
503 => LessonlyApi::Errors::ServiceUnavailable
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
23
|
+
|
24
|
+
attr_reader :root_url, :domain, :api_key, :logger
|
25
|
+
|
26
|
+
def initialize(configuration)
|
27
|
+
@root_url = configuration.root_url
|
28
|
+
@domain = configuration.domain
|
29
|
+
@api_key = configuration.api_key
|
30
|
+
@logger = configuration.logger
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.instance
|
34
|
+
@instance ||= new(LessonlyApi.configuration)
|
35
|
+
end
|
36
|
+
|
37
|
+
def get(endpoint, params = {})
|
38
|
+
send_request(:get, endpoint, params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def post(endpoint, params = {})
|
42
|
+
send_request(:post, endpoint, params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def put(endpoint, params = {})
|
46
|
+
send_request(:put, endpoint, params)
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete(endpoint, params = {})
|
50
|
+
send_request(:delete, endpoint, params)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def connection
|
56
|
+
Faraday.new(root_url, http_options) do |faraday|
|
57
|
+
faraday.request :url_encoded
|
58
|
+
faraday.response :logger, logger, headers: true, bodies: true
|
59
|
+
|
60
|
+
faraday.adapter :httpclient
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def http_options
|
65
|
+
{
|
66
|
+
headers: {
|
67
|
+
'Accept' => 'application/json',
|
68
|
+
'Content-Type' => 'application/json',
|
69
|
+
'Authorization' => auth_token
|
70
|
+
}
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def auth_token
|
75
|
+
Base64.strict_encode64("#{domain}:#{api_key}")
|
76
|
+
end
|
77
|
+
|
78
|
+
def send_request(method, endpoint, params)
|
79
|
+
response = with_tag do
|
80
|
+
connection.public_send(method) do |request|
|
81
|
+
# TODO: i.kamenko refactor it
|
82
|
+
request.url "/api/v1.1/#{endpoint}"
|
83
|
+
assign_params(request, method: method, params: params)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
process_response(response)
|
88
|
+
rescue Faraday::TimeoutError => e
|
89
|
+
raise LessonlyApi::Errors::ApiTimeoutError, e.message
|
90
|
+
rescue Faraday::Error => e
|
91
|
+
raise LessonlyApi::Errors::Base, e.message
|
92
|
+
end
|
93
|
+
|
94
|
+
def assign_params(request, method:, params:)
|
95
|
+
if method == :get
|
96
|
+
request.params = params
|
97
|
+
else
|
98
|
+
request.body = params.to_json
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def process_response(response)
|
103
|
+
return process_success(response) if response.status >= 200 && response.status < 300
|
104
|
+
|
105
|
+
error = ERRORS_MAPPING[response.status] || LessonlyApi::Errors::ApiError
|
106
|
+
raise(error, parse_json(response.body))
|
107
|
+
end
|
108
|
+
|
109
|
+
def process_success(response)
|
110
|
+
return {} if response.body.empty?
|
111
|
+
|
112
|
+
parse_json(response.body)
|
113
|
+
end
|
114
|
+
|
115
|
+
def with_tag
|
116
|
+
if logger&.respond_to?(:tagged)
|
117
|
+
logger.tagged('LESSONLY API') { yield }
|
118
|
+
else
|
119
|
+
yield
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def parse_json(data)
|
124
|
+
JSON.parse(data)
|
125
|
+
rescue JSON::ParserError => e
|
126
|
+
raise LessonlyApi::Errors::InvalidJson, e.message
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
|
5
|
+
module LessonlyApi
|
6
|
+
module Utils
|
7
|
+
class CustomFieldConverter
|
8
|
+
CONVERSIONS = {
|
9
|
+
big_decimal: ->(val) { val.is_a?(BigDecimal) ? val : val && BigDecimal(val.to_s) },
|
10
|
+
date: ->(val) { val.is_a?(Date) ? val : val && Date.parse(val) }
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def initialize(data_type)
|
14
|
+
@data_type = data_type
|
15
|
+
end
|
16
|
+
|
17
|
+
def convert(value)
|
18
|
+
if @data_type.is_a?(Array)
|
19
|
+
convert_array(value)
|
20
|
+
elsif CONVERSIONS.key?(@data_type)
|
21
|
+
CONVERSIONS[@data_type].call(value)
|
22
|
+
else
|
23
|
+
wrap(value, @data_type)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def wrap(value, data_type)
|
30
|
+
data_type_class = "LessonlyApi::ResourceType::#{data_type.to_s.camelize}".constantize
|
31
|
+
value.is_a?(LessonlyApi::ResourceType::Base) ? value : data_type_class.new(value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def convert_array(array)
|
35
|
+
return [] if array.blank?
|
36
|
+
|
37
|
+
array.map { |item| wrap(item, @data_type.first) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module LessonlyApi
|
2
|
+
class Webhook
|
3
|
+
class << self
|
4
|
+
def call(env)
|
5
|
+
new(env).call
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :env
|
10
|
+
|
11
|
+
def initialize(env)
|
12
|
+
@env = env
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
return [405, {"Content-Type" => "text/plain"}, ['Method Not Allowed']] unless webhook_handler
|
17
|
+
return [401, {"Content-Type" => "text/plain"}, ['Unauthorized']] unless authorized?
|
18
|
+
|
19
|
+
parse_webhook_data
|
20
|
+
|
21
|
+
return [406, {"Content-Type" => "text/plain"}, ['Not Acceptable']] if raw_webhook_data.nil?
|
22
|
+
|
23
|
+
webhook_handler.call(webhook_data)
|
24
|
+
|
25
|
+
[200, {"Content-Type" => "text/plain"}, ['OK']]
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :raw_webhook_data
|
31
|
+
|
32
|
+
def authorized?
|
33
|
+
env['HTTP_AUTHORIZATION'] == LessonlyApi.configuration.webhook_authentication
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_webhook_data
|
37
|
+
@raw_webhook_data = JSON.parse(env['rack.input'].read)
|
38
|
+
rescue JSON::ParserError
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def webhook_data
|
43
|
+
LessonlyApi::ResourceType::Webhook.new(raw_webhook_data)
|
44
|
+
end
|
45
|
+
|
46
|
+
def webhook_handler
|
47
|
+
LessonlyApi.configuration.webhook_handler
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lessonly-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ilya Kamenko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-06-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gem_config
|
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: activemodel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httpclient
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.1.2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.1.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: dotenv
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry-byebug
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.7'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.7'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '12.3'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '12.3'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.0'
|
139
|
+
description: Ruby client for Lesson.ly API
|
140
|
+
email:
|
141
|
+
- ilya.kamenko@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rspec"
|
148
|
+
- Gemfile
|
149
|
+
- LICENSE.md
|
150
|
+
- README.md
|
151
|
+
- bin/console
|
152
|
+
- bin/setup
|
153
|
+
- lessonly-api.gemspec
|
154
|
+
- lib/lessonly_api.rb
|
155
|
+
- lib/lessonly_api/errors.rb
|
156
|
+
- lib/lessonly_api/groups.rb
|
157
|
+
- lib/lessonly_api/request.rb
|
158
|
+
- lib/lessonly_api/resource_type/assignment.rb
|
159
|
+
- lib/lessonly_api/resource_type/base.rb
|
160
|
+
- lib/lessonly_api/resource_type/group.rb
|
161
|
+
- lib/lessonly_api/resource_type/groups.rb
|
162
|
+
- lib/lessonly_api/resource_type/lesson.rb
|
163
|
+
- lib/lessonly_api/resource_type/user.rb
|
164
|
+
- lib/lessonly_api/resource_type/user_assignments.rb
|
165
|
+
- lib/lessonly_api/resource_type/user_group.rb
|
166
|
+
- lib/lessonly_api/resource_type/users.rb
|
167
|
+
- lib/lessonly_api/resource_type/webhook.rb
|
168
|
+
- lib/lessonly_api/users.rb
|
169
|
+
- lib/lessonly_api/utils/client.rb
|
170
|
+
- lib/lessonly_api/utils/custom_field_converter.rb
|
171
|
+
- lib/lessonly_api/version.rb
|
172
|
+
- lib/lessonly_api/webhook.rb
|
173
|
+
homepage: https://github.com/toptal/lessonly-api
|
174
|
+
licenses:
|
175
|
+
- MIT
|
176
|
+
metadata: {}
|
177
|
+
post_install_message:
|
178
|
+
rdoc_options: []
|
179
|
+
require_paths:
|
180
|
+
- lib
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
|
+
requirements:
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
191
|
+
requirements: []
|
192
|
+
rubygems_version: 3.1.4
|
193
|
+
signing_key:
|
194
|
+
specification_version: 4
|
195
|
+
summary: Ruby client for Lesson.ly API
|
196
|
+
test_files: []
|