diff --git a/app/models/add_on.rb b/app/models/add_on.rb index 0da2a7df..45e1cbeb 100644 --- a/app/models/add_on.rb +++ b/app/models/add_on.rb @@ -6,7 +6,7 @@ # chart_type :string not null # metadata :jsonb # name :string not null -# status :integer default(0), not null +# status :integer default("installing"), not null # created_at :datetime not null # updated_at :datetime not null # cluster_id :bigint not null diff --git a/app/models/build.rb b/app/models/build.rb index cae9e1f0..290d4075 100644 --- a/app/models/build.rb +++ b/app/models/build.rb @@ -7,7 +7,7 @@ # commit_sha :string not null # git_sha :string # repository_url :string -# status :integer default(0) +# status :integer default("in_progress") # created_at :datetime not null # updated_at :datetime not null # project_id :bigint not null diff --git a/app/models/cluster.rb b/app/models/cluster.rb index 089d8ff0..b44fd603 100644 --- a/app/models/cluster.rb +++ b/app/models/cluster.rb @@ -5,7 +5,7 @@ # id :bigint not null, primary key # kubeconfig :jsonb not null # name :string not null -# status :integer default(0), not null +# status :integer default("initializing"), not null # created_at :datetime not null # updated_at :datetime not null # user_id :bigint not null diff --git a/app/models/connected_provider.rb b/app/models/connected_provider.rb new file mode 100644 index 00000000..8816f1b0 --- /dev/null +++ b/app/models/connected_provider.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: connected_providers +# +# id :bigint not null, primary key +# access_token :string +# access_token_secret :string +# auth :text +# expires_at :datetime +# owner_type :string +# provider :string +# refresh_token :string +# uid :string +# created_at :datetime not null +# updated_at :datetime not null +# owner_id :bigint +# +# Indexes +# +# index_connected_providers_on_owner (owner_type,owner_id) +# +class ConnectedProvider < ApplicationRecord + include Token + include Oauth + + belongs_to :owner, polymorphic: true +end diff --git a/app/models/connected_provider/oauth.rb b/app/models/connected_provider/oauth.rb new file mode 100644 index 00000000..ed72abff --- /dev/null +++ b/app/models/connected_provider/oauth.rb @@ -0,0 +1,37 @@ +module ConnectedProvider::Oauth + extend ActiveSupport::Concern + + included do + serialize :auth, coder: JSON + + encrypts :access_token + encrypts :access_token_secret + + # Scopes for each provider + Devise.omniauth_configs.each do |provider, _| + scope provider, -> { where(provider: provider) } + end + end + + class_methods do + def for_auth(auth) + where(provider: auth.provider, uid: auth.uid).first + end + end + + def provider_name + provider.humanize + end + + def name + auth&.dig("info", "name") + end + + def email + auth&.dig("info", "email") + end + + def image_url + auth&.dig("info", "image") || GravatarHelper.gravatar_url_for(email) + end +end diff --git a/app/models/connected_provider/token.rb b/app/models/connected_provider/token.rb new file mode 100644 index 00000000..3d7e9fc9 --- /dev/null +++ b/app/models/connected_provider/token.rb @@ -0,0 +1,47 @@ +module ConnectedProvider::Token + extend ActiveSupport::Concern + + def token + renew_token! if expired? + access_token + end + + def expired? + expires_at? && expires_at <= 30.minutes.from_now + end + + def renew_token! + new_token = current_token.refresh! + update( + access_token: new_token.token, + refresh_token: new_token.refresh_token, + expires_at: Time.at(new_token.expires_at) + ) + end + + private + + def current_token + OAuth2::AccessToken.new( + strategy.client, + access_token, + refresh_token: + ) + end + + def credentials_for(provider) + { + private_key: ENV["OMNIAUTH_#{provider.to_s.upcase}_PRIVATE_KEY"], + public_key: ENV["OMNIAUTH_#{provider.to_s.upcase}_PUBLIC_KEY"] + }.compact + end + + def strategy + provider_config = credentials_for(provider) + OmniAuth::Strategies.const_get(OmniAuth::Utils.camelize(provider).to_s).new( + nil, + provider_config[:public_key], # client id + provider_config[:private_key] # client secret + ) + end +end diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 17b17d10..e9a16986 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -3,7 +3,7 @@ # Table name: deployments # # id :bigint not null, primary key -# status :integer default(0), not null +# status :integer default("in_progress"), not null # created_at :datetime not null # updated_at :datetime not null # build_id :bigint not null diff --git a/app/models/user.rb b/app/models/user.rb index 27ee239e..0f528d68 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -36,4 +36,18 @@ class User < ApplicationRecord has_many :projects, through: :clusters has_one :docker_hub_credential, dependent: :destroy has_many :add_ons, through: :clusters + has_many :connected_providers, as: :owner, dependent: :destroy + + + def github_username + github_account.auth["info"]["nickname"] + end + + def github_access_token + github_account.access_token + end + + def github_account + @_github_account ||= connected_providers.find_by(provider: "github") + end end diff --git a/db/migrate/20240925222027_create_connected_providers.rb b/db/migrate/20240925222027_create_connected_providers.rb new file mode 100644 index 00000000..357460c9 --- /dev/null +++ b/db/migrate/20240925222027_create_connected_providers.rb @@ -0,0 +1,15 @@ +class CreateConnectedProviders < ActiveRecord::Migration[7.2] + def change + create_table :connected_providers do |t| + t.references :owner, polymorphic: true, index: true + t.string :access_token + t.string :access_token_secret + t.text :auth + t.string :provider + t.string :refresh_token + t.string :uid + t.datetime :expires_at + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 75abfec1..863fdc53 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_09_25_213906) do +ActiveRecord::Schema[7.2].define(version: 2024_09_25_222027) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -85,6 +85,21 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_25_213906) do t.index ["user_id"], name: "index_clusters_on_user_id" end + create_table "connected_providers", force: :cascade do |t| + t.string "owner_type" + t.bigint "owner_id" + t.string "access_token" + t.string "access_token_secret" + t.text "auth" + t.string "provider" + t.string "refresh_token" + t.string "uid" + t.datetime "expires_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["owner_type", "owner_id"], name: "index_connected_providers_on_owner" + end + create_table "cron_schedules", force: :cascade do |t| t.bigint "service_id", null: false t.string "schedule", null: false diff --git a/test/fixtures/add_ons.yml b/test/fixtures/add_ons.yml index 671e6f3e..edb7d294 100644 --- a/test/fixtures/add_ons.yml +++ b/test/fixtures/add_ons.yml @@ -6,7 +6,7 @@ # chart_type :string not null # metadata :jsonb # name :string not null -# status :integer default(0), not null +# status :integer default("installing"), not null # created_at :datetime not null # updated_at :datetime not null # cluster_id :bigint not null diff --git a/test/fixtures/builds.yml b/test/fixtures/builds.yml index e638c0d8..e5ababe1 100644 --- a/test/fixtures/builds.yml +++ b/test/fixtures/builds.yml @@ -7,7 +7,7 @@ # commit_sha :string not null # git_sha :string # repository_url :string -# status :integer default(0) +# status :integer default("in_progress") # created_at :datetime not null # updated_at :datetime not null # project_id :bigint not null diff --git a/test/fixtures/clusters.yml b/test/fixtures/clusters.yml index 1c712a79..7bde2210 100644 --- a/test/fixtures/clusters.yml +++ b/test/fixtures/clusters.yml @@ -5,7 +5,7 @@ # id :bigint not null, primary key # kubeconfig :jsonb not null # name :string not null -# status :integer default(0), not null +# status :integer default("initializing"), not null # created_at :datetime not null # updated_at :datetime not null # user_id :bigint not null diff --git a/test/fixtures/connected_providers.yml b/test/fixtures/connected_providers.yml new file mode 100644 index 00000000..ce81359a --- /dev/null +++ b/test/fixtures/connected_providers.yml @@ -0,0 +1,31 @@ +# == Schema Information +# +# Table name: connected_providers +# +# id :bigint not null, primary key +# access_token :string +# access_token_secret :string +# auth :text +# expires_at :datetime +# owner_type :string +# provider :string +# refresh_token :string +# uid :string +# created_at :datetime not null +# updated_at :datetime not null +# owner_id :bigint +# +# Indexes +# +# index_connected_providers_on_owner (owner_type,owner_id) +# + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/fixtures/deployments.yml b/test/fixtures/deployments.yml index 8184ce7c..cb0156ed 100644 --- a/test/fixtures/deployments.yml +++ b/test/fixtures/deployments.yml @@ -3,7 +3,7 @@ # Table name: deployments # # id :bigint not null, primary key -# status :integer default(0), not null +# status :integer default("in_progress"), not null # created_at :datetime not null # updated_at :datetime not null # build_id :bigint not null diff --git a/test/models/add_on_test.rb b/test/models/add_on_test.rb index b0b4ef47..6d55b99b 100644 --- a/test/models/add_on_test.rb +++ b/test/models/add_on_test.rb @@ -6,7 +6,7 @@ # chart_type :string not null # metadata :jsonb # name :string not null -# status :integer default(0), not null +# status :integer default("installing"), not null # created_at :datetime not null # updated_at :datetime not null # cluster_id :bigint not null diff --git a/test/models/build_test.rb b/test/models/build_test.rb index 464e86c7..9cdae790 100644 --- a/test/models/build_test.rb +++ b/test/models/build_test.rb @@ -7,7 +7,7 @@ # commit_sha :string not null # git_sha :string # repository_url :string -# status :integer default(0) +# status :integer default("in_progress") # created_at :datetime not null # updated_at :datetime not null # project_id :bigint not null diff --git a/test/models/cluster_test.rb b/test/models/cluster_test.rb index a138c64a..51306b95 100644 --- a/test/models/cluster_test.rb +++ b/test/models/cluster_test.rb @@ -5,7 +5,7 @@ # id :bigint not null, primary key # kubeconfig :jsonb not null # name :string not null -# status :integer default(0), not null +# status :integer default("initializing"), not null # created_at :datetime not null # updated_at :datetime not null # user_id :bigint not null diff --git a/test/models/connected_provider_test.rb b/test/models/connected_provider_test.rb new file mode 100644 index 00000000..be70d7c3 --- /dev/null +++ b/test/models/connected_provider_test.rb @@ -0,0 +1,28 @@ +# == Schema Information +# +# Table name: connected_providers +# +# id :bigint not null, primary key +# access_token :string +# access_token_secret :string +# auth :text +# expires_at :datetime +# owner_type :string +# provider :string +# refresh_token :string +# uid :string +# created_at :datetime not null +# updated_at :datetime not null +# owner_id :bigint +# +# Indexes +# +# index_connected_providers_on_owner (owner_type,owner_id) +# +require "test_helper" + +class ConnectedProviderTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/deployment_test.rb b/test/models/deployment_test.rb index 621893ad..47a80a6b 100644 --- a/test/models/deployment_test.rb +++ b/test/models/deployment_test.rb @@ -3,7 +3,7 @@ # Table name: deployments # # id :bigint not null, primary key -# status :integer default(0), not null +# status :integer default("in_progress"), not null # created_at :datetime not null # updated_at :datetime not null # build_id :bigint not null