effective_learndash 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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +126 -0
- data/Rakefile +18 -0
- data/app/assets/config/effective_learndash_manifest.js +3 -0
- data/app/assets/javascripts/effective_learndash/base.js +0 -0
- data/app/assets/javascripts/effective_learndash.js +1 -0
- data/app/assets/stylesheets/effective_learndash/base.scss +0 -0
- data/app/assets/stylesheets/effective_learndash.scss +1 -0
- data/app/controllers/admin/learndash_courses_controller.rb +15 -0
- data/app/controllers/admin/learndash_enrollments_controller.rb +9 -0
- data/app/controllers/admin/learndash_users_controller.rb +11 -0
- data/app/datatables/admin/effective_learndash_courses_datatable.rb +26 -0
- data/app/datatables/admin/effective_learndash_enrollments_datatable.rb +39 -0
- data/app/datatables/admin/effective_learndash_users_datatable.rb +25 -0
- data/app/helpers/effective_learndash_helper.rb +2 -0
- data/app/models/concerns/effective_learndash_owner.rb +64 -0
- data/app/models/effective/learndash_api.rb +269 -0
- data/app/models/effective/learndash_course.rb +39 -0
- data/app/models/effective/learndash_enrollment.rb +73 -0
- data/app/models/effective/learndash_user.rb +97 -0
- data/app/views/admin/learndash_courses/_learndash_course.html.haml +12 -0
- data/app/views/admin/learndash_enrollments/_form.html.haml +16 -0
- data/app/views/admin/learndash_owners/_form.html.haml +5 -0
- data/app/views/admin/learndash_users/_form.html.haml +6 -0
- data/app/views/admin/learndash_users/_learndash_user.html.haml +21 -0
- data/config/effective_learndash.rb +18 -0
- data/config/routes.rb +25 -0
- data/db/migrate/01_create_effective_learndash.rb.erb +48 -0
- data/db/seeds.rb +1 -0
- data/lib/effective_learndash/engine.rb +22 -0
- data/lib/effective_learndash/version.rb +3 -0
- data/lib/effective_learndash.rb +52 -0
- data/lib/generators/effective_learndash/install_generator.rb +29 -0
- data/lib/generators/templates/effective_learndash_mailer_preview.rb +4 -0
- data/lib/tasks/effective_learndash_tasks.rake +8 -0
- metadata +232 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '0970ec691c0993f6c77e5131eba3da9ed11ef1c74a5cd00f0cdba5373cf1f5b4'
|
4
|
+
data.tar.gz: dd0229161ba6030e9711202259063af16e506ec6d029647d43a112b4ac4f8150
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a6ff74e9f0842c69d6f69886a8a7ef86b1196bbfd83e803afdd58e075c8ac99371a4b125d22b67e136268b4b5d4ac6718371b3ff6db936abddcb123ac3d8b28a
|
7
|
+
data.tar.gz: e742085fcf413769c5936203091663b95d704a98d4b26b3778d77668f62d7ec79a53c52ffade1e9cf0d4cf56941ab83797d67a3efac1905ae30755f416958ff2
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2022 Code and Effect Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# Effective Learndash
|
2
|
+
|
3
|
+
Create Wordpress users and read Learndash course progress. This is an unoffocial integration that is not supported or affiliated with WordPress or Learndash.
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
This requires Rails 6+ and Twitter Bootstrap 4 and just works with Devise.
|
8
|
+
|
9
|
+
Please first install the [effective_datatables](https://github.com/code-and-effect/effective_datatables) gem.
|
10
|
+
|
11
|
+
Please download and install the [Twitter Bootstrap4](http://getbootstrap.com)
|
12
|
+
|
13
|
+
Add to your Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'haml-rails' # or try using gem 'hamlit-rails'
|
17
|
+
gem 'effective_learndash'
|
18
|
+
```
|
19
|
+
|
20
|
+
Run the bundle command to install it:
|
21
|
+
|
22
|
+
```console
|
23
|
+
bundle install
|
24
|
+
```
|
25
|
+
|
26
|
+
Then run the generator:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
rails generate effective_learndash:install
|
30
|
+
```
|
31
|
+
|
32
|
+
The generator will install an initializer which describes all configuration options and creates a database migration.
|
33
|
+
|
34
|
+
If you want to tweak the table names, manually adjust both the configuration file and the migration now.
|
35
|
+
|
36
|
+
Then migrate the database:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
rake db:migrate
|
40
|
+
```
|
41
|
+
|
42
|
+
Add to your user class:
|
43
|
+
|
44
|
+
```
|
45
|
+
class User < ApplicationRecord
|
46
|
+
effective_learndash_owner
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Add a link to the admin menu:
|
51
|
+
|
52
|
+
```haml
|
53
|
+
- if can? :admin, :effective_learndash
|
54
|
+
= nav_dropdown 'Learndash' do
|
55
|
+
- if can? :index, Effective::LearndashUser
|
56
|
+
= nav_link_to 'Learndash Users', effective_learndash.admin_learndash_users_path
|
57
|
+
|
58
|
+
- if can? :index, Effective::LearndashCourse
|
59
|
+
= nav_link_to 'Learndash Courses', effective_learndash.admin_learndash_courses_path
|
60
|
+
|
61
|
+
- if can? :index, Effective::LearndashEnrollment
|
62
|
+
= nav_link_to 'Learndash Enrollments', effective_learndash.admin_learndash_enrollments_path
|
63
|
+
```
|
64
|
+
|
65
|
+
## Authorization
|
66
|
+
|
67
|
+
All authorization checks are handled via the effective_resources gem found in the `config/initializers/effective_resources.rb` file.
|
68
|
+
|
69
|
+
## Permissions
|
70
|
+
|
71
|
+
The permissions you actually want to define are as follows (using CanCan):
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
if user.admin?
|
75
|
+
can :admin, :effective_learndash
|
76
|
+
|
77
|
+
can(crud + [:refresh], Effective::LearndashUser)
|
78
|
+
can(crud + [:refresh], Effective::LearndashCourse)
|
79
|
+
|
80
|
+
can(crud, Effective::LearndashEnrollment)
|
81
|
+
can(:refresh, Effective::LearndashEnrollment) { |enrollment| !enrollment.completed? }
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
## Configuring Learndash
|
86
|
+
|
87
|
+
Your Wordpress should be configured ahead of time with the Learndash plugin.
|
88
|
+
|
89
|
+
Please generate an application password via:
|
90
|
+
|
91
|
+
https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/
|
92
|
+
|
93
|
+
and fill in the username/password details in config/initializers/effective_leardash.rb
|
94
|
+
|
95
|
+
## Working with Learndash
|
96
|
+
|
97
|
+
Visit `/admin/learndash_courses` and Refresh the list of Courses.
|
98
|
+
|
99
|
+
Create a New Learndash User will create a new Wordpress/Learndash account with a username/password according to the settings in the config file.
|
100
|
+
|
101
|
+
When you create a user, you only get access to the password once. So any existing users will have an unknown password.
|
102
|
+
|
103
|
+
Create a new Learndash Enrollment to enroll a learndash user into a course. This will begin tracking their progress.
|
104
|
+
|
105
|
+
There are no webhooks or callbacks from Learndash, everything is a GET request that updates the local database.
|
106
|
+
|
107
|
+
You can refresh an entire learndash user in one operation and it will sync the entire user at once, `user.learndash_user.refresh!`
|
108
|
+
|
109
|
+
## License
|
110
|
+
|
111
|
+
MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
|
112
|
+
|
113
|
+
## Testing
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
rails test
|
117
|
+
```
|
118
|
+
|
119
|
+
## Contributing
|
120
|
+
|
121
|
+
1. Fork it
|
122
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
123
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
124
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
125
|
+
5. Bonus points for test coverage
|
126
|
+
6. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
|
3
|
+
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
4
|
+
load "rails/tasks/engine.rake"
|
5
|
+
|
6
|
+
load "rails/tasks/statistics.rake"
|
7
|
+
|
8
|
+
require "bundler/gem_tasks"
|
9
|
+
|
10
|
+
require "rake/testtask"
|
11
|
+
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = false
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: :test
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree ./effective_learndash
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
@import 'effective_learndash/base';
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Admin
|
2
|
+
class LearndashCoursesController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
before_action { EffectiveResources.authorize!(self, :admin, :effective_learndash) }
|
5
|
+
|
6
|
+
include Effective::CrudController
|
7
|
+
|
8
|
+
def refresh
|
9
|
+
resource_scope.refresh!
|
10
|
+
flash[:success] = "Successfully refreshed Courses from Learndash"
|
11
|
+
redirect_to effective_learndash.admin_learndash_courses_path
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Admin
|
2
|
+
class LearndashEnrollmentsController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
before_action { EffectiveResources.authorize!(self, :admin, :effective_learndash) }
|
5
|
+
|
6
|
+
include Effective::CrudController
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Admin
|
2
|
+
class LearndashUsersController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
before_action { EffectiveResources.authorize!(self, :admin, :effective_learndash) }
|
5
|
+
|
6
|
+
include Effective::CrudController
|
7
|
+
|
8
|
+
on :refresh, success: -> { "Successfully refreshed #{resource} and all course enrollments" }
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Admin
|
2
|
+
class EffectiveLearndashCoursesDatatable < Effective::Datatable
|
3
|
+
datatable do
|
4
|
+
order :title
|
5
|
+
|
6
|
+
col :id, visible: false
|
7
|
+
col :course_id, label: 'Learndash Id', visible: false
|
8
|
+
|
9
|
+
col :title
|
10
|
+
col :status
|
11
|
+
|
12
|
+
col :link do |course|
|
13
|
+
link_to(course.link, course.link, target: '_blank')
|
14
|
+
end
|
15
|
+
|
16
|
+
col :learndash_users, visible: false
|
17
|
+
|
18
|
+
actions_col
|
19
|
+
end
|
20
|
+
|
21
|
+
collection do
|
22
|
+
Effective::LearndashCourse.deep.all
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Admin
|
2
|
+
class EffectiveLearndashEnrollmentsDatatable < Effective::Datatable
|
3
|
+
filters do
|
4
|
+
scope :all
|
5
|
+
scope :completed
|
6
|
+
scope :in_progress
|
7
|
+
scope :not_started
|
8
|
+
end
|
9
|
+
|
10
|
+
datatable do
|
11
|
+
col :id, visible: false
|
12
|
+
|
13
|
+
col :last_refreshed, visible: false do |enrollment|
|
14
|
+
time_ago_in_words(enrollment.last_synced_at) + ' ago'
|
15
|
+
end
|
16
|
+
|
17
|
+
col :owner, visible: false
|
18
|
+
|
19
|
+
col :learndash_course
|
20
|
+
col :learndash_user
|
21
|
+
|
22
|
+
col :progress_status
|
23
|
+
|
24
|
+
col :last_step, visible: false
|
25
|
+
col :steps_completed, visible: false
|
26
|
+
col :steps_total, visible: false
|
27
|
+
|
28
|
+
col :date_started, as: :date
|
29
|
+
col :date_completed, as: :date
|
30
|
+
|
31
|
+
actions_col
|
32
|
+
end
|
33
|
+
|
34
|
+
collection do
|
35
|
+
Effective::LearndashEnrollment.deep.all
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Admin
|
2
|
+
class EffectiveLearndashUsersDatatable < Effective::Datatable
|
3
|
+
datatable do
|
4
|
+
col :id, visible: false
|
5
|
+
col :user_id, label: 'Learndash Id', visible: false
|
6
|
+
|
7
|
+
col :last_refreshed, visible: true do |user|
|
8
|
+
time_ago_in_words(user.last_synced_at) + ' ago'
|
9
|
+
end
|
10
|
+
|
11
|
+
col :owner
|
12
|
+
col :email
|
13
|
+
col :username
|
14
|
+
col :password
|
15
|
+
col :learndash_courses
|
16
|
+
|
17
|
+
actions_col
|
18
|
+
end
|
19
|
+
|
20
|
+
collection do
|
21
|
+
Effective::LearndashUser.deep.all
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# EffectiveLearndashOwner
|
2
|
+
#
|
3
|
+
# Mark your user model with effective_learndash_owner to get all the includes
|
4
|
+
|
5
|
+
module EffectiveLearndashOwner
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module Base
|
9
|
+
def effective_learndash_owner
|
10
|
+
include ::EffectiveLearndashOwner
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def effective_learndash_owner?; true; end
|
16
|
+
end
|
17
|
+
|
18
|
+
included do
|
19
|
+
# Effective Scoped - this is a has_one in preactice
|
20
|
+
has_many :learndash_users, class_name: 'Effective::LearndashUser', as: :owner, inverse_of: :owner, dependent: :delete_all
|
21
|
+
accepts_nested_attributes_for :learndash_users, allow_destroy: true
|
22
|
+
|
23
|
+
# Not used
|
24
|
+
has_many :learndash_enrollments, class_name: 'Effective::LearndashEnrollment', as: :owner, inverse_of: :owner, dependent: :delete_all
|
25
|
+
accepts_nested_attributes_for :learndash_enrollments, allow_destroy: true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Find
|
29
|
+
def learndash_user
|
30
|
+
learndash_users.first
|
31
|
+
end
|
32
|
+
|
33
|
+
# Find or create
|
34
|
+
def create_learndash_user
|
35
|
+
learndash_user || learndash_users.create!(owner: self)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Find
|
39
|
+
def learndash_enrollment(course:)
|
40
|
+
learndash_user&.enrollment(course: course)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Find or create
|
44
|
+
def create_learndash_enrollment(course:)
|
45
|
+
raise('expected a persisted learndash_user') unless learndash_user&.persisted?
|
46
|
+
learndash_user.create_enrollment(course: course)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Find or sync and check completed?
|
50
|
+
def learndash_completed?(course:)
|
51
|
+
enrollment = learndash_enrollment(course: course)
|
52
|
+
|
53
|
+
# We haven't been enrolled
|
54
|
+
return false if enrollment.blank?
|
55
|
+
|
56
|
+
# Return completed right away if previously marked completed
|
57
|
+
return true if enrollment.completed?
|
58
|
+
|
59
|
+
# Check the API
|
60
|
+
enrollment.sync!
|
61
|
+
enrollment.completed?
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,269 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class LearndashApi
|
5
|
+
|
6
|
+
attr_accessor :url
|
7
|
+
attr_accessor :username
|
8
|
+
attr_accessor :password
|
9
|
+
|
10
|
+
def initialize(url:, username:, password:)
|
11
|
+
@url = url
|
12
|
+
@username = username
|
13
|
+
@password = password
|
14
|
+
end
|
15
|
+
|
16
|
+
# Methods
|
17
|
+
# https://developer.wordpress.org/rest-api/reference/users/#definition
|
18
|
+
# curl --user username:password http://www.example.com/wp-json/wp/v2/users/me
|
19
|
+
def me
|
20
|
+
get('/wp/v2/users/me')
|
21
|
+
end
|
22
|
+
|
23
|
+
# List users
|
24
|
+
def users
|
25
|
+
get('/wp/v2/users')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a WP Hash of User or nil
|
29
|
+
# This find by EMAIL doesn't work reliably
|
30
|
+
def find_user(value)
|
31
|
+
# Find by email
|
32
|
+
if value.kind_of?(String) && value.include?('@')
|
33
|
+
return find_by("/wp/v2/users", :email, value)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Fetch by saved param value
|
37
|
+
user_id = user_id(value)
|
38
|
+
user = find("/wp/v2/users/#{user_id}", context: :edit) if user_id
|
39
|
+
return user if user.present?
|
40
|
+
|
41
|
+
# Find by email
|
42
|
+
email = value.try(:email)
|
43
|
+
user = find_by("/wp/v2/users", :email, email) if email
|
44
|
+
return user if user.present?
|
45
|
+
|
46
|
+
# Find by username
|
47
|
+
username = username_for(value) if value.class.respond_to?(:effective_learndash_owner?)
|
48
|
+
user = find_by("/wp/v2/users", :username, username) if username
|
49
|
+
return user if user.present?
|
50
|
+
|
51
|
+
# Otherwise none
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create User
|
56
|
+
# Usernames can only contain lowercase letters (a-z) and numbers.
|
57
|
+
def create_user(owner)
|
58
|
+
raise ('expected a leardash owner') unless owner.class.respond_to?(:effective_learndash_owner?)
|
59
|
+
raise('owner must have an email') unless owner.try(:email).present?
|
60
|
+
|
61
|
+
username = username_for(owner)
|
62
|
+
password = password_for(owner)
|
63
|
+
|
64
|
+
payload = {
|
65
|
+
username: username,
|
66
|
+
password: password,
|
67
|
+
|
68
|
+
name: owner.to_s,
|
69
|
+
email: owner.email,
|
70
|
+
roles: ['subscriber'],
|
71
|
+
|
72
|
+
first_name: owner.try(:first_name),
|
73
|
+
last_name: owner.try(:last_name)
|
74
|
+
}.compact
|
75
|
+
|
76
|
+
post("/wp/v2/users", payload.stringify_keys).merge(password: password)
|
77
|
+
end
|
78
|
+
|
79
|
+
# List Courses
|
80
|
+
def courses
|
81
|
+
get('/ldlms/v2/sfwd-courses')
|
82
|
+
end
|
83
|
+
|
84
|
+
# List User Course Progress
|
85
|
+
def user_enrollments(user)
|
86
|
+
user = user_id(user) || raise('expected a user')
|
87
|
+
|
88
|
+
get("/ldlms/v2/users/#{user}/course-progress")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Helper methods for enrollments
|
92
|
+
def find_enrollment(enrollment)
|
93
|
+
find_user_course(enrollment.learndash_user, enrollment.learndash_course)
|
94
|
+
end
|
95
|
+
|
96
|
+
def create_enrollment(enrollment)
|
97
|
+
create_user_course(enrollment.learndash_user, enrollment.learndash_course)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Find User Course Progress
|
101
|
+
def find_user_course(user, course)
|
102
|
+
user = user_id(user) || raise('expected a user')
|
103
|
+
course = course_id(course) || raise('expected a course')
|
104
|
+
|
105
|
+
find("/ldlms/v2/users/#{user}/course-progress/#{course}")
|
106
|
+
end
|
107
|
+
|
108
|
+
# Crete Course User
|
109
|
+
def create_user_course(user, course)
|
110
|
+
user = user_id(user) || raise('expected a user')
|
111
|
+
course = course_id(course) || raise('expected a course')
|
112
|
+
|
113
|
+
response = post("/ldlms/v2/sfwd-courses/#{course}/users", user_ids: [user])
|
114
|
+
|
115
|
+
unless (response.first.fetch(:code) rescue nil) == 'learndash_rest_enroll_success'
|
116
|
+
raise("unsuccessful course creation: #{response}")
|
117
|
+
end
|
118
|
+
|
119
|
+
find_user_course(user, course)
|
120
|
+
end
|
121
|
+
|
122
|
+
# private under this point
|
123
|
+
|
124
|
+
|
125
|
+
def user_id(resource)
|
126
|
+
if resource.class.respond_to?(:effective_learndash_owner?) # This is a user
|
127
|
+
resource.learndash_user&.user_id
|
128
|
+
elsif resource.kind_of?(LearndashEnrollment)
|
129
|
+
resource.learndash_user&.user_id
|
130
|
+
elsif resource.kind_of?(LearndashUser)
|
131
|
+
resource.user_id
|
132
|
+
else
|
133
|
+
resource
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def course_id(resource)
|
138
|
+
if resource.kind_of?(LearndashCourse)
|
139
|
+
resource.course_id
|
140
|
+
elsif resource.kind_of?(LearndashEnrollment)
|
141
|
+
resource.learndash_course&.course_id
|
142
|
+
else
|
143
|
+
resource
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def username_for(resource)
|
148
|
+
raise('expected a learndash owner') unless resource.class.respond_to?(:effective_learndash_owner?) # This is a user
|
149
|
+
|
150
|
+
name = EffectiveLearndash.wp_username_for(resource)
|
151
|
+
name = "test#{name}" unless Rails.env.production?
|
152
|
+
name
|
153
|
+
end
|
154
|
+
|
155
|
+
def password_for(resource)
|
156
|
+
raise('expected a learndash owner') unless resource.class.respond_to?(:effective_learndash_owner?) # This is a user
|
157
|
+
EffectiveLearndash.wp_password_for(resource)
|
158
|
+
end
|
159
|
+
|
160
|
+
def find(endpoint, params = nil)
|
161
|
+
response = get(endpoint, params)
|
162
|
+
|
163
|
+
if response == false
|
164
|
+
nil
|
165
|
+
elsif response.kind_of?(Hash) && response.dig(:data, :status) == 404
|
166
|
+
nil
|
167
|
+
elsif response.kind_of?(Hash)
|
168
|
+
response
|
169
|
+
elsif response.kind_of?(Array)
|
170
|
+
response.first
|
171
|
+
else
|
172
|
+
raise("unexpected Learndash API response #{response}")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# We can't just like, find by email, so we gotta search then filter on our side
|
177
|
+
def find_by(endpoint, key, value)
|
178
|
+
raise('expected a symbol key') unless key.kind_of?(Symbol)
|
179
|
+
raise('expected a value') unless value.present?
|
180
|
+
|
181
|
+
response = get(endpoint, { search: value, context: :edit })
|
182
|
+
|
183
|
+
collection = Array(
|
184
|
+
if response == false
|
185
|
+
nil
|
186
|
+
elsif response.kind_of?(Hash) && response.dig(:data, :status) == 404
|
187
|
+
nil
|
188
|
+
elsif response.kind_of?(Hash)
|
189
|
+
response
|
190
|
+
elsif response.kind_of?(Array)
|
191
|
+
response
|
192
|
+
else
|
193
|
+
raise("unexpected Learndash API find_by response #{response}")
|
194
|
+
end
|
195
|
+
)
|
196
|
+
|
197
|
+
resource = collection.find { |data| data[key] == value }
|
198
|
+
resource
|
199
|
+
end
|
200
|
+
|
201
|
+
def get(endpoint, params = nil)
|
202
|
+
query = ('?' + params.compact.map { |k, v| "#{k}=#{v}" }.join('&')) if params.present?
|
203
|
+
|
204
|
+
uri = URI.parse(api_url + endpoint + query.to_s)
|
205
|
+
|
206
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
207
|
+
http.use_ssl = (uri.scheme == 'https')
|
208
|
+
http.read_timeout = 10
|
209
|
+
|
210
|
+
response = with_retries do
|
211
|
+
puts("[GET] #{uri}") if Rails.env.development?
|
212
|
+
http.get(uri, headers)
|
213
|
+
end
|
214
|
+
|
215
|
+
unless response.code.start_with?('2')
|
216
|
+
puts("Response code: #{response.code} #{response.body}") if Rails.env.development?
|
217
|
+
return false
|
218
|
+
end
|
219
|
+
|
220
|
+
JSON.parse(response.body, symbolize_names: true)
|
221
|
+
end
|
222
|
+
|
223
|
+
def post(endpoint, params = nil)
|
224
|
+
uri = URI.parse(api_url + endpoint)
|
225
|
+
|
226
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
227
|
+
http.use_ssl = (uri.scheme == 'https')
|
228
|
+
http.read_timeout = 10
|
229
|
+
|
230
|
+
response = with_retries do
|
231
|
+
puts("[POST] #{uri} #{params}") if Rails.env.development?
|
232
|
+
http.post(uri.path, (params || {}).to_json, headers)
|
233
|
+
end
|
234
|
+
|
235
|
+
unless response.code.start_with?('2')
|
236
|
+
raise("Invalid Learndash API request: #{response.body}")
|
237
|
+
end
|
238
|
+
|
239
|
+
JSON.parse(response.body, symbolize_names: true)
|
240
|
+
end
|
241
|
+
|
242
|
+
def api_url
|
243
|
+
url.chomp('/') + '/wp-json'
|
244
|
+
end
|
245
|
+
|
246
|
+
def headers
|
247
|
+
{
|
248
|
+
'Authorization': "Basic #{Base64.strict_encode64("#{username}:#{password}")}",
|
249
|
+
'Accept': 'application/json',
|
250
|
+
'Content-Type': 'application/json'
|
251
|
+
}
|
252
|
+
end
|
253
|
+
|
254
|
+
def with_retries(retries: 3, wait: 2, &block)
|
255
|
+
raise('expected a block') unless block_given?
|
256
|
+
|
257
|
+
begin
|
258
|
+
return yield
|
259
|
+
rescue Exception => e
|
260
|
+
if (retries -= 1) > 0
|
261
|
+
sleep(wait); retry
|
262
|
+
else
|
263
|
+
raise
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
end
|