From 877acbad575fbd1210c2e1e0b79fbf8c81407c6c Mon Sep 17 00:00:00 2001 From: Karthik Sankar Date: Thu, 20 Mar 2025 16:38:23 +0800 Subject: [PATCH 1/4] added staging seed.rb --- db/seeds.rb | 2 + db/seeds/staging.rb | 324 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 db/seeds/staging.rb diff --git a/db/seeds.rb b/db/seeds.rb index 9c609917..b497f5e2 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -45,6 +45,8 @@ else puts "Sample heartbeats already exist for the test user" end +elsif Rails.env.staging? + require_relative 'seeds/staging' else puts "Skipping development seed data in #{Rails.env} environment" end diff --git a/db/seeds/staging.rb b/db/seeds/staging.rb new file mode 100644 index 00000000..c427beb8 --- /dev/null +++ b/db/seeds/staging.rb @@ -0,0 +1,324 @@ +if Rails.env.staging? + puts "Seeding staging environment..." + + # Create multiple users with various configurations + puts "Creating users..." + + # Admin user with all features enabled + admin_user = User.find_or_create_by(slack_uid: 'ADMIN123456') do |user| + user.username = 'admin' + user.slack_username = 'admin' + user.slack_avatar_url = 'https://via.placeholder.com/300' + user.is_admin = true + user.uses_slack_status = true + user.timezone = 'America/New_York' + user.hackatime_extension_text_type = :simple_text + end + + # Regular user with GitHub integration + github_user = User.find_or_create_by(slack_uid: 'GITHUB123456') do |user| + user.username = 'github_user' + user.slack_username = 'github_user' + user.github_uid = 'github123' + user.github_username = 'github_user' + user.github_avatar_url = 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png' + user.timezone = 'America/Los_Angeles' + end + + # Regular user without GitHub + regular_user = User.find_or_create_by(slack_uid: 'USER123456') do |user| + user.username = 'regular_user' + user.slack_username = 'regular_user' + user.slack_avatar_url = 'https://via.placeholder.com/300' + user.timezone = 'Europe/London' + end + + # User for testing sailors log + sailors_user = User.find_or_create_by(slack_uid: 'SAILORS123456') do |user| + user.username = 'sailors_user' + user.slack_username = 'sailors_user' + user.timezone = 'Asia/Tokyo' + end + + # Create email addresses for each user + puts "Creating email addresses..." + admin_user.email_addresses.find_or_create_by(email: 'admin@example.com') + github_user.email_addresses.find_or_create_by(email: 'github_user@example.com') + regular_user.email_addresses.find_or_create_by(email: 'regular_user@example.com') + sailors_user.email_addresses.find_or_create_by(email: 'sailors_user@example.com') + + # Create API keys for each user + puts "Creating API keys..." + admin_user.api_keys.find_or_create_by(name: 'Admin API Key') do |key| + key.token = 'admin-api-key-12345' + end + + github_user.api_keys.find_or_create_by(name: 'GitHub User API Key') do |key| + key.token = 'github-api-key-12345' + end + + regular_user.api_keys.find_or_create_by(name: 'Regular User API Key') do |key| + key.token = 'regular-api-key-12345' + end + + sailors_user.api_keys.find_or_create_by(name: 'Sailors User API Key') do |key| + key.token = 'sailors-api-key-12345' + end + + # Create sign-in tokens for testing + puts "Creating sign-in tokens..." + admin_user.sign_in_tokens.find_or_create_by(token: 'admin-token') do |t| + t.expires_at = 1.year.from_now + t.auth_type = :email + end + + github_user.sign_in_tokens.find_or_create_by(token: 'github-token') do |t| + t.expires_at = 1.year.from_now + t.auth_type = :email + end + + regular_user.sign_in_tokens.find_or_create_by(token: 'regular-token') do |t| + t.expires_at = 1.year.from_now + t.auth_type = :email + end + + sailors_user.sign_in_tokens.find_or_create_by(token: 'sailors-token') do |t| + t.expires_at = 1.year.from_now + t.auth_type = :email + end + + # Sample projects, languages, and editors for heartbeats + projects = ['rails-app', 'react-frontend', 'data-analysis', 'mobile-app', 'api-service', 'cli-tool', 'documentation', 'hackatime'] + languages = ['ruby', 'javascript', 'typescript', 'python', 'go', 'rust', 'html', 'css', 'markdown'] + editors = ['vs-code', 'vim', 'emacs', 'atom', 'sublime', 'intellij', 'xcode', 'android-studio'] + operating_systems = ['macos', 'windows', 'linux', 'ubuntu', 'debian', 'fedora', 'arch'] + + # Create heartbeats for each user + puts "Creating heartbeats..." + + users = [admin_user, github_user, regular_user, sailors_user] + + # Helper to create a unique heartbeat using fields_hash + def create_unique_heartbeat(user, attrs) + # Skip if it would be a duplicate + fields_hash = Heartbeat.generate_fields_hash(attrs) + return if Heartbeat.where(fields_hash: fields_hash).exists? + + heartbeat = user.heartbeats.new(attrs) + heartbeat.fields_hash = fields_hash + heartbeat.save! + rescue ActiveRecord::RecordNotUnique + # Skip if there's a race condition + end + + # Transaction to speed up database operations + ActiveRecord::Base.transaction do + users.each do |user| + # Skip if user already has heartbeats + next if user.heartbeats.count > 0 + + puts "Creating heartbeats for #{user.username}..." + + # Create heartbeats for the last 30 days + (0..30).each do |days_ago| + date = Date.current - days_ago.days + + # Pick 2-3 projects for this day + day_projects = projects.sample(rand(2..3)) + + day_projects.each do |project| + language = languages.sample + editor = editors.sample + os = operating_systems.sample + + # Create 4-8 heartbeats throughout the day + (1..24).to_a.sample(rand(4..8)).each do |hour| + time = date.to_time + hour.hours + rand(0..59).minutes + + attrs = { + time: time.to_f, + entity: "#{project}/file_#{rand(1..10)}.#{language.split('-').first}", + project: project, + language: language, + editor: editor, + operating_system: os, + source_type: :direct_entry, + is_write: [true, false].sample, + category: 'coding', + type: 'file', + line_additions: rand(1..50), + line_deletions: rand(0..10), + lineno: rand(1..100), + lines: rand(100..1000), + cursorpos: rand(1..500) + } + + create_unique_heartbeat(user, attrs) + end + end + end + end + end + + # Create project repo mappings for GitHub user + puts "Creating project repo mappings..." + projects.sample(3).each do |project| + github_user.project_repo_mappings.find_or_create_by(project_name: project) do |mapping| + mapping.repo_url = "https://github.com/#{github_user.github_username}/#{project}" + end + end + + # Create project milestones + puts "Creating project milestones..." + users.each do |user| + user_projects = user.heartbeats.pluck(:project).uniq.sample(2) + + user_projects.each do |project| + # Hourly milestone + duration = user.heartbeats.where(project: project).duration_seconds + hours = (duration / 3600.0).floor + + if hours > 0 + user.project_milestones.find_or_create_by( + project_name: project, + milestone_type: :hourly, + milestone_value: hours + ) + end + + # Daily milestone + today_duration = user.heartbeats.where(project: project).today.duration_seconds + + if today_duration > 0 + user.project_milestones.find_or_create_by( + project_name: project, + milestone_type: :daily, + milestone_value: today_duration + ) + end + + # Weekly milestone + week_start = Time.current.beginning_of_week.to_i + week_end = Time.current.end_of_week.to_i + weekly_duration = user.heartbeats.where("time >= ? AND time <= ?", week_start, week_end).duration_seconds + + if weekly_duration > 0 + user.project_milestones.find_or_create_by( + project_name: project, + milestone_type: :weekly, + milestone_value: weekly_duration + ) + end + end + end + + # Add kudos to project milestones + puts "Adding kudos to project milestones..." + + # Get all milestones + milestones = ProjectMilestone.all + + # For each user, give kudos to some milestones that aren't their own + users.each do |user| + other_user_milestones = milestones.where.not(user_id: user.id).sample(2) + + other_user_milestones.each do |milestone| + # Skip if user already gave kudos to this milestone + next if milestone.kudos_from?(user.id) + + ProjectMilestoneKudos.create!( + project_milestone: milestone, + user_id: user.id + ) + rescue ActiveRecord::RecordInvalid + # Skip if there's a validation error + end + end + + # Create leaderboards + puts "Creating leaderboards..." + + # Daily leaderboard for today + daily_leaderboard = Leaderboard.find_or_create_by( + start_date: Date.current, + period_type: :daily + ) do |leaderboard| + leaderboard.finished_generating_at = Time.current + end + + # Weekly leaderboard for this week + weekly_leaderboard = Leaderboard.find_or_create_by( + start_date: Date.current.beginning_of_week, + period_type: :weekly + ) do |leaderboard| + leaderboard.finished_generating_at = Time.current + end + + # Create leaderboard entries + puts "Creating leaderboard entries..." + + users.each do |user| + # Daily leaderboard entry + daily_seconds = user.heartbeats.today.duration_seconds + + if daily_seconds > 0 + LeaderboardEntry.find_or_create_by( + leaderboard: daily_leaderboard, + user: user + ) do |entry| + entry.total_seconds = daily_seconds + end + end + + # Weekly leaderboard entry + week_start = Time.current.beginning_of_week.to_i + week_end = Time.current.end_of_week.to_i + weekly_seconds = user.heartbeats.where("time >= ? AND time <= ?", week_start, week_end).duration_seconds + + if weekly_seconds > 0 + LeaderboardEntry.find_or_create_by( + leaderboard: weekly_leaderboard, + user: user + ) do |entry| + entry.total_seconds = weekly_seconds + end + end + end + + # Create sailors log data + puts "Creating sailors log data..." + + sailors_log = SailorsLog.find_or_create_by(slack_uid: sailors_user.slack_uid) do |log| + projects_summary = {} + sailors_user.heartbeats.group(:project).duration_seconds.each do |project, duration| + projects_summary[project] = duration + end + log.projects_summary = projects_summary + end + + # Create notification preferences + SailorsLogNotificationPreference.find_or_create_by( + slack_uid: sailors_user.slack_uid, + slack_channel_id: 'C12345678' + ) do |pref| + pref.enabled = true + end + + # Create test notifications + sailors_user.heartbeats.pluck(:project).uniq.sample(2).each do |project| + project_duration = sailors_user.heartbeats.where(project: project).duration_seconds + + SailorsLogSlackNotification.find_or_create_by( + slack_uid: sailors_user.slack_uid, + slack_channel_id: 'C12345678', + project_name: project, + project_duration: [project_duration, 3600].max + ) do |notification| + notification.sent = [true, false].sample + end + end + + puts "Staging seed data created successfully!" +else + puts "Skipping staging seed data in #{Rails.env} environment" +end \ No newline at end of file From 823140df584ea040be932b3b10412fb0d6874de9 Mon Sep 17 00:00:00 2001 From: Karthik Sankar Date: Thu, 20 Mar 2025 16:52:41 +0800 Subject: [PATCH 2/4] fixed linting errors and removed milestones --- db/seeds/staging.rb | 185 +++++++++++--------------------------------- 1 file changed, 46 insertions(+), 139 deletions(-) diff --git a/db/seeds/staging.rb b/db/seeds/staging.rb index c427beb8..d5fe8f56 100644 --- a/db/seeds/staging.rb +++ b/db/seeds/staging.rb @@ -3,7 +3,7 @@ # Create multiple users with various configurations puts "Creating users..." - + # Admin user with all features enabled admin_user = User.find_or_create_by(slack_uid: 'ADMIN123456') do |user| user.username = 'admin' @@ -14,7 +14,7 @@ user.timezone = 'America/New_York' user.hackatime_extension_text_type = :simple_text end - + # Regular user with GitHub integration github_user = User.find_or_create_by(slack_uid: 'GITHUB123456') do |user| user.username = 'github_user' @@ -24,7 +24,7 @@ user.github_avatar_url = 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png' user.timezone = 'America/Los_Angeles' end - + # Regular user without GitHub regular_user = User.find_or_create_by(slack_uid: 'USER123456') do |user| user.username = 'regular_user' @@ -32,109 +32,93 @@ user.slack_avatar_url = 'https://via.placeholder.com/300' user.timezone = 'Europe/London' end - - # User for testing sailors log - sailors_user = User.find_or_create_by(slack_uid: 'SAILORS123456') do |user| - user.username = 'sailors_user' - user.slack_username = 'sailors_user' - user.timezone = 'Asia/Tokyo' - end - + # Create email addresses for each user puts "Creating email addresses..." admin_user.email_addresses.find_or_create_by(email: 'admin@example.com') github_user.email_addresses.find_or_create_by(email: 'github_user@example.com') regular_user.email_addresses.find_or_create_by(email: 'regular_user@example.com') - sailors_user.email_addresses.find_or_create_by(email: 'sailors_user@example.com') - + # Create API keys for each user puts "Creating API keys..." admin_user.api_keys.find_or_create_by(name: 'Admin API Key') do |key| key.token = 'admin-api-key-12345' end - + github_user.api_keys.find_or_create_by(name: 'GitHub User API Key') do |key| key.token = 'github-api-key-12345' end - + regular_user.api_keys.find_or_create_by(name: 'Regular User API Key') do |key| key.token = 'regular-api-key-12345' end - - sailors_user.api_keys.find_or_create_by(name: 'Sailors User API Key') do |key| - key.token = 'sailors-api-key-12345' - end - + + # Create sign-in tokens for testing puts "Creating sign-in tokens..." admin_user.sign_in_tokens.find_or_create_by(token: 'admin-token') do |t| t.expires_at = 1.year.from_now t.auth_type = :email end - + github_user.sign_in_tokens.find_or_create_by(token: 'github-token') do |t| t.expires_at = 1.year.from_now t.auth_type = :email end - + regular_user.sign_in_tokens.find_or_create_by(token: 'regular-token') do |t| t.expires_at = 1.year.from_now t.auth_type = :email end - - sailors_user.sign_in_tokens.find_or_create_by(token: 'sailors-token') do |t| - t.expires_at = 1.year.from_now - t.auth_type = :email - end - + # Sample projects, languages, and editors for heartbeats - projects = ['rails-app', 'react-frontend', 'data-analysis', 'mobile-app', 'api-service', 'cli-tool', 'documentation', 'hackatime'] - languages = ['ruby', 'javascript', 'typescript', 'python', 'go', 'rust', 'html', 'css', 'markdown'] - editors = ['vs-code', 'vim', 'emacs', 'atom', 'sublime', 'intellij', 'xcode', 'android-studio'] - operating_systems = ['macos', 'windows', 'linux', 'ubuntu', 'debian', 'fedora', 'arch'] - + projects = [ 'rails-app', 'react-frontend', 'data-analysis', 'mobile-app', 'api-service', 'cli-tool', 'documentation', 'hackatime' ] + languages = [ 'ruby', 'javascript', 'typescript', 'python', 'go', 'rust', 'html', 'css', 'markdown' ] + editors = [ 'vs-code', 'vim', 'emacs', 'atom', 'sublime', 'intellij', 'xcode', 'android-studio' ] + operating_systems = [ 'macos', 'windows', 'linux', 'ubuntu', 'debian', 'fedora', 'arch' ] + # Create heartbeats for each user puts "Creating heartbeats..." - - users = [admin_user, github_user, regular_user, sailors_user] - + + users = [ admin_user, github_user, regular_user ] + # Helper to create a unique heartbeat using fields_hash def create_unique_heartbeat(user, attrs) # Skip if it would be a duplicate fields_hash = Heartbeat.generate_fields_hash(attrs) return if Heartbeat.where(fields_hash: fields_hash).exists? - + heartbeat = user.heartbeats.new(attrs) heartbeat.fields_hash = fields_hash heartbeat.save! rescue ActiveRecord::RecordNotUnique # Skip if there's a race condition end - + # Transaction to speed up database operations ActiveRecord::Base.transaction do users.each do |user| # Skip if user already has heartbeats next if user.heartbeats.count > 0 - + puts "Creating heartbeats for #{user.username}..." - + # Create heartbeats for the last 30 days (0..30).each do |days_ago| date = Date.current - days_ago.days - + # Pick 2-3 projects for this day day_projects = projects.sample(rand(2..3)) - + day_projects.each do |project| language = languages.sample editor = editors.sample os = operating_systems.sample - + # Create 4-8 heartbeats throughout the day (1..24).to_a.sample(rand(4..8)).each do |hour| time = date.to_time + hour.hours + rand(0..59).minutes - + attrs = { time: time.to_f, entity: "#{project}/file_#{rand(1..10)}.#{language.split('-').first}", @@ -143,7 +127,7 @@ def create_unique_heartbeat(user, attrs) editor: editor, operating_system: os, source_type: :direct_entry, - is_write: [true, false].sample, + is_write: [ true, false ].sample, category: 'coding', type: 'file', line_additions: rand(1..50), @@ -152,14 +136,14 @@ def create_unique_heartbeat(user, attrs) lines: rand(100..1000), cursorpos: rand(1..500) } - + create_unique_heartbeat(user, attrs) end end end end end - + # Create project repo mappings for GitHub user puts "Creating project repo mappings..." projects.sample(3).each do |project| @@ -167,65 +151,21 @@ def create_unique_heartbeat(user, attrs) mapping.repo_url = "https://github.com/#{github_user.github_username}/#{project}" end end - - # Create project milestones - puts "Creating project milestones..." - users.each do |user| - user_projects = user.heartbeats.pluck(:project).uniq.sample(2) - - user_projects.each do |project| - # Hourly milestone - duration = user.heartbeats.where(project: project).duration_seconds - hours = (duration / 3600.0).floor - - if hours > 0 - user.project_milestones.find_or_create_by( - project_name: project, - milestone_type: :hourly, - milestone_value: hours - ) - end - - # Daily milestone - today_duration = user.heartbeats.where(project: project).today.duration_seconds - - if today_duration > 0 - user.project_milestones.find_or_create_by( - project_name: project, - milestone_type: :daily, - milestone_value: today_duration - ) - end - - # Weekly milestone - week_start = Time.current.beginning_of_week.to_i - week_end = Time.current.end_of_week.to_i - weekly_duration = user.heartbeats.where("time >= ? AND time <= ?", week_start, week_end).duration_seconds - - if weekly_duration > 0 - user.project_milestones.find_or_create_by( - project_name: project, - milestone_type: :weekly, - milestone_value: weekly_duration - ) - end - end - end - + # Add kudos to project milestones puts "Adding kudos to project milestones..." - + # Get all milestones milestones = ProjectMilestone.all - + # For each user, give kudos to some milestones that aren't their own users.each do |user| other_user_milestones = milestones.where.not(user_id: user.id).sample(2) - + other_user_milestones.each do |milestone| # Skip if user already gave kudos to this milestone next if milestone.kudos_from?(user.id) - + ProjectMilestoneKudos.create!( project_milestone: milestone, user_id: user.id @@ -234,10 +174,10 @@ def create_unique_heartbeat(user, attrs) # Skip if there's a validation error end end - + # Create leaderboards puts "Creating leaderboards..." - + # Daily leaderboard for today daily_leaderboard = Leaderboard.find_or_create_by( start_date: Date.current, @@ -245,7 +185,7 @@ def create_unique_heartbeat(user, attrs) ) do |leaderboard| leaderboard.finished_generating_at = Time.current end - + # Weekly leaderboard for this week weekly_leaderboard = Leaderboard.find_or_create_by( start_date: Date.current.beginning_of_week, @@ -253,14 +193,14 @@ def create_unique_heartbeat(user, attrs) ) do |leaderboard| leaderboard.finished_generating_at = Time.current end - + # Create leaderboard entries puts "Creating leaderboard entries..." - + users.each do |user| # Daily leaderboard entry daily_seconds = user.heartbeats.today.duration_seconds - + if daily_seconds > 0 LeaderboardEntry.find_or_create_by( leaderboard: daily_leaderboard, @@ -269,12 +209,12 @@ def create_unique_heartbeat(user, attrs) entry.total_seconds = daily_seconds end end - + # Weekly leaderboard entry week_start = Time.current.beginning_of_week.to_i week_end = Time.current.end_of_week.to_i weekly_seconds = user.heartbeats.where("time >= ? AND time <= ?", week_start, week_end).duration_seconds - + if weekly_seconds > 0 LeaderboardEntry.find_or_create_by( leaderboard: weekly_leaderboard, @@ -284,41 +224,8 @@ def create_unique_heartbeat(user, attrs) end end end - - # Create sailors log data - puts "Creating sailors log data..." - - sailors_log = SailorsLog.find_or_create_by(slack_uid: sailors_user.slack_uid) do |log| - projects_summary = {} - sailors_user.heartbeats.group(:project).duration_seconds.each do |project, duration| - projects_summary[project] = duration - end - log.projects_summary = projects_summary - end - - # Create notification preferences - SailorsLogNotificationPreference.find_or_create_by( - slack_uid: sailors_user.slack_uid, - slack_channel_id: 'C12345678' - ) do |pref| - pref.enabled = true - end - - # Create test notifications - sailors_user.heartbeats.pluck(:project).uniq.sample(2).each do |project| - project_duration = sailors_user.heartbeats.where(project: project).duration_seconds - - SailorsLogSlackNotification.find_or_create_by( - slack_uid: sailors_user.slack_uid, - slack_channel_id: 'C12345678', - project_name: project, - project_duration: [project_duration, 3600].max - ) do |notification| - notification.sent = [true, false].sample - end - end - + puts "Staging seed data created successfully!" else puts "Skipping staging seed data in #{Rails.env} environment" -end \ No newline at end of file +end From 17aa80104e0f5a6dfeb2c2ec4e66d0342dbb46b9 Mon Sep 17 00:00:00 2001 From: Karthik Sankar Date: Thu, 20 Mar 2025 16:53:23 +0800 Subject: [PATCH 3/4] forgot to remove kudos --- db/seeds/staging.rb | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/db/seeds/staging.rb b/db/seeds/staging.rb index d5fe8f56..99386da2 100644 --- a/db/seeds/staging.rb +++ b/db/seeds/staging.rb @@ -152,29 +152,6 @@ def create_unique_heartbeat(user, attrs) end end - # Add kudos to project milestones - puts "Adding kudos to project milestones..." - - # Get all milestones - milestones = ProjectMilestone.all - - # For each user, give kudos to some milestones that aren't their own - users.each do |user| - other_user_milestones = milestones.where.not(user_id: user.id).sample(2) - - other_user_milestones.each do |milestone| - # Skip if user already gave kudos to this milestone - next if milestone.kudos_from?(user.id) - - ProjectMilestoneKudos.create!( - project_milestone: milestone, - user_id: user.id - ) - rescue ActiveRecord::RecordInvalid - # Skip if there's a validation error - end - end - # Create leaderboards puts "Creating leaderboards..." From eb4b86241b8b3d04a82e8e473c0efc31d741997b Mon Sep 17 00:00:00 2001 From: Max Wofford Date: Thu, 20 Mar 2025 10:51:45 -0400 Subject: [PATCH 4/4] Attempt to pin hostname on db docker compose https://github.com/coollabsio/coolify/issues/3511#issuecomment-2610018266 --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 232f1c21..10f22603 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,6 +27,7 @@ services: - POSTGRES_DB=app_development ports: - "5432:5432" + hostname: db volumes: harbor_postgres_data: