From e59ed8250a3afab5f625c52a7baf8683a62516e3 Mon Sep 17 00:00:00 2001 From: Celina Lopez Date: Wed, 25 Sep 2024 14:18:54 -0700 Subject: [PATCH] jumpstart --- Gemfile | 13 ++ Gemfile.lock | 123 ++++++++++++++++++ app/actions/add_ons/install_helm_chart.rb | 31 +++++ app/actions/add_ons/uninstall_helm_chart.rb | 14 ++ app/actions/clusters/install.rb | 18 +++ app/actions/clusters/install_acme_issuer.rb | 25 ++++ app/actions/clusters/install_metric_server.rb | 20 +++ app/actions/clusters/install_nginx_ingress.rb | 30 +++++ app/actions/clusters/is_ready.rb | 17 +++ .../environment_variables/bulk_update.rb | 19 +++ app/actions/projects/create.rb | 17 +++ app/actions/projects/create_associations.rb | 11 ++ app/actions/projects/deploy_latest_commit.rb | 20 +++ .../projects/register_github_webhook.rb | 24 ++++ app/actions/projects/save.rb | 10 ++ .../projects/validate_github_repository.rb | 14 ++ .../encrypted_rich_texts_controller.rb | 4 + .../action_text/rich_texts_controller.rb | 4 + .../active_storage/attachments_controller.rb | 4 + .../madmin/active_storage/blobs_controller.rb | 8 ++ .../variant_records_controller.rb | 4 + .../madmin/announcements_controller.rb | 4 + .../madmin/application_controller.rb | 22 ++++ .../madmin/noticed/events_controller.rb | 4 + .../noticed/notifications_controller.rb | 4 + app/controllers/madmin/services_controller.rb | 4 + app/controllers/madmin/users_controller.rb | 4 + .../encrypted_rich_text_resource.rb | 26 ++++ .../action_text/rich_text_resource.rb | 26 ++++ .../active_storage/attachment_resource.rb | 24 ++++ .../resources/active_storage/blob_resource.rb | 33 +++++ .../active_storage/variant_record_resource.rb | 24 ++++ app/madmin/resources/announcement_resource.rb | 25 ++++ .../resources/noticed/event_resource.rb | 28 ++++ .../noticed/notification_resource.rb | 28 ++++ app/madmin/resources/service_resource.rb | 27 ++++ app/madmin/resources/user_resource.rb | 57 ++++++++ config/routes.rb | 1 + config/routes/madmin.rb | 28 ++++ db/schema.rb | 122 +++++++++++++++++ 40 files changed, 921 insertions(+) create mode 100644 app/actions/add_ons/install_helm_chart.rb create mode 100644 app/actions/add_ons/uninstall_helm_chart.rb create mode 100644 app/actions/clusters/install.rb create mode 100644 app/actions/clusters/install_acme_issuer.rb create mode 100644 app/actions/clusters/install_metric_server.rb create mode 100644 app/actions/clusters/install_nginx_ingress.rb create mode 100644 app/actions/clusters/is_ready.rb create mode 100644 app/actions/environment_variables/bulk_update.rb create mode 100644 app/actions/projects/create.rb create mode 100644 app/actions/projects/create_associations.rb create mode 100644 app/actions/projects/deploy_latest_commit.rb create mode 100644 app/actions/projects/register_github_webhook.rb create mode 100644 app/actions/projects/save.rb create mode 100644 app/actions/projects/validate_github_repository.rb create mode 100644 app/controllers/madmin/action_text/encrypted_rich_texts_controller.rb create mode 100644 app/controllers/madmin/action_text/rich_texts_controller.rb create mode 100644 app/controllers/madmin/active_storage/attachments_controller.rb create mode 100644 app/controllers/madmin/active_storage/blobs_controller.rb create mode 100644 app/controllers/madmin/active_storage/variant_records_controller.rb create mode 100644 app/controllers/madmin/announcements_controller.rb create mode 100644 app/controllers/madmin/application_controller.rb create mode 100644 app/controllers/madmin/noticed/events_controller.rb create mode 100644 app/controllers/madmin/noticed/notifications_controller.rb create mode 100644 app/controllers/madmin/services_controller.rb create mode 100644 app/controllers/madmin/users_controller.rb create mode 100644 app/madmin/resources/action_text/encrypted_rich_text_resource.rb create mode 100644 app/madmin/resources/action_text/rich_text_resource.rb create mode 100644 app/madmin/resources/active_storage/attachment_resource.rb create mode 100644 app/madmin/resources/active_storage/blob_resource.rb create mode 100644 app/madmin/resources/active_storage/variant_record_resource.rb create mode 100644 app/madmin/resources/announcement_resource.rb create mode 100644 app/madmin/resources/noticed/event_resource.rb create mode 100644 app/madmin/resources/noticed/notification_resource.rb create mode 100644 app/madmin/resources/service_resource.rb create mode 100644 app/madmin/resources/user_resource.rb create mode 100644 config/routes/madmin.rb create mode 100644 db/schema.rb diff --git a/Gemfile b/Gemfile index aa9ad45d..f40fa565 100644 --- a/Gemfile +++ b/Gemfile @@ -71,3 +71,16 @@ gem "sidekiq", "~> 6.2" gem "sitemap_generator", "~> 6.1" gem "whenever", require: false gem "responders", github: "heartcombo/responders", branch: "main" +gem "dotenv", "~> 3.1" +gem "image_processing", "~> 1.13" +gem "k8s-ruby", "~> 0.16.0" +gem "kubeclient", "~> 4.12" +gem "light-service", "~> 0.19.0" +gem "octokit", "~> 9.1" +gem "omniauth-digitalocean", "~> 0.3.2" +gem "redis", "~> 4.8" +gem "pagy", "~> 9.0" +gem "rqrcode", "~> 2.2" +gem "oj", "~> 3.16" +gem "omniauth", "~> 2.1" +gem "omniauth-rails_csrf_protection", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index 42b45cea..6ecf7632 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,6 +109,7 @@ GEM regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) chronic (0.10.2) + chunky_png (1.4.0) concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) @@ -124,21 +125,71 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) + domain_name (0.6.20240107) + dotenv (3.1.4) drb (2.2.1) + dry-configurable (1.2.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.1) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.1.0) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-struct (1.6.0) + dry-core (~> 1.0, < 2) + dry-types (>= 1.7, < 2) + ice_nine (~> 0.11) + zeitwerk (~> 2.6) + dry-types (1.7.2) + bigdecimal (~> 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) erubi (1.13.0) + excon (0.111.0) faraday (2.12.0) faraday-net_http (>= 2.0, < 3.4) json logger faraday-net_http (3.3.0) net-http + ffi (1.17.0-aarch64-linux-gnu) + ffi (1.17.0-arm-linux-gnu) + ffi (1.17.0-arm64-darwin) + ffi (1.17.0-x86-linux-gnu) + ffi (1.17.0-x86_64-darwin) + ffi (1.17.0-x86_64-linux-gnu) + ffi-compiler (1.3.2) + ffi (>= 1.15.5) + rake friendly_id (5.5.1) activerecord (>= 4.0.0) globalid (1.2.1) activesupport (>= 6.1) + hashdiff (1.0.1) hashie (5.0.0) + http (5.2.0) + addressable (~> 2.8) + base64 (~> 0.1) + http-cookie (~> 1.0) + http-form_data (~> 2.2) + llhttp-ffi (~> 0.5.0) + http-accept (1.7.0) + http-cookie (1.0.7) + domain_name (~> 0.5) + http-form_data (2.3.0) i18n (1.14.6) concurrent-ruby (~> 1.0) + ice_nine (0.11.2) + image_processing (1.13.0) + mini_magick (>= 4.9.5, < 5) + ruby-vips (>= 2.0.17, < 3) importmap-rails (2.0.1) actionpack (>= 6.0.0) activesupport (>= 6.0.0) @@ -153,9 +204,30 @@ GEM jsbundling-rails (1.3.1) railties (>= 6.0.0) json (2.7.2) + jsonpath (1.1.5) + multi_json jwt (2.9.1) base64 + k8s-ruby (0.16.0) + dry-configurable + dry-struct + dry-types + excon (~> 0.71) + hashdiff (~> 1.0.0) + jsonpath (~> 1.1) + recursive-open-struct (~> 1.1.3) + yajl-ruby (~> 1.4.0) + yaml-safe_load_stream3 + kubeclient (4.12.0) + http (>= 3.0, < 6.0) + jsonpath (~> 1.0) + recursive-open-struct (~> 1.1, >= 1.1.1) + rest-client (~> 2.0) language_server-protocol (3.17.0.3) + light-service (0.19.0) + llhttp-ffi (0.5.0) + ffi-compiler (~> 1.0) + rake (~> 13.0) logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) @@ -170,9 +242,14 @@ GEM net-smtp marcel (1.0.4) matrix (0.4.2) + mime-types (3.5.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2024.0903) + mini_magick (4.13.2) mini_mime (1.1.5) minitest (5.25.1) msgpack (1.7.2) + multi_json (1.15.0) multi_xml (0.7.1) bigdecimal (~> 3.1) net-http (0.4.1) @@ -186,6 +263,7 @@ GEM timeout net-smtp (0.5.0) net-protocol + netrc (0.11.0) nio4r (2.7.3) nokogiri (1.16.7-aarch64-linux) racc (~> 1.4) @@ -214,10 +292,20 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) + octokit (9.1.0) + faraday (>= 1, < 3) + sawyer (~> 0.9) + oj (3.16.6) + bigdecimal (>= 3.0) + ostruct (>= 0.2) omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection + omniauth-digitalocean (0.3.2) + multi_json (~> 1.15) + omniauth (~> 2.0) + omniauth-oauth2 (~> 1.0) omniauth-facebook (8.0.0) omniauth-oauth2 (~> 1.2) omniauth-github (2.0.1) @@ -230,10 +318,14 @@ GEM omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) omniauth (~> 2.0) + omniauth-rails_csrf_protection (1.0.2) + actionpack (>= 4.2) + omniauth (~> 2.0) omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack orm_adapter (0.5.0) + ostruct (0.6.0) pagy (9.0.9) parallel (1.26.3) parser (3.3.5.0) @@ -294,11 +386,21 @@ GEM rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) + recursive-open-struct (1.1.3) redis (4.8.1) regexp_parser (2.9.2) reline (0.5.10) io-console (~> 0.5) + rest-client (2.1.0) + http-accept (>= 1.7.0, < 2.0) + http-cookie (>= 1.0.2, < 2.0) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) rexml (3.3.7) + rqrcode (2.2.0) + chunky_png (~> 1.0) + rqrcode_core (~> 1.0) + rqrcode_core (1.2.0) rubocop (1.66.1) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -328,7 +430,13 @@ GEM rubocop-performance rubocop-rails ruby-progressbar (1.13.0) + ruby-vips (2.2.2) + ffi (~> 1.12) + logger rubyzip (2.3.2) + sawyer (0.9.2) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) securerandom (0.3.1) selenium-webdriver (4.25.0) base64 (~> 0.2) @@ -382,6 +490,8 @@ GEM chronic (>= 0.6.3) xpath (3.2.0) nokogiri (~> 1.8) + yajl-ruby (1.4.3) + yaml-safe_load_stream3 (0.1.2) zeitwerk (2.6.18) PLATFORMS @@ -399,22 +509,35 @@ DEPENDENCIES cssbundling-rails debug devise (~> 4.9) + dotenv (~> 3.1) friendly_id (~> 5.4) + image_processing (~> 1.13) importmap-rails jbuilder jsbundling-rails + k8s-ruby (~> 0.16.0) + kubeclient (~> 4.12) + light-service (~> 0.19.0) madmin name_of_person! noticed (~> 2.0) + octokit (~> 9.1) + oj (~> 3.16) + omniauth (~> 2.1) + omniauth-digitalocean (~> 0.3.2) omniauth-facebook (~> 8.0) omniauth-github (~> 2.0) + omniauth-rails_csrf_protection (~> 1.0) omniauth-twitter (~> 1.4) + pagy (~> 9.0) pg (~> 1.1) pretender (~> 0.3.4) puma (>= 5.0) pundit (~> 2.1) rails (~> 7.2.1) + redis (~> 4.8) responders! + rqrcode (~> 2.2) rubocop-rails-omakase selenium-webdriver sidekiq (~> 6.2) diff --git a/app/actions/add_ons/install_helm_chart.rb b/app/actions/add_ons/install_helm_chart.rb new file mode 100644 index 00000000..6cbb4358 --- /dev/null +++ b/app/actions/add_ons/install_helm_chart.rb @@ -0,0 +1,31 @@ +class AddOns::InstallHelmChart + extend LightService::Action + expects :add_on + + executed do |context| + add_on = context.add_on + add_on.installing! + charts = YAML.load_file(Rails.root.join('resources', 'helm', 'charts.yml'))['helm']['charts'] + chart = charts.find { |chart| chart['name'] == add_on.chart_type } + # First, check if the chart is already installed & running + + client = K8::Helm::Client.new(add_on.cluster.kubeconfig, Cli::RunAndLog.new(add_on)) + charts = client.ls + unless charts.any? { |chart| chart.name == add_on.name } + charts = client.install(add_on.name, add_on.helm_chart_url, values: get_values(add_on)) + end + add_on.installed! + end + + def self.get_values(add_on) + values = add_on.metadata['template'].keys.each_with_object({}) do |key, values| + template = add_on.metadata['template'][key] + if template.is_a?(Hash) && template['type'] == 'size' + values[key] = "#{template['value']}#{template['unit']}" + else + values[key] = template['value'] + end + end + values + end +end \ No newline at end of file diff --git a/app/actions/add_ons/uninstall_helm_chart.rb b/app/actions/add_ons/uninstall_helm_chart.rb new file mode 100644 index 00000000..d9fcef11 --- /dev/null +++ b/app/actions/add_ons/uninstall_helm_chart.rb @@ -0,0 +1,14 @@ +class AddOns::UninstallHelmChart + extend LightService::Action + expects :add_on + + executed do |context| + add_on = context.add_on + client = K8::Helm::Client.new(add_on.cluster.kubeconfig, Cli::RunAndLog.new(add_on)) + charts = client.ls + if charts.any? { |chart| chart.name == add_on.name } + client.uninstall(add_on.name) + end + add_on.uninstalled! + end +end \ No newline at end of file diff --git a/app/actions/clusters/install.rb b/app/actions/clusters/install.rb new file mode 100644 index 00000000..5cc8c680 --- /dev/null +++ b/app/actions/clusters/install.rb @@ -0,0 +1,18 @@ +class Clusters::Install + extend LightService::Organizer + + def self.call(cluster) + cluster.installing! + result = with(cluster:).reduce( + Clusters::IsReady, + Clusters::InstallNginxIngress, + Clusters::InstallAcmeIssuer, + Clusters::InstallMetricServer, + ) + cluster.running! if result.success? + cluster.failed! if result.failure? + rescue StandardError => e + cluster.failed! + raise e + end +end \ No newline at end of file diff --git a/app/actions/clusters/install_acme_issuer.rb b/app/actions/clusters/install_acme_issuer.rb new file mode 100644 index 00000000..146e69e5 --- /dev/null +++ b/app/actions/clusters/install_acme_issuer.rb @@ -0,0 +1,25 @@ +class Clusters::InstallAcmeIssuer + extend LightService::Action + + expects :cluster + + executed do |context| + cluster = context.cluster + cluster.info("Checking if acme issuer is already installed") + runner = Cli::RunAndLog.new(cluster) + kubectl = K8::Kubectl.new(cluster.kubeconfig, runner) + begin + kubectl.("get clusterissuer letsencryptasdf") + cluster.info("Acme issuer is already installed") + rescue Cli::CommandFailedError => e + cluster.info("Acme issuer not detected, installing...") + ingress_yaml = K8::Shared::AcmeIssuer.new(cluster.user.email).to_yaml + kubectl.apply_yaml(ingress_yaml) + cluster.info("Acme issuer installed") + end + rescue StandardError => e + cluster.failed! + cluster.info("Acme issuer failed to install") + context.fail!("Script failed with exit code #{exit_status.exitstatus}") + end +end \ No newline at end of file diff --git a/app/actions/clusters/install_metric_server.rb b/app/actions/clusters/install_metric_server.rb new file mode 100644 index 00000000..fa734ad7 --- /dev/null +++ b/app/actions/clusters/install_metric_server.rb @@ -0,0 +1,20 @@ +class Clusters::InstallMetricServer + extend LightService::Action + + expects :cluster + + executed do |context| + cluster = context.cluster + runner = Cli::RunAndLog.new(cluster) + kubectl = K8::Kubectl.new(cluster.kubeconfig, runner) + cluster.info("Checking if metric server is already installed...") + + begin + kubectl.("get deployment metrics-server -n kube-system") + cluster.info("Nginx ingress controller is already installed") + rescue Cli::CommandFailedError => e + cluster.info("Metric server not detected, installing...") + kubectl.apply_yaml(Rails.root.join("resources", "k8", "shared", "metrics_server.yaml")) + end + end +end \ No newline at end of file diff --git a/app/actions/clusters/install_nginx_ingress.rb b/app/actions/clusters/install_nginx_ingress.rb new file mode 100644 index 00000000..92692c1d --- /dev/null +++ b/app/actions/clusters/install_nginx_ingress.rb @@ -0,0 +1,30 @@ +class Clusters::InstallNginxIngress + extend LightService::Action + + expects :cluster + + executed do |context| + cluster = context.cluster + runner = Cli::RunAndLog.new(cluster) + kubectl = K8::Kubectl.new(cluster.kubeconfig, runner) + cluster.info("Checking if Nginx ingress controller is already installed...") + + begin + kubectl.("get deployment ingress-nginx-controller") + cluster.info("Nginx ingress controller is already installed") + rescue Cli::CommandFailedError => e + cluster.info("Nginx ingress controller not detected, installing...") + command = "bash #{Rails.root.join("resources", "k8", "scripts", "install_cert_manager.sh")}" + kubectl.with_kube_config do |kubeconfig_file| + begin + runner.(command, envs: { "KUBECONFIG" => kubeconfig_file.path }) + cluster.info("Nginx ingress controller installed successfully") + rescue Cli::CommandFailedError => e + cluster.failed! + cluster.info("Cert manager failed to install") + context.fail!("Script failed with exit code #{exit_status.exitstatus}") + end + end + end + end +end \ No newline at end of file diff --git a/app/actions/clusters/is_ready.rb b/app/actions/clusters/is_ready.rb new file mode 100644 index 00000000..098b8024 --- /dev/null +++ b/app/actions/clusters/is_ready.rb @@ -0,0 +1,17 @@ +class Clusters::IsReady + extend LightService::Action + + expects :cluster + + executed do |context| + cluster = context.cluster + client = K8::Client.new(cluster.kubeconfig) + if client.can_connect? + cluster.installing! + cluster.info("Cluster is ready") + else + cluster.info("Cluster is not ready, retrying in 60 seconds...") + context.fail!("Cluster is not ready") + end + end +end \ No newline at end of file diff --git a/app/actions/environment_variables/bulk_update.rb b/app/actions/environment_variables/bulk_update.rb new file mode 100644 index 00000000..4b716489 --- /dev/null +++ b/app/actions/environment_variables/bulk_update.rb @@ -0,0 +1,19 @@ +class EnvironmentVariables::BulkUpdate + extend LightService::Action + + expects :project, :params + + executed do |context| + project = context.project + # Delete all environment variables and create new ones + + project.environment_variables.destroy_all + + (context.params[:environment_variables] || []).each do |environment_variable_params| + next if environment_variable_params[:name].blank? + name = environment_variable_params[:name].strip.upcase + value = environment_variable_params[:value].strip + project.environment_variables.create!(name:, value:) + end + end +end \ No newline at end of file diff --git a/app/actions/projects/create.rb b/app/actions/projects/create.rb new file mode 100644 index 00000000..27f5df76 --- /dev/null +++ b/app/actions/projects/create.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Projects + class Create + extend LightService::Organizer + + def self.call(project, params) + with(project:, params:).reduce( + Projects::CreateAssociations, + Projects::ValidateGithubRepository, + Projects::Save, + Projects::RegisterGithubWebhook, + Projects::DeployLatestCommit + ) + end + end +end diff --git a/app/actions/projects/create_associations.rb b/app/actions/projects/create_associations.rb new file mode 100644 index 00000000..adfefe86 --- /dev/null +++ b/app/actions/projects/create_associations.rb @@ -0,0 +1,11 @@ +class Projects::CreateAssociations + extend LightService::Action + + expects :project, :params + + executed do |context| + if context.params[:cron_schedule].present? + CronSchedule.create(schedule: context.params[:cron_schedule], project: context.project) + end + end +end \ No newline at end of file diff --git a/app/actions/projects/deploy_latest_commit.rb b/app/actions/projects/deploy_latest_commit.rb new file mode 100644 index 00000000..6381824c --- /dev/null +++ b/app/actions/projects/deploy_latest_commit.rb @@ -0,0 +1,20 @@ +class Projects::DeployLatestCommit + extend LightService::Action + + expects :project + promises :project + + executed do |context| + # Fetch the latest commit from the default branch + project = context.project + client = Octokit::Client.new(access_token: project.user.github_access_token) + commit = client.commits(project.repository_url).first + + build = Build.create!( + project: context.project, + commit_sha: commit.sha, + commit_message: commit.commit[:message] + ) + Projects::BuildJob.perform_later(build) + end +end \ No newline at end of file diff --git a/app/actions/projects/register_github_webhook.rb b/app/actions/projects/register_github_webhook.rb new file mode 100644 index 00000000..8599c6d8 --- /dev/null +++ b/app/actions/projects/register_github_webhook.rb @@ -0,0 +1,24 @@ +class Projects::RegisterGithubWebhook + extend LightService::Action + + expects :project + promises :project + + executed do |context| + client = Octokit::Client.new(access_token: context.project.user.github_access_token) + client.create_hook( + context.project.repository_url, + 'web', + { + url: Rails.application.routes.url_helpers.inbound_webhooks_github_index_url, + content_type: 'json', + secret: ENV.fetch('OMNIAUTH_GITHUB_WEBHOOK_SECRET', + Jumpstart::Omniauth.credentials_for(:github)[:webhook_secret]) + }, + { + events: ['push'], + active: true + } + ) + end +end diff --git a/app/actions/projects/save.rb b/app/actions/projects/save.rb new file mode 100644 index 00000000..9a138127 --- /dev/null +++ b/app/actions/projects/save.rb @@ -0,0 +1,10 @@ +class Projects::Save + extend LightService::Action + + expects :project + promises :project + + executed do |context| + context.project.save! + end +end \ No newline at end of file diff --git a/app/actions/projects/validate_github_repository.rb b/app/actions/projects/validate_github_repository.rb new file mode 100644 index 00000000..74e37215 --- /dev/null +++ b/app/actions/projects/validate_github_repository.rb @@ -0,0 +1,14 @@ +class Projects::ValidateGithubRepository + extend LightService::Action + + expects :project + promises :project + + executed do |context| + client = Octokit::Client.new(access_token: context.project.user.github_access_token) + unless client.repository?(context.project.repository_url) + context.project.errors.add(:repository_url, 'does not exist') + context.fail_and_return!('Repository does not exist') + end + end +end diff --git a/app/controllers/madmin/action_text/encrypted_rich_texts_controller.rb b/app/controllers/madmin/action_text/encrypted_rich_texts_controller.rb new file mode 100644 index 00000000..140fbcbd --- /dev/null +++ b/app/controllers/madmin/action_text/encrypted_rich_texts_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class ActionText::EncryptedRichTextsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/action_text/rich_texts_controller.rb b/app/controllers/madmin/action_text/rich_texts_controller.rb new file mode 100644 index 00000000..2bdf4088 --- /dev/null +++ b/app/controllers/madmin/action_text/rich_texts_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class ActionText::RichTextsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/active_storage/attachments_controller.rb b/app/controllers/madmin/active_storage/attachments_controller.rb new file mode 100644 index 00000000..d950ae62 --- /dev/null +++ b/app/controllers/madmin/active_storage/attachments_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class ActiveStorage::AttachmentsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/active_storage/blobs_controller.rb b/app/controllers/madmin/active_storage/blobs_controller.rb new file mode 100644 index 00000000..fb590182 --- /dev/null +++ b/app/controllers/madmin/active_storage/blobs_controller.rb @@ -0,0 +1,8 @@ +module Madmin + class ActiveStorage::BlobsController < Madmin::ResourceController + def new + super + @record.assign_attributes(filename: "") + end + end +end diff --git a/app/controllers/madmin/active_storage/variant_records_controller.rb b/app/controllers/madmin/active_storage/variant_records_controller.rb new file mode 100644 index 00000000..87986287 --- /dev/null +++ b/app/controllers/madmin/active_storage/variant_records_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class ActiveStorage::VariantRecordsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/announcements_controller.rb b/app/controllers/madmin/announcements_controller.rb new file mode 100644 index 00000000..638beed2 --- /dev/null +++ b/app/controllers/madmin/announcements_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class AnnouncementsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/application_controller.rb b/app/controllers/madmin/application_controller.rb new file mode 100644 index 00000000..eade8ec2 --- /dev/null +++ b/app/controllers/madmin/application_controller.rb @@ -0,0 +1,22 @@ +module Madmin + class ApplicationController < Madmin::BaseController + before_action :authenticate_admin_user + + def authenticate_admin_user + # TODO: Add your authentication logic here + + # For example, we could redirect if the user isn't an admin + # redirect_to "/", alert: "Not authorized." unless user_signed_in? && current_user.admin? + end + + # Authenticate with Clearance + # include Clearance::Controller + # before_action :require_login + + # Authenticate with Devise + # before_action :authenticate_user! + + # Authenticate with Basic Auth + # http_basic_authenticate_with(name: Rails.application.credentials.admin_username, password: Rails.application.credentials.admin_password) + end +end diff --git a/app/controllers/madmin/noticed/events_controller.rb b/app/controllers/madmin/noticed/events_controller.rb new file mode 100644 index 00000000..9ab89bbf --- /dev/null +++ b/app/controllers/madmin/noticed/events_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class Noticed::EventsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/noticed/notifications_controller.rb b/app/controllers/madmin/noticed/notifications_controller.rb new file mode 100644 index 00000000..56d27c4d --- /dev/null +++ b/app/controllers/madmin/noticed/notifications_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class Noticed::NotificationsController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/services_controller.rb b/app/controllers/madmin/services_controller.rb new file mode 100644 index 00000000..dedd659b --- /dev/null +++ b/app/controllers/madmin/services_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class ServicesController < Madmin::ResourceController + end +end diff --git a/app/controllers/madmin/users_controller.rb b/app/controllers/madmin/users_controller.rb new file mode 100644 index 00000000..323ea7e0 --- /dev/null +++ b/app/controllers/madmin/users_controller.rb @@ -0,0 +1,4 @@ +module Madmin + class UsersController < Madmin::ResourceController + end +end diff --git a/app/madmin/resources/action_text/encrypted_rich_text_resource.rb b/app/madmin/resources/action_text/encrypted_rich_text_resource.rb new file mode 100644 index 00000000..aaf53754 --- /dev/null +++ b/app/madmin/resources/action_text/encrypted_rich_text_resource.rb @@ -0,0 +1,26 @@ +class ActionText::EncryptedRichTextResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :name + attribute :body + attribute :created_at, form: false + attribute :updated_at, form: false + attribute :embeds, index: false + + # Associations + attribute :record + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/action_text/rich_text_resource.rb b/app/madmin/resources/action_text/rich_text_resource.rb new file mode 100644 index 00000000..e24c1137 --- /dev/null +++ b/app/madmin/resources/action_text/rich_text_resource.rb @@ -0,0 +1,26 @@ +class ActionText::RichTextResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :name + attribute :body + attribute :created_at, form: false + attribute :updated_at, form: false + attribute :embeds, index: false + + # Associations + attribute :record + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/active_storage/attachment_resource.rb b/app/madmin/resources/active_storage/attachment_resource.rb new file mode 100644 index 00000000..eb3b73ed --- /dev/null +++ b/app/madmin/resources/active_storage/attachment_resource.rb @@ -0,0 +1,24 @@ +class ActiveStorage::AttachmentResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :name + attribute :created_at, form: false + + # Associations + attribute :record + attribute :blob + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/active_storage/blob_resource.rb b/app/madmin/resources/active_storage/blob_resource.rb new file mode 100644 index 00000000..1e6324f1 --- /dev/null +++ b/app/madmin/resources/active_storage/blob_resource.rb @@ -0,0 +1,33 @@ +class ActiveStorage::BlobResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :key + attribute :filename + attribute :content_type + attribute :byte_size + attribute :checksum + attribute :created_at, form: false + attribute :service_name + attribute :analyzed + attribute :identified + attribute :composed + attribute :preview_image, index: false + + # Associations + attribute :attachments + attribute :variant_records + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/active_storage/variant_record_resource.rb b/app/madmin/resources/active_storage/variant_record_resource.rb new file mode 100644 index 00000000..4ed9c3c9 --- /dev/null +++ b/app/madmin/resources/active_storage/variant_record_resource.rb @@ -0,0 +1,24 @@ +class ActiveStorage::VariantRecordResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :variation, index: false, show: false + attribute :variation_confirmation, index: false, show: false + attribute :image, index: false + + # Associations + attribute :blob + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/announcement_resource.rb b/app/madmin/resources/announcement_resource.rb new file mode 100644 index 00000000..3ed068bd --- /dev/null +++ b/app/madmin/resources/announcement_resource.rb @@ -0,0 +1,25 @@ +class AnnouncementResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :kind + attribute :title + attribute :published_at + attribute :created_at, form: false + attribute :updated_at, form: false + + # Associations + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/noticed/event_resource.rb b/app/madmin/resources/noticed/event_resource.rb new file mode 100644 index 00000000..a7c9284a --- /dev/null +++ b/app/madmin/resources/noticed/event_resource.rb @@ -0,0 +1,28 @@ +class Noticed::EventResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :account_id + attribute :type + attribute :params + attribute :created_at, form: false + attribute :updated_at, form: false + attribute :notifications_count, form: false + + # Associations + attribute :record + attribute :notifications + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/noticed/notification_resource.rb b/app/madmin/resources/noticed/notification_resource.rb new file mode 100644 index 00000000..e48f2570 --- /dev/null +++ b/app/madmin/resources/noticed/notification_resource.rb @@ -0,0 +1,28 @@ +class Noticed::NotificationResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :account_id + attribute :type + attribute :read_at + attribute :seen_at + attribute :created_at, form: false + attribute :updated_at, form: false + + # Associations + attribute :event + attribute :recipient + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/service_resource.rb b/app/madmin/resources/service_resource.rb new file mode 100644 index 00000000..59f19015 --- /dev/null +++ b/app/madmin/resources/service_resource.rb @@ -0,0 +1,27 @@ +class ServiceResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :project_id + attribute :service_type + attribute :command + attribute :name + attribute :created_at, form: false + attribute :updated_at, form: false + + # Associations + attribute :user + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/app/madmin/resources/user_resource.rb b/app/madmin/resources/user_resource.rb new file mode 100644 index 00000000..edf58b46 --- /dev/null +++ b/app/madmin/resources/user_resource.rb @@ -0,0 +1,57 @@ +class UserResource < Madmin::Resource + # Attributes + attribute :id, form: false + attribute :email + attribute :encrypted_password + attribute :reset_password_token + attribute :reset_password_sent_at + attribute :remember_created_at + attribute :confirmation_token + attribute :confirmed_at + attribute :confirmation_sent_at + attribute :unconfirmed_email + attribute :first_name + attribute :last_name + attribute :time_zone + attribute :accepted_terms_at + attribute :accepted_privacy_at + attribute :announcements_read_at + attribute :admin + attribute :created_at, form: false + attribute :updated_at, form: false + attribute :invitation_token + attribute :invitation_created_at + attribute :invitation_sent_at + attribute :invitation_accepted_at + attribute :invitation_limit + attribute :invited_by_type + attribute :invited_by_id + attribute :invitations_count, form: false + attribute :preferred_language + attribute :otp_required_for_login + attribute :otp_secret + attribute :last_otp_timestep + attribute :otp_backup_codes + attribute :preferences + attribute :name + attribute :avatar, index: false + + # Associations + attribute :notifications + attribute :notification_mentions + attribute :services + + # Uncomment this to customize the display name of records in the admin area. + # def self.display_name(record) + # record.name + # end + + # Uncomment this to customize the default sort column and direction. + # def self.default_sort_column + # "created_at" + # end + # + # def self.default_sort_direction + # "desc" + # end +end diff --git a/config/routes.rb b/config/routes.rb index 9ef1eddf..bdfffb87 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ require 'sidekiq/web' Rails.application.routes.draw do + draw :madmin get '/privacy', to: 'home#privacy' get '/terms', to: 'home#terms' authenticate :user, lambda { |u| u.admin? } do diff --git a/config/routes/madmin.rb b/config/routes/madmin.rb new file mode 100644 index 00000000..37c454b6 --- /dev/null +++ b/config/routes/madmin.rb @@ -0,0 +1,28 @@ +# Below are the routes for madmin +namespace :madmin do + namespace :action_text do + resources :encrypted_rich_texts + end + namespace :action_text do + resources :rich_texts + end + resources :announcements + resources :services + resources :users + namespace :active_storage do + resources :blobs + end + namespace :active_storage do + resources :attachments + end + namespace :active_storage do + resources :variant_records + end + namespace :noticed do + resources :events + end + namespace :noticed do + resources :notifications + end + root to: "dashboard#show" +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 00000000..4d0e7380 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,122 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.2].define(version: 2024_09_25_205204) do + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "active_storage_attachments", force: :cascade do |t| + t.string "name", null: false + t.string "record_type", null: false + t.bigint "record_id", null: false + t.bigint "blob_id", null: false + t.datetime "created_at", null: false + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + end + + create_table "active_storage_blobs", force: :cascade do |t| + t.string "key", null: false + t.string "filename", null: false + t.string "content_type" + t.text "metadata" + t.string "service_name", null: false + t.bigint "byte_size", null: false + t.string "checksum" + t.datetime "created_at", null: false + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + end + + create_table "active_storage_variant_records", force: :cascade do |t| + t.bigint "blob_id", null: false + t.string "variation_digest", null: false + t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + end + + create_table "announcements", force: :cascade do |t| + t.datetime "published_at" + t.string "announcement_type" + t.string "name" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "friendly_id_slugs", force: :cascade do |t| + t.string "slug", null: false + t.integer "sluggable_id", null: false + t.string "sluggable_type", limit: 50 + t.string "scope" + t.datetime "created_at" + t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true + t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type" + t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id" + end + + create_table "noticed_events", force: :cascade do |t| + t.string "type" + t.string "record_type" + t.bigint "record_id" + t.jsonb "params" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "notifications_count" + t.index ["record_type", "record_id"], name: "index_noticed_events_on_record" + end + + create_table "noticed_notifications", force: :cascade do |t| + t.string "type" + t.bigint "event_id", null: false + t.string "recipient_type", null: false + t.bigint "recipient_id", null: false + t.datetime "read_at", precision: nil + t.datetime "seen_at", precision: nil + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["event_id"], name: "index_noticed_notifications_on_event_id" + t.index ["recipient_type", "recipient_id"], name: "index_noticed_notifications_on_recipient" + end + + create_table "services", force: :cascade do |t| + t.bigint "user_id", null: false + t.string "provider" + t.string "uid" + t.string "access_token" + t.string "access_token_secret" + t.string "refresh_token" + t.datetime "expires_at" + t.text "auth" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["user_id"], name: "index_services_on_user_id" + end + + create_table "users", force: :cascade do |t| + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.string "first_name" + t.string "last_name" + t.datetime "announcements_last_read_at" + t.boolean "admin", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["email"], name: "index_users_on_email", unique: true + t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + end + + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" + add_foreign_key "services", "users" +end