openstax_accounts 9.0.0 → 9.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3fe1e9662df1f455d7506864c26c6143134196a7e191b6606a4644db5e564b2
4
- data.tar.gz: 13778e9ea7baf42944c3fdfe3ccd590e1bcf8100771956dbbc12a2e1295042d9
3
+ metadata.gz: 62551f377f8696bbba00fe09aa6aa6f05e73f19228a53ff80b887ecdd928cbf5
4
+ data.tar.gz: 2c44edd556152ed485164f79c4f22eb7bf6678f3ae9f89549c3e522f33df3b7c
5
5
  SHA512:
6
- metadata.gz: e74e04ebbf93d4703146f94f23d63ec69a9d68fd9437bee355789a36f51ec010857fd5b1805b79bfb6e5880b5eac73cb883d8e51163c6ec28ea599247ae85675
7
- data.tar.gz: 9aa7d1ddfd8c37e9de254403c51469fad5a317406d5eab74001421131deef5b94e3078f3378567e3a141f1ff461cf65d741a5969fe809d3e50b0dcf320799dfa
6
+ metadata.gz: f99971a6f9896957b4cef704c78cc577a91ed54b5569ec887a76f347490a216cb73da401901939a46fdbf965ec1197b99ceb9b7a2a53536e0f01f7a5e6ec66d6
7
+ data.tar.gz: ec791f1e30ca7465f151c7ac2e7900993d43d0c387007f046dd2107fef8fd52f76efe1a28e4425ef913b05eb7765df4319aab24d6df449782ac447bb19a98f6f
@@ -1,8 +1,6 @@
1
1
  module OpenStax
2
2
  module Accounts
3
-
4
3
  class ApplicationController < ::ActionController::Base
5
-
6
4
  include Lev::HandleWith
7
5
 
8
6
  skip_before_action :authenticate_user!, raise: false
@@ -10,8 +8,6 @@ module OpenStax
10
8
  def configuration
11
9
  OpenStax::Accounts.configuration
12
10
  end
13
-
14
11
  end
15
-
16
12
  end
17
13
  end
@@ -3,23 +3,30 @@ module OpenStax
3
3
  module Dev
4
4
  class AccountsController < OpenStax::Accounts::Dev::BaseController
5
5
  # Allow accessing from inside an iframe
6
- before_action :allow_iframe_access, only: [:index, :search]
6
+ before_action :allow_iframe_access, only: :index
7
7
 
8
8
  def index
9
- end
10
-
11
- def search
12
- handle_with(AccountsSearch)
9
+ handle_with AccountsSearch
13
10
  end
14
11
 
15
12
  def create
16
- handle_with(AccountsCreate,
17
- complete: lambda { redirect_to dev_accounts_path })
13
+ handle_with(
14
+ AccountsCreate,
15
+ success: -> do
16
+ username = @handler_result.outputs.account.username
17
+ flash.notice = "Account with username \"#{username}\" created."
18
+ redirect_to dev_accounts_path(search: { query: username })
19
+ end,
20
+ failure: -> do
21
+ flash.alert = @handler_result.errors.first.translate
22
+ redirect_to dev_accounts_path(search: { query: params.dig(:create, :username) })
23
+ end
24
+ )
18
25
  end
19
26
 
20
27
  def become
21
28
  @account = Account.find(params[:id])
22
- sign_in(@account)
29
+ sign_in @account
23
30
  redirect_back key: :accounts_return_to, strategies: [:session]
24
31
  end
25
32
 
@@ -2,11 +2,7 @@ module OpenStax
2
2
  module Accounts
3
3
  module Dev
4
4
  class BaseController < OpenStax::Accounts::ApplicationController
5
-
6
- before_action do
7
- raise SecurityTransgression if Rails.env.production?
8
- end
9
-
5
+ before_action { raise SecurityTransgression if Rails.env.production? }
10
6
  end
11
7
  end
12
8
  end
@@ -1,7 +1,6 @@
1
1
  module OpenStax
2
2
  module Accounts
3
3
  class SessionsController < OpenStax::Accounts::ApplicationController
4
-
5
4
  def new
6
5
  if configuration.is_return_to_url_approved?(params[:return_to])
7
6
  store_url url: params[:return_to], key: :accounts_return_to, strategies: [:session]
@@ -11,8 +10,7 @@ module OpenStax
11
10
  if configuration.enable_stubbing?
12
11
  redirect_to dev_accounts_path
13
12
  else
14
- forwardable_params =
15
- params.permit(*configuration.forwardable_login_param_keys.map(&:to_s)).to_h
13
+ forwardable_params = params.permit(*configuration.forwardable_login_params).to_h
16
14
  redirect_to openstax_login_path(forwardable_params)
17
15
  end
18
16
  end
@@ -40,14 +38,13 @@ module OpenStax
40
38
  end
41
39
 
42
40
  def failure
43
- redirect_back key: :accounts_return_to, alert: "Authentication failed, please try again."
41
+ redirect_back key: :accounts_return_to, alert: 'Authentication failed, please try again.'
44
42
  end
45
43
 
46
44
  def profile
47
45
  # TODO: stub profile if stubbing is enabled
48
- redirect_to URI.join(configuration.openstax_accounts_url, "/profile").to_s
46
+ redirect_to URI.join(configuration.openstax_accounts_url, '/profile').to_s
49
47
  end
50
-
51
48
  end
52
49
  end
53
50
  end
@@ -1,7 +1,6 @@
1
1
  module OpenStax
2
2
  module Accounts
3
3
  class AccountsSearch
4
-
5
4
  lev_handler
6
5
 
7
6
  paramify :search do
@@ -50,17 +49,16 @@ module OpenStax
50
49
  page: search_params.page,
51
50
  per_page: search_params.per_page}
52
51
  out = run(OpenStax::Accounts::SearchAccounts, params).outputs
53
- outputs[:total_count] = out[:total_count]
52
+ outputs.total_count = out.total_count
54
53
 
55
- if !@max_items.nil? && outputs[:total_count] > @max_items
54
+ if !@max_items.nil? && outputs.total_count > @max_items
56
55
  fatal_error(code: :too_many_items,
57
56
  message: "The number of matches exceeded the allowed limit of #{
58
57
  @max_items} matches. Please refine your query and try again.")
59
58
  end
60
59
 
61
- outputs[:items] = out[:items].to_a
60
+ outputs.items = out.items.to_a
62
61
  end
63
-
64
62
  end
65
63
  end
66
64
  end
@@ -1,21 +1,17 @@
1
1
  module OpenStax
2
2
  module Accounts
3
-
4
3
  module Dev
5
4
  class AccountsCreate
6
-
7
5
  lev_handler
8
6
 
9
7
  paramify :create do
10
8
  attribute :username, type: String
11
- validates :username, presence: true
12
9
  attribute :role, type: String
13
10
  end
14
11
 
15
12
  uses_routine OpenStax::Accounts::Dev::CreateAccount,
16
13
  as: :create_account,
17
- translations: { inputs: { scope: :create },
18
- outputs: { type: :verbatim } }
14
+ translations: { inputs: { scope: :create }, outputs: { type: :verbatim } }
19
15
 
20
16
  protected
21
17
 
@@ -26,9 +22,7 @@ module OpenStax
26
22
  def handle
27
23
  run(:create_account, create_params.as_hash(:username, :role))
28
24
  end
29
-
30
25
  end
31
26
  end
32
-
33
27
  end
34
28
  end
@@ -2,7 +2,6 @@ module OpenStax
2
2
  module Accounts
3
3
  module Dev
4
4
  class AccountsSearch < OpenStax::Accounts::AccountsSearch
5
-
6
5
  paramify :search do
7
6
  attribute :type, type: String
8
7
  attribute :query, type: String
@@ -21,7 +20,6 @@ module OpenStax
21
20
  def authorized?
22
21
  !Rails.env.production?
23
22
  end
24
-
25
23
  end
26
24
  end
27
25
  end
@@ -14,12 +14,18 @@ module OpenStax::Accounts
14
14
  :school_type,
15
15
  :salesforce_contact_id,
16
16
  :support_identifier,
17
- :is_test
17
+ :is_test,
18
+ :is_kip
18
19
  ]
19
20
 
20
21
  attr_accessor :syncing
21
22
 
22
- enum faculty_status: [:no_faculty_info, :pending_faculty, :confirmed_faculty, :rejected_faculty]
23
+ enum faculty_status: [
24
+ :no_faculty_info,
25
+ :pending_faculty,
26
+ :confirmed_faculty,
27
+ :rejected_faculty
28
+ ]
23
29
  enum role: [
24
30
  :unknown_role,
25
31
  :student,
@@ -31,7 +37,13 @@ module OpenStax::Accounts
31
37
  :adjunct,
32
38
  :homeschool
33
39
  ]
34
- enum school_type: [:unknown_school_type, :other_school_type, :college]
40
+ enum school_type: [
41
+ :unknown_school_type,
42
+ :other_school_type,
43
+ :college,
44
+ :high_school,
45
+ :k12_school
46
+ ]
35
47
 
36
48
  validates :faculty_status, :role, :school_type, presence: true
37
49
 
@@ -5,7 +5,6 @@ module OpenStax
5
5
  module Api
6
6
  module V1
7
7
  class AccountRepresenter < Roar::Decorator
8
-
9
8
  # This representer is used to communicate with Accounts
10
9
  # and so must allow read/write on all properties
11
10
  # Do not use it in create/update APIs!
@@ -89,21 +88,26 @@ module OpenStax
89
88
  property :uuid,
90
89
  type: String,
91
90
  schema_info: {
92
- description: "The UUID as set by Accounts"
91
+ description: 'The UUID as set by Accounts'
93
92
  }
94
93
 
95
94
  property :support_identifier,
96
95
  type: String,
97
96
  schema_info: {
98
- description: "The support_identifier as set by Accounts"
97
+ description: 'The support_identifier as set by Accounts'
99
98
  }
100
99
 
101
100
  property :is_test,
102
101
  type: :boolean,
103
102
  schema_info: {
104
- description: "Whether or not this is a test account"
103
+ description: 'Whether or not this is a test account'
105
104
  }
106
105
 
106
+ property :is_kip,
107
+ type: :boolean,
108
+ schema_info: {
109
+ description: 'Whether or not this is a Key Institutional Partner account'
110
+ }
107
111
  end
108
112
  end
109
113
  end
@@ -1,5 +1,4 @@
1
- # Routine for creating an account, only for use when stubbing and
2
- # not on production.
1
+ # Routine for creating an account, only for use when stubbing and not on production.
3
2
 
4
3
  module OpenStax
5
4
  module Accounts
@@ -11,30 +10,33 @@ module OpenStax
11
10
 
12
11
  def exec(inputs={})
13
12
  fatal_error(code: :cannot_create_account_in_production) if Rails.env.production?
14
- fatal_error(code: :can_only_create_account_when_stubbing) if !OpenStax::Accounts.configuration.enable_stubbing?
13
+ fatal_error(code: :can_only_create_account_when_stubbing) \
14
+ unless OpenStax::Accounts.configuration.enable_stubbing?
15
15
 
16
16
  username = inputs[:username]
17
- while username.nil? || Account.where(username: username).exists? do
18
- username = SecureRandom.hex(3).to_s
17
+ if username.blank?
18
+ while username.blank? || Account.where(username: username).exists? do
19
+ username = SecureRandom.hex(3).to_s
20
+ end
21
+ else
22
+ fatal_error(
23
+ code: :account_already_exists,
24
+ message: "One or more accounts with username \"#{username}\" already exist."
25
+ ) if Account.where(username: username).exists?
19
26
  end
20
27
 
21
- account = OpenStax::Accounts::Account.new
22
-
23
- account.openstax_uid = -SecureRandom.hex(4).to_i(16)/2
24
- account.access_token = SecureRandom.hex.to_s
25
- account.username = username
26
- account.role = inputs[:role] || :unknown_role
27
- account.uuid = SecureRandom.uuid
28
- account.support_identifier = "cs_#{SecureRandom.hex(4)}"
29
- account.is_test = true
30
-
31
- account.save
32
-
33
- transfer_errors_from(account, {type: :verbatim}, true)
34
-
35
- outputs[:account] = account
28
+ outputs.account = OpenStax::Accounts::Account.create(
29
+ openstax_uid: -SecureRandom.hex(4).to_i(16)/2,
30
+ access_token: SecureRandom.hex.to_s,
31
+ username: username,
32
+ role: inputs[:role] || :unknown_role,
33
+ uuid: SecureRandom.uuid,
34
+ support_identifier: "cs_#{SecureRandom.hex(4)}",
35
+ is_test: true
36
+ )
37
+
38
+ transfer_errors_from(outputs.account, {type: :verbatim}, true)
36
39
  end
37
-
38
40
  end
39
41
  end
40
42
  end
@@ -15,12 +15,11 @@ module OpenStax
15
15
 
16
16
  if OpenStax::Accounts.configuration.enable_stubbing
17
17
  # We can only stub finding by username b/c accounts-rails doesn't persist emails
18
- openstax_uid = Account.find_by(username: username)&.openstax_uid ||
19
- -SecureRandom.hex(4).to_i(16)/2
20
- uuid = SecureRandom.uuid
18
+ uuid = Account.find_by(username: username)&.uuid || SecureRandom.uuid
19
+ openstax_uid = -SecureRandom.hex(4).to_i(16)/2
21
20
  support_identifier = "cs_#{SecureRandom.hex(4)}"
22
21
  else
23
- response = Api.find_or_create_account(
22
+ response = OpenStax::Accounts::Api.find_or_create_account(
24
23
  email: email, username: username, password: password,
25
24
  first_name: first_name, last_name: last_name, full_name: full_name,
26
25
  salesforce_contact_id: salesforce_contact_id, faculty_status: faculty_status,
@@ -35,12 +34,8 @@ module OpenStax
35
34
  support_identifier = struct.support_identifier
36
35
  end
37
36
 
38
- account = Account.find_or_initialize_by(uuid: uuid)
39
-
40
- unless account.persisted?
41
- while username.nil? || Account.where(username: username).exists? do
42
- username = SecureRandom.hex(3).to_s
43
- end
37
+ outputs.account = Account.find_or_create_by(uuid: uuid) do |account|
38
+ account.openstax_uid = openstax_uid
44
39
  account.username = username
45
40
  account.first_name = first_name
46
41
  account.last_name = last_name
@@ -50,14 +45,11 @@ module OpenStax
50
45
  account.faculty_status = faculty_status || :no_faculty_info
51
46
  account.role = role || :unknown_role
52
47
  account.school_type = school_type || :unknown_school_type
53
- account.openstax_uid = openstax_uid
54
48
  account.support_identifier = support_identifier
55
49
  account.is_test = is_test
56
- account.save!
57
50
  end
58
51
 
59
- transfer_errors_from(account, {type: :verbatim}, true)
60
- outputs.account = account
52
+ transfer_errors_from outputs.account, { type: :verbatim }, true
61
53
  end
62
54
  end
63
55
  end
@@ -10,7 +10,6 @@ module OpenStax
10
10
  protected
11
11
 
12
12
  def exec(options={})
13
-
14
13
  return if OpenStax::Accounts.configuration.enable_stubbing?
15
14
 
16
15
  response = OpenStax::Accounts::Api.get_application_account_updates
@@ -2,8 +2,8 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Accounts</title>
5
- <%= stylesheet_link_tag "openstax/accounts/application", :media => "all" %>
6
- <%= javascript_include_tag "openstax/accounts/application" %>
5
+ <%= stylesheet_link_tag 'openstax/accounts/application', media: 'all' %>
6
+ <%= javascript_include_tag 'openstax/accounts/application' %>
7
7
  <%= csrf_meta_tags %>
8
8
  </head>
9
9
  <body>
@@ -1,5 +1,5 @@
1
- <% total_count = @handler_result.outputs[:total_count]
2
- accounts = @handler_result.outputs[:items] %>
1
+ <% total_count = @handler_result.outputs.total_count
2
+ accounts = @handler_result.outputs.items || [] %>
3
3
 
4
4
  <div id='search-results-count'>
5
5
  <%= pluralize(total_count, 'user') %> found.
@@ -9,14 +9,13 @@
9
9
  <%= osu.action_list(
10
10
  records: accounts,
11
11
  list: {
12
- headings: ['UID', 'Username (click to sign in as)', 'Name'],
13
- widths: ['20%', '40%', '40%'],
12
+ headings: ['UID', 'UUID', 'Username (click to sign in as)', 'Name'],
13
+ widths: ['20%', '20%', '30%', '30%'],
14
14
  data_procs: [
15
15
  ->(account) { account.openstax_uid },
16
+ ->(account) { account.uuid },
16
17
  ->(account) {
17
- link_to account.username, become_dev_account_path(
18
- account.openstax_uid
19
- ), method: :post
18
+ link_to account.username, become_dev_account_path(account.id), method: :post
20
19
  },
21
20
  ->(account) { account.name || '---' }
22
21
  ]
@@ -1,5 +1,4 @@
1
1
  <div class="openstax-accounts development-login">
2
-
3
2
  <%= render partial: 'openstax/accounts/shared/attention' %>
4
3
 
5
4
  <h3>Create an Account</h3>
@@ -11,7 +10,7 @@
11
10
 
12
11
 
13
12
  <div class="form-group">
14
- <%= f.text_field :username, placeholder: "Username" %>&nbsp;
13
+ <%= f.text_field :username, placeholder: 'Username' %>&nbsp;
15
14
  <%= f.select :role, OpenStax::Accounts::Account.roles.keys.map{|rr| [rr, rr]} %>&nbsp;
16
15
  <%= f.submit 'Create', class: 'btn btn-primary' %>
17
16
  </div>
@@ -23,15 +22,13 @@
23
22
  <p>You need to login, but we're not connected to the Accounts server.<br>
24
23
  Search for a user below and click the sign in link next to him or her.</p>
25
24
 
26
- <%= render :partial => 'openstax/accounts/shared/accounts/search',
27
- :locals => {
28
- :search_action_path => openstax_accounts.search_dev_accounts_path,
29
- :remote => true,
30
- :method => :get
25
+ <%= render partial: 'openstax/accounts/shared/accounts/search',
26
+ locals: {
27
+ search_action_path: openstax_accounts.dev_accounts_path,
28
+ search_results_partial: 'openstax/accounts/dev/accounts/search_results',
29
+ remote: true,
30
+ method: :get
31
31
  } %>
32
32
 
33
33
  <br>
34
-
35
- <div id="search-results"></div>
36
-
37
34
  </div>
@@ -1,3 +1,11 @@
1
1
  <% handler_errors.each do |error| %>
2
- <%= error.translate %>
2
+ <div class="error"><%= error.translate %></div>
3
+ <% end %>
4
+
5
+ <% if flash.alert %>
6
+ <div class="alert"><%= flash.alert %></div>
7
+ <% end %>
8
+
9
+ <% if flash.notice %>
10
+ <div class="notice"><%= flash.notice %></div>
3
11
  <% end %>
@@ -1,12 +1,11 @@
1
1
  <%
2
- # Clients of this partial can override the following variables:
3
- search_action_path ||= nil
4
- method ||= :get
5
- remote ||= false
6
- form_html ||= {id: 'search-form',
7
- class: 'form-inline'}
8
- search_types ||= ['Any', 'Username', 'Name',
9
- 'First Name', 'Last Name', 'Email']
2
+ # Clients of this partial can override the following variables:
3
+ search_action_path ||= nil
4
+ search_results_partial ||= nil
5
+ method ||= :get
6
+ remote ||= false
7
+ form_html ||= {id: 'search-form', class: 'form-inline'}
8
+ search_types ||= ['Any', 'Username', 'Name', 'First Name', 'Last Name', 'Email']
10
9
  %>
11
10
 
12
11
  <%= lev_form_for :search,
@@ -26,6 +25,11 @@
26
25
 
27
26
  <% end %>
28
27
 
28
+ <div id="search-results">
29
+ <% unless search_results_partial.blank? %>
30
+ <%= render partial: search_results_partial %>
31
+ <% end %>
32
+ </div>
29
33
 
30
34
  <script>
31
35
  var input = $('input[name="search[query]"]');
data/config/routes.rb CHANGED
@@ -4,14 +4,13 @@ OpenStax::Accounts::Engine.routes.draw do
4
4
 
5
5
  # Shortcut to OmniAuth route that redirects to the Accounts server
6
6
  # This is provided by OmniAuth and is not in the SessionsController
7
- get '/auth/openstax', as: 'openstax_login'
7
+ get '/auth/openstax', to: ->(env) { [ 404, {}, [ '' ] ] }, as: 'openstax_login'
8
8
 
9
9
  if OpenStax::Accounts.configuration.enable_stubbing?
10
10
  # User profile route
11
11
  namespace :dev do
12
12
  resources :accounts, only: [:index, :create] do
13
13
  post 'become', on: :member
14
- get 'search', on: :collection
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,5 @@
1
+ class AddIsKipToOpenStaxAccountsAccounts < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :openstax_accounts_accounts, :is_kip, :boolean
4
+ end
5
+ end
@@ -60,9 +60,9 @@ module OpenStax
60
60
  # to the default Accounts logout URL.
61
61
  attr_writer :logout_redirect_url
62
62
 
63
- # forwardable_login_param_keys
63
+ # forwardable_login_params
64
64
  # Which params are forwarded on the accounts login path
65
- attr_accessor :forwardable_login_param_keys
65
+ attr_accessor :forwardable_login_params
66
66
 
67
67
  # max_user_updates_per_request
68
68
  # When the user profile sync operation is called, this parameter will limit
@@ -119,10 +119,10 @@ module OpenStax
119
119
  @max_search_items = 10
120
120
  @logout_redirect_url = nil
121
121
  @return_to_url_approver = nil
122
- @forwardable_login_param_keys = [
122
+ @forwardable_login_params = [
123
123
  :signup_at,
124
124
  :go,
125
- :sp # "signed payload"; "sp" for short to keep nested parameter names short
125
+ sp: {} # "signed payload"; "sp" to keep nested parameter names short.
126
126
  ]
127
127
  @max_user_updates_per_request = 250
128
128
  @sso_cookie_name = 'ox'
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Accounts
3
- VERSION = "9.0.0"
3
+ VERSION = '9.2.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstax_accounts
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.0.0
4
+ version: 9.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-22 00:00:00.000000000 Z
11
+ date: 2020-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "<"
17
+ - - ">"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "<"
24
+ - - ">"
25
25
  - !ruby/object:Gem::Version
26
- version: '6.0'
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: omniauth
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -330,7 +330,7 @@ files:
330
330
  - app/views/layouts/openstax/accounts/application.html.erb
331
331
  - app/views/openstax/accounts/dev/accounts/_search_results.html.erb
332
332
  - app/views/openstax/accounts/dev/accounts/index.html.erb
333
- - app/views/openstax/accounts/dev/accounts/search.js.erb
333
+ - app/views/openstax/accounts/dev/accounts/index.js.erb
334
334
  - app/views/openstax/accounts/shared/_attention.html.erb
335
335
  - app/views/openstax/accounts/shared/accounts/_search.html.erb
336
336
  - config/routes.rb
@@ -341,6 +341,7 @@ files:
341
341
  - db/migrate/13_add_school_type_to_accounts_accounts.rb
342
342
  - db/migrate/14_drop_openstax_uid_and_username_uniqueness.rb
343
343
  - db/migrate/15_drop_accounts_groups.rb
344
+ - db/migrate/16_add_is_kip_to_openstax_accounts_accounts.rb
344
345
  - db/migrate/1_create_openstax_accounts_groups.rb
345
346
  - db/migrate/2_create_openstax_accounts_group_members.rb
346
347
  - db/migrate/3_create_openstax_accounts_group_owners.rb