aven 0.0.1 → 0.0.2
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 +4 -4
- data/Rakefile +1 -1
- data/app/components/aven/views/oauth/error/component.html.erb +44 -0
- data/app/components/aven/views/oauth/error/component.rb +30 -0
- data/app/components/aven/views/static/index/component.html.erb +4 -4
- data/app/components/aven/views/static/index/component.rb +11 -0
- data/app/controllers/aven/admin/base.rb +4 -4
- data/app/controllers/aven/application_controller.rb +22 -0
- data/app/controllers/aven/auth_controller.rb +6 -58
- data/app/controllers/aven/oauth/auth0_controller.rb +84 -0
- data/app/controllers/aven/oauth/base_controller.rb +183 -0
- data/app/controllers/aven/oauth/documentation/auth0.md +387 -0
- data/app/controllers/aven/oauth/documentation/entra_id.md +608 -0
- data/app/controllers/aven/oauth/documentation/github.md +329 -0
- data/app/controllers/aven/oauth/documentation/google.md +253 -0
- data/app/controllers/aven/oauth/entra_id_controller.rb +92 -0
- data/app/controllers/aven/oauth/github_controller.rb +91 -0
- data/app/controllers/aven/oauth/google_controller.rb +64 -0
- data/app/controllers/aven/workspaces_controller.rb +20 -0
- data/app/controllers/concerns/aven/authentication.rb +49 -0
- data/app/controllers/concerns/aven/controller_helpers.rb +38 -0
- data/app/helpers/aven/application_helper.rb +2 -6
- data/app/models/aven/app_record.rb +1 -1
- data/app/models/aven/app_record_schema.rb +0 -1
- data/app/models/aven/log.rb +0 -1
- data/app/models/aven/loggable.rb +2 -3
- data/app/models/aven/user.rb +0 -23
- data/app/models/aven/workspace.rb +49 -5
- data/app/models/aven/workspace_role.rb +0 -1
- data/app/models/aven/workspace_user.rb +0 -1
- data/app/models/aven/workspace_user_role.rb +0 -1
- data/config/routes.rb +22 -7
- data/db/migrate/{20251003090752_create_aven_users.rb → 20200101000001_create_aven_users.rb} +1 -1
- data/db/migrate/{20251004182010_create_aven_workspace_users.rb → 20200101000003_create_aven_workspace_users.rb} +1 -1
- data/db/migrate/{20251004182020_create_aven_workspace_roles.rb → 20200101000004_create_aven_workspace_roles.rb} +1 -1
- data/db/migrate/{20251004182030_create_aven_workspace_user_roles.rb → 20200101000005_create_aven_workspace_user_roles.rb} +1 -1
- data/db/migrate/{20251004190000_create_aven_logs.rb → 20200101000006_create_aven_logs.rb} +2 -3
- data/db/migrate/{20251004190100_create_aven_app_record_schemas.rb → 20200101000007_create_aven_app_record_schemas.rb} +0 -1
- data/db/migrate/{20251004190110_create_aven_app_records.rb → 20200101000008_create_aven_app_records.rb} +0 -1
- data/lib/aven/configuration.rb +26 -10
- data/lib/aven/engine.rb +15 -16
- data/lib/aven/model/tenant_model.rb +91 -0
- data/lib/aven/model.rb +6 -0
- data/lib/aven/version.rb +1 -1
- metadata +42 -69
- data/config/initializers/devise.rb +0 -43
- /data/db/migrate/{20251004182000_create_aven_workspaces.rb → 20200101000002_create_aven_workspaces.rb} +0 -0
- /data/lib/tasks/{sqema_tasks.rake → aven_tasks.rake} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Aven
|
|
7
|
+
module Oauth
|
|
8
|
+
class GithubController < BaseController
|
|
9
|
+
AUTHORIZATION_URL = "https://github.com/login/oauth/authorize"
|
|
10
|
+
TOKEN_URL = "https://github.com/login/oauth/access_token"
|
|
11
|
+
USER_INFO_URL = "https://api.github.com/user"
|
|
12
|
+
USER_EMAIL_URL = "https://api.github.com/user/emails"
|
|
13
|
+
DEFAULT_SCOPE = "user:email"
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
|
|
17
|
+
def authorization_url(state)
|
|
18
|
+
params = {
|
|
19
|
+
client_id: oauth_config[:client_id],
|
|
20
|
+
redirect_uri: callback_url,
|
|
21
|
+
scope: oauth_config[:scope] || DEFAULT_SCOPE,
|
|
22
|
+
state:
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
"#{AUTHORIZATION_URL}?#{params.to_query}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def exchange_code_for_token(code)
|
|
29
|
+
params = {
|
|
30
|
+
client_id: oauth_config[:client_id],
|
|
31
|
+
client_secret: oauth_config[:client_secret],
|
|
32
|
+
code:,
|
|
33
|
+
redirect_uri: callback_url
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
headers = { "Accept" => "application/json" }
|
|
37
|
+
oauth_request(URI(TOKEN_URL), params, headers)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def fetch_user_info(access_token)
|
|
41
|
+
# Fetch user profile
|
|
42
|
+
user_data = github_api_request(USER_INFO_URL, access_token)
|
|
43
|
+
|
|
44
|
+
# Fetch primary email if not public
|
|
45
|
+
email = user_data[:email]
|
|
46
|
+
if email.blank?
|
|
47
|
+
emails_data = github_api_request(USER_EMAIL_URL, access_token)
|
|
48
|
+
primary_email = emails_data.find { |e| e[:primary] && e[:verified] }
|
|
49
|
+
email = primary_email[:email] if primary_email
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
id: user_data[:id],
|
|
54
|
+
email:,
|
|
55
|
+
name: user_data[:name] || user_data[:login],
|
|
56
|
+
avatar_url: user_data[:avatar_url],
|
|
57
|
+
login: user_data[:login]
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def callback_url
|
|
64
|
+
aven.oauth_github_callback_url(host: request.host, protocol: request.protocol)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def oauth_config
|
|
68
|
+
@oauth_config ||= Aven.configuration.oauth_providers[:github] || raise("GitHub OAuth not configured")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def github_api_request(url, access_token)
|
|
72
|
+
uri = URI(url)
|
|
73
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
74
|
+
http.use_ssl = true
|
|
75
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
|
|
76
|
+
|
|
77
|
+
request = Net::HTTP::Get.new(uri)
|
|
78
|
+
request["Authorization"] = "Bearer #{access_token}"
|
|
79
|
+
request["Accept"] = "application/vnd.github.v3+json"
|
|
80
|
+
|
|
81
|
+
response = http.request(request)
|
|
82
|
+
|
|
83
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
84
|
+
raise StandardError, "GitHub API request failed: #{response.body}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
JSON.parse(response.body, symbolize_names: true)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Aven
|
|
7
|
+
module Oauth
|
|
8
|
+
class GoogleController < BaseController
|
|
9
|
+
AUTHORIZATION_URL = "https://accounts.google.com/o/oauth2/v2/auth"
|
|
10
|
+
TOKEN_URL = "https://www.googleapis.com/oauth2/v4/token"
|
|
11
|
+
USER_INFO_URL = "https://www.googleapis.com/oauth2/v3/userinfo"
|
|
12
|
+
DEFAULT_SCOPE = "openid email profile"
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def authorization_url(state)
|
|
17
|
+
params = {
|
|
18
|
+
client_id: oauth_config[:client_id],
|
|
19
|
+
redirect_uri: callback_url,
|
|
20
|
+
response_type: "code",
|
|
21
|
+
scope: oauth_config[:scope] || DEFAULT_SCOPE,
|
|
22
|
+
state:,
|
|
23
|
+
access_type: oauth_config[:access_type] || "offline",
|
|
24
|
+
prompt: oauth_config[:prompt] || "select_account"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
"#{AUTHORIZATION_URL}?#{params.to_query}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def exchange_code_for_token(code)
|
|
31
|
+
params = {
|
|
32
|
+
code:,
|
|
33
|
+
client_id: oauth_config[:client_id],
|
|
34
|
+
client_secret: oauth_config[:client_secret],
|
|
35
|
+
redirect_uri: callback_url,
|
|
36
|
+
grant_type: "authorization_code"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
oauth_request(URI(TOKEN_URL), params)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def fetch_user_info(access_token)
|
|
43
|
+
response = oauth_get_request(URI(USER_INFO_URL), access_token)
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
id: response[:sub],
|
|
47
|
+
email: response[:email],
|
|
48
|
+
name: response[:name],
|
|
49
|
+
picture: response[:picture]
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def callback_url
|
|
56
|
+
aven.oauth_google_callback_url(host: request.host, protocol: request.protocol)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def oauth_config
|
|
60
|
+
@oauth_config ||= Aven.configuration.oauth_providers[:google] || raise("Google OAuth not configured")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven
|
|
4
|
+
class WorkspacesController < ApplicationController
|
|
5
|
+
before_action :authenticate_user!
|
|
6
|
+
|
|
7
|
+
# POST /workspaces/:id/switch
|
|
8
|
+
def switch
|
|
9
|
+
workspace = current_user.workspaces.friendly.find(params[:id])
|
|
10
|
+
self.current_workspace = workspace
|
|
11
|
+
redirect_to after_switch_workspace_path, notice: "Switched to #{workspace.label}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def after_switch_workspace_path
|
|
17
|
+
Aven.configuration.resolve_authenticated_root_path || root_path
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven
|
|
4
|
+
module Authentication
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
helper_method :current_user if respond_to?(:helper_method)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
# Returns the currently signed-in user, if any
|
|
13
|
+
def current_user
|
|
14
|
+
@current_user ||= Aven::User.find_by(id: session[:user_id]) if session[:user_id]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Signs in the given user by setting the session
|
|
18
|
+
def sign_in(user)
|
|
19
|
+
reset_session
|
|
20
|
+
session[:user_id] = user.id
|
|
21
|
+
@current_user = user
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Signs out the current user by clearing the session
|
|
25
|
+
def sign_out
|
|
26
|
+
reset_session
|
|
27
|
+
@current_user = nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Stores the current location to redirect back after authentication
|
|
31
|
+
def store_location
|
|
32
|
+
session[:return_to_after_authentication] = request.url if request.get?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns and clears the stored location for redirect after authentication
|
|
36
|
+
# This method accepts a resource parameter for API compatibility with Devise
|
|
37
|
+
def stored_location_for(_resource = nil)
|
|
38
|
+
session.delete(:return_to_after_authentication)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Requires user to be authenticated, redirects to root if not
|
|
42
|
+
def authenticate_user!
|
|
43
|
+
unless current_user
|
|
44
|
+
store_location
|
|
45
|
+
redirect_to main_app.root_path, alert: "You must be signed in to access this page."
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Aven
|
|
2
|
+
module ControllerHelpers
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
helper_method :current_workspace if respond_to?(:helper_method)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Get the current workspace from session
|
|
10
|
+
def current_workspace
|
|
11
|
+
return @current_workspace if defined?(@current_workspace)
|
|
12
|
+
|
|
13
|
+
@current_workspace = if session[:workspace_id].present? && current_user
|
|
14
|
+
current_user.workspaces.find_by(id: session[:workspace_id])
|
|
15
|
+
elsif current_user
|
|
16
|
+
# Auto-select first workspace if none selected
|
|
17
|
+
workspace = current_user.workspaces.first
|
|
18
|
+
session[:workspace_id] = workspace&.id
|
|
19
|
+
workspace
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Set the current workspace
|
|
24
|
+
def current_workspace=(workspace)
|
|
25
|
+
@current_workspace = workspace
|
|
26
|
+
session[:workspace_id] = workspace&.id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Verify user has access to current workspace (similar to Devise's authenticate_user!)
|
|
30
|
+
def verify_workspace!
|
|
31
|
+
return unless current_user.present? && current_workspace.present?
|
|
32
|
+
|
|
33
|
+
unless current_user.workspaces.exists?(id: current_workspace.id)
|
|
34
|
+
render file: Rails.public_path.join("404.html"), status: :not_found, layout: false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -8,13 +8,9 @@ module Aven
|
|
|
8
8
|
].compact, "\n"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def view_component(name, *args,
|
|
11
|
+
def view_component(name, *args, **kwargs, &block)
|
|
12
12
|
component = "Aven::Views::#{name.split("/").map(&:camelize).join("::")}::Component".constantize
|
|
13
|
-
|
|
14
|
-
render(component.new(*args, **kwargs), status:, &block)
|
|
15
|
-
else
|
|
16
|
-
render(component.new(*args, **kwargs), &block)
|
|
17
|
-
end
|
|
13
|
+
render(component.new(*args, **kwargs), &block)
|
|
18
14
|
end
|
|
19
15
|
end
|
|
20
16
|
end
|
|
@@ -53,7 +53,7 @@ module Aven
|
|
|
53
53
|
registry = JSONSkooma.create_registry("2020-12", assert_formats: true)
|
|
54
54
|
schema_with_meta = app_record_schema.schema.dup
|
|
55
55
|
schema_with_meta["$schema"] ||= "https://json-schema.org/draft/2020-12/schema"
|
|
56
|
-
json_schema = JSONSkooma::JSONSchema.new(schema_with_meta, registry:
|
|
56
|
+
json_schema = JSONSkooma::JSONSchema.new(schema_with_meta, registry:)
|
|
57
57
|
result = json_schema.evaluate(data)
|
|
58
58
|
unless result.valid?
|
|
59
59
|
error_output = result.output(:basic)
|
data/app/models/aven/log.rb
CHANGED
data/app/models/aven/loggable.rb
CHANGED
data/app/models/aven/user.rb
CHANGED
|
@@ -22,11 +22,6 @@
|
|
|
22
22
|
#
|
|
23
23
|
module Aven
|
|
24
24
|
class User < ApplicationRecord
|
|
25
|
-
devise(
|
|
26
|
-
:omniauthable,
|
|
27
|
-
omniauth_providers: Aven.configuration.auth.providers.map { |p| p[:provider] }
|
|
28
|
-
)
|
|
29
|
-
|
|
30
25
|
has_many :workspace_users, dependent: :destroy
|
|
31
26
|
has_many :workspaces, through: :workspace_users
|
|
32
27
|
has_many :workspace_user_roles, through: :workspace_users
|
|
@@ -41,23 +36,5 @@ module Aven
|
|
|
41
36
|
validates :remote_id, uniqueness: { scope: :auth_tenant, case_sensitive: false }, allow_blank: true
|
|
42
37
|
|
|
43
38
|
encrypts(:access_token)
|
|
44
|
-
|
|
45
|
-
def self.create_from_omniauth!(request_env, auth_tenant)
|
|
46
|
-
user = request_env.dig("omniauth.auth")
|
|
47
|
-
remote_id = user["uid"]
|
|
48
|
-
email = user.dig("info", "email") || "#{SecureRandom.uuid}@aven.dev"
|
|
49
|
-
|
|
50
|
-
u = where(auth_tenant:, remote_id:).or(
|
|
51
|
-
where(auth_tenant:, email:)
|
|
52
|
-
).first_or_initialize
|
|
53
|
-
|
|
54
|
-
u.auth_tenant = auth_tenant
|
|
55
|
-
u.remote_id = remote_id
|
|
56
|
-
u.email = email
|
|
57
|
-
u.access_token = user.dig("credentials", "token")
|
|
58
|
-
u.save!
|
|
59
|
-
|
|
60
|
-
u
|
|
61
|
-
end
|
|
62
39
|
end
|
|
63
40
|
end
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
#
|
|
17
17
|
module Aven
|
|
18
18
|
class Workspace < ApplicationRecord
|
|
19
|
+
extend FriendlyId
|
|
20
|
+
friendly_id :label, use: :slugged
|
|
21
|
+
|
|
19
22
|
self.table_name = "aven_workspaces"
|
|
20
23
|
|
|
21
24
|
has_many :workspace_users, class_name: "Aven::WorkspaceUser", dependent: :destroy
|
|
@@ -27,13 +30,54 @@ module Aven
|
|
|
27
30
|
validates :label, length: { maximum: 255 }, allow_blank: true
|
|
28
31
|
validates :description, length: { maximum: 1000 }, allow_blank: true
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
# Tenant model registry (inspired by Flipper's group registry pattern)
|
|
34
|
+
class << self
|
|
35
|
+
# Returns array of all registered tenant model classes
|
|
36
|
+
def tenant_models
|
|
37
|
+
@tenant_models ||= []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Register a model class as workspace-scoped
|
|
41
|
+
# Called automatically when a model includes Aven::TenantModel
|
|
42
|
+
def register_tenant_model(model_class)
|
|
43
|
+
return if tenant_models.include?(model_class)
|
|
44
|
+
|
|
45
|
+
tenant_models << model_class
|
|
46
|
+
define_tenant_association(model_class)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Get all registered tenant model class names
|
|
50
|
+
def tenant_model_names
|
|
51
|
+
tenant_models.map(&:name)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# Define association method for a tenant model
|
|
57
|
+
# Creates query method that returns ActiveRecord::Relation
|
|
58
|
+
def define_tenant_association(model_class)
|
|
59
|
+
association_name = model_class.workspace_association_name
|
|
31
60
|
|
|
32
|
-
|
|
61
|
+
# Define instance method for querying tenant records
|
|
62
|
+
define_method(association_name) do
|
|
63
|
+
model_class.where(workspace_id: id)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
33
67
|
|
|
34
|
-
|
|
35
|
-
|
|
68
|
+
# Find a tenant record by type and ID
|
|
69
|
+
def find_tenant_record(model_name, record_id)
|
|
70
|
+
model_class = self.class.tenant_models.find { |m| m.name == model_name }
|
|
71
|
+
return nil unless model_class
|
|
72
|
+
|
|
73
|
+
model_class.where(workspace_id: id).find(record_id)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Destroy all tenant data for this workspace
|
|
77
|
+
def destroy_tenant_data
|
|
78
|
+
self.class.tenant_models.each do |model_class|
|
|
79
|
+
model_class.where(workspace_id: id).destroy_all
|
|
36
80
|
end
|
|
81
|
+
end
|
|
37
82
|
end
|
|
38
83
|
end
|
|
39
|
-
|
data/config/routes.rb
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
Aven::Engine.routes.draw do
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
controllers: { omniauth_callbacks: "aven/auth" }
|
|
5
|
-
)
|
|
2
|
+
# Logout route
|
|
3
|
+
get(:logout, to: "auth#logout", as: :logout)
|
|
6
4
|
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
# OAuth routes
|
|
6
|
+
namespace :oauth do
|
|
7
|
+
# Error page
|
|
8
|
+
get "error", to: "base#error", as: :error
|
|
9
|
+
|
|
10
|
+
# Google OAuth
|
|
11
|
+
get "google", to: "google#create", as: :google
|
|
12
|
+
get "google/callback", to: "google#callback", as: :google_callback
|
|
13
|
+
|
|
14
|
+
# GitHub OAuth
|
|
15
|
+
get "github", to: "github#create", as: :github
|
|
16
|
+
get "github/callback", to: "github#callback", as: :github_callback
|
|
17
|
+
|
|
18
|
+
# Auth0 OAuth
|
|
19
|
+
get "auth0", to: "auth0#create", as: :auth0
|
|
20
|
+
get "auth0/callback", to: "auth0#callback", as: :auth0_callback
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Workspace switching
|
|
24
|
+
post("/workspaces/:id/switch", to: "workspaces#switch", as: :switch_workspace)
|
|
10
25
|
|
|
11
26
|
namespace(:admin) do
|
|
12
27
|
root(to: "dashboard#index")
|
|
@@ -13,7 +13,7 @@ class CreateAvenUsers < ActiveRecord::Migration[8.0]
|
|
|
13
13
|
t.timestamps
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
add_index(:aven_users, [:email, :auth_tenant], unique: true)
|
|
16
|
+
add_index(:aven_users, [ :email, :auth_tenant ], unique: true)
|
|
17
17
|
add_index(:aven_users, :reset_password_token, unique: true)
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -7,6 +7,6 @@ class CreateAvenWorkspaceUsers < ActiveRecord::Migration[8.0]
|
|
|
7
7
|
t.timestamps
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
add_index :aven_workspace_users, [:user_id, :workspace_id], unique: true, name: "idx_aven_workspace_users_on_user_workspace"
|
|
10
|
+
add_index :aven_workspace_users, [ :user_id, :workspace_id ], unique: true, name: "idx_aven_workspace_users_on_user_workspace"
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -8,6 +8,6 @@ class CreateAvenWorkspaceRoles < ActiveRecord::Migration[8.0]
|
|
|
8
8
|
t.timestamps
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
add_index :aven_workspace_roles, [:workspace_id, :label], unique: true, name: "idx_aven_workspace_roles_on_ws_label"
|
|
11
|
+
add_index :aven_workspace_roles, [ :workspace_id, :label ], unique: true, name: "idx_aven_workspace_roles_on_ws_label"
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -7,6 +7,6 @@ class CreateAvenWorkspaceUserRoles < ActiveRecord::Migration[8.0]
|
|
|
7
7
|
t.timestamps
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
add_index :aven_workspace_user_roles, [:workspace_role_id, :workspace_user_id], unique: true, name: "idx_aven_ws_user_roles_on_role_user"
|
|
10
|
+
add_index :aven_workspace_user_roles, [ :workspace_role_id, :workspace_user_id ], unique: true, name: "idx_aven_ws_user_roles_on_role_user"
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -15,8 +15,7 @@ class CreateAvenLogs < ActiveRecord::Migration[8.0]
|
|
|
15
15
|
|
|
16
16
|
add_index :aven_logs, :created_at
|
|
17
17
|
add_index :aven_logs, :level
|
|
18
|
-
add_index :aven_logs, [:loggable_type, :loggable_id], name: "index_aven_logs_on_loggable"
|
|
19
|
-
add_index :aven_logs, [:loggable_type, :loggable_id, :run_id, :state, :created_at], name: "idx_aven_logs_on_loggable_run_state_created_at"
|
|
18
|
+
add_index :aven_logs, [ :loggable_type, :loggable_id ], name: "index_aven_logs_on_loggable"
|
|
19
|
+
add_index :aven_logs, [ :loggable_type, :loggable_id, :run_id, :state, :created_at ], name: "idx_aven_logs_on_loggable_run_state_created_at"
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
|
-
|
data/lib/aven/configuration.rb
CHANGED
|
@@ -1,23 +1,39 @@
|
|
|
1
1
|
module Aven
|
|
2
2
|
class Configuration
|
|
3
|
-
attr_reader :auth
|
|
4
3
|
attr_accessor :authenticated_root_path
|
|
4
|
+
attr_accessor :oauth_providers
|
|
5
5
|
|
|
6
6
|
def initialize
|
|
7
|
-
@auth = Auth.new
|
|
8
7
|
@authenticated_root_path = nil
|
|
8
|
+
@oauth_providers = {}
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
# Configure OAuth providers
|
|
12
|
+
#
|
|
13
|
+
# @param provider [Symbol] The OAuth provider name (:github, :google, etc.)
|
|
14
|
+
# @param credentials [Hash] Configuration hash with:
|
|
15
|
+
# - :client_id [String] OAuth client ID
|
|
16
|
+
# - :client_secret [String] OAuth client secret
|
|
17
|
+
# - :scope [String] Optional. OAuth scopes to request
|
|
18
|
+
# - Any other provider-specific options
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# config.configure_oauth(:github, {
|
|
22
|
+
# client_id: "abc123",
|
|
23
|
+
# client_secret: "secret",
|
|
24
|
+
# scope: "user:email,repo,workflow"
|
|
25
|
+
# })
|
|
26
|
+
def configure_oauth(provider, credentials = {})
|
|
27
|
+
@oauth_providers[provider.to_sym] = credentials
|
|
28
|
+
end
|
|
13
29
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
# Resolves authenticated_root_path, calling it if it's a lambda/proc
|
|
31
|
+
#
|
|
32
|
+
# @return [String] The resolved path
|
|
33
|
+
def resolve_authenticated_root_path
|
|
34
|
+
return nil if @authenticated_root_path.nil?
|
|
17
35
|
|
|
18
|
-
|
|
19
|
-
@providers << { provider: provider, args: args, options: options }
|
|
20
|
-
end
|
|
36
|
+
@authenticated_root_path.respond_to?(:call) ? @authenticated_root_path.call : @authenticated_root_path
|
|
21
37
|
end
|
|
22
38
|
end
|
|
23
39
|
|
data/lib/aven/engine.rb
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
require "devise"
|
|
2
|
-
require "omniauth"
|
|
3
|
-
require "omniauth/rails_csrf_protection"
|
|
4
|
-
require "repost"
|
|
5
1
|
require "importmap-rails"
|
|
6
2
|
require "view_component-contrib"
|
|
7
3
|
require "dry-effects"
|
|
8
4
|
require "tailwind_merge"
|
|
9
5
|
require "json_skooma"
|
|
10
6
|
require "aeros"
|
|
7
|
+
require "friendly_id"
|
|
8
|
+
require "aven/model"
|
|
11
9
|
|
|
12
10
|
module Aven
|
|
13
11
|
class << self
|
|
@@ -20,24 +18,25 @@ module Aven
|
|
|
20
18
|
Aeros::EngineHelpers.setup_assets(self, namespace: Aven)
|
|
21
19
|
Aeros::EngineHelpers.setup_importmap(self, namespace: Aven)
|
|
22
20
|
|
|
23
|
-
#
|
|
24
|
-
initializer
|
|
25
|
-
unless
|
|
21
|
+
# Append engine migrations to the main app
|
|
22
|
+
initializer :append_migrations do |app|
|
|
23
|
+
unless app.root.to_s.include?("test/dummy")
|
|
26
24
|
config.paths["db/migrate"].expanded.each do |expanded_path|
|
|
27
|
-
|
|
25
|
+
app.config.paths["db/migrate"] << expanded_path
|
|
28
26
|
end
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
# Include engine route helpers, authentication, and controller helpers in controllers and views
|
|
31
|
+
initializer "aven.helpers" do
|
|
32
|
+
ActiveSupport.on_load(:action_controller) do
|
|
33
|
+
include Aven::Engine.routes.url_helpers
|
|
34
|
+
include Aven::Authentication
|
|
35
|
+
include Aven::ControllerHelpers
|
|
36
|
+
end
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
providers.each do |provider_config|
|
|
39
|
-
provider provider_config[:provider], *provider_config[:args], **provider_config[:options]
|
|
40
|
-
end
|
|
38
|
+
ActiveSupport.on_load(:action_view) do
|
|
39
|
+
include Aven::Engine.routes.url_helpers
|
|
41
40
|
end
|
|
42
41
|
end
|
|
43
42
|
end
|