mirror of
https://github.com/SrIzan10/hc-harbor.git
synced 2026-05-01 10:45:21 +00:00
Add initial ysws program claiming (#178)
This commit is contained in:
73
app/controllers/api/v1/ysws_programs_controller.rb
Normal file
73
app/controllers/api/v1/ysws_programs_controller.rb
Normal file
@@ -0,0 +1,73 @@
|
||||
module Api
|
||||
module V1
|
||||
class YswsProgramsController < ApplicationController
|
||||
before_action :ensure_authenticated!, only: [ :claim ]
|
||||
|
||||
def index
|
||||
render json: Heartbeat.ysws_programs.keys
|
||||
end
|
||||
|
||||
def claim
|
||||
validate_params
|
||||
|
||||
heartbeats = find_heartbeats
|
||||
conflicting_heartbeats = heartbeats.where.not(ysws_program: [ nil, :nothing ])
|
||||
|
||||
if conflicting_heartbeats.any?
|
||||
render json: {
|
||||
error: "Some heartbeats are already claimed",
|
||||
conflicts: conflicting_heartbeats.pluck(:id, :ysws_program)
|
||||
}, status: :conflict
|
||||
return
|
||||
end
|
||||
|
||||
heartbeats.update_all(ysws_program: params[:program_id])
|
||||
|
||||
render json: {
|
||||
message: "Successfully claimed #{heartbeats.count} heartbeats",
|
||||
claimed_count: heartbeats.count
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_authenticated!
|
||||
token = request.headers["Authorization"]&.split(" ")&.last
|
||||
token ||= params[:api_key]
|
||||
|
||||
render json: { error: "Unauthorized" }, status: :unauthorized unless token == ENV["STATS_API_KEY"]
|
||||
end
|
||||
|
||||
def validate_params
|
||||
required_params = [ :start_time, :end_time, :user_id, :program_id ]
|
||||
missing_params = required_params.select { |param| params[param].blank? }
|
||||
|
||||
if missing_params.any?
|
||||
render json: { error: "Missing required parameters: #{missing_params.join(', ')}" }, status: :bad_request
|
||||
end
|
||||
|
||||
unless Heartbeat.ysws_programs.value?(params[:program_id].to_i)
|
||||
render json: { error: "Invalid program_id value" }, status: :bad_request
|
||||
end
|
||||
end
|
||||
|
||||
def find_heartbeats
|
||||
user = User.where(id: params[:user_id]).first
|
||||
user ||= User.where(slack_uid: params[:user_id]).first
|
||||
|
||||
return Heartbeat.none unless user.present?
|
||||
|
||||
scope = Heartbeat.where(
|
||||
user_id: user.id,
|
||||
time: params[:start_time]..params[:end_time]
|
||||
)
|
||||
|
||||
if params[:project].present?
|
||||
scope = scope.where(project: params[:project])
|
||||
end
|
||||
|
||||
scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,6 +12,68 @@ class Heartbeat < ApplicationRecord
|
||||
test_entry: 2
|
||||
}
|
||||
|
||||
enum :ysws_program, {
|
||||
nothing: 0,
|
||||
high_seas: 1,
|
||||
arcade: 2,
|
||||
juice: 3,
|
||||
onboard: 4,
|
||||
sprig: 5,
|
||||
cider: 6,
|
||||
hackpad: 7,
|
||||
boba_drops: 8,
|
||||
the_bin: 9,
|
||||
blot: 10,
|
||||
infill: 11,
|
||||
scrapyard: 12,
|
||||
hackcraft_mod_edition: 13,
|
||||
browser_buddy: 14,
|
||||
hackaccino: 15,
|
||||
cafe: 16,
|
||||
low_skies: 17,
|
||||
rasp_api: 18,
|
||||
terminal_craft: 19,
|
||||
neon: 20,
|
||||
jungle: 21,
|
||||
counterspell: 22,
|
||||
riceathon: 23,
|
||||
power_hour: 24,
|
||||
scrapyard_flagship: 25,
|
||||
ten_days_in_public: 26,
|
||||
build_your_own_llm: 27,
|
||||
cargo_cult_v2: 28,
|
||||
sockathon: 29,
|
||||
bakebuild: 30,
|
||||
minus_twelve: 31,
|
||||
easel: 32,
|
||||
retrospect: 33,
|
||||
cascade: 34,
|
||||
ten_hours_in_public: 35,
|
||||
swirl: 36,
|
||||
tarot: 37,
|
||||
asylum: 38,
|
||||
cargo_cult: 39,
|
||||
rpg: 40,
|
||||
ham_club: 41,
|
||||
anchor: 42,
|
||||
dessert: 43,
|
||||
wizard_orpheus: 44,
|
||||
onboard_live: 45,
|
||||
say_cheese: 46,
|
||||
hackapet: 47,
|
||||
clubs_competitions: 48,
|
||||
printboard: 49,
|
||||
black_box: 50,
|
||||
shipwrecked: 51,
|
||||
pizza_grant_ysws: 52,
|
||||
pixeldust: 53,
|
||||
hacklet: 54,
|
||||
reflow: 55,
|
||||
the_journey: 56,
|
||||
visioneer: 57,
|
||||
neighborhood: 58
|
||||
}, prefix: :claimed_by
|
||||
|
||||
# This is to prevent Rails from trying to use STI even though we have a "type" column
|
||||
self.inheritance_column = nil
|
||||
|
||||
@@ -36,7 +98,7 @@ class Heartbeat < ApplicationRecord
|
||||
end
|
||||
|
||||
def self.unindexed_attributes
|
||||
%w[id created_at updated_at source_type fields_hash]
|
||||
%w[id created_at updated_at source_type fields_hash ysws_program]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -77,16 +77,22 @@ Rails.application.routes.draw do
|
||||
|
||||
# API routes
|
||||
namespace :api do
|
||||
# This is our own API– don't worry about compatibility.
|
||||
namespace :v1 do
|
||||
get "stats", to: "stats#show"
|
||||
get "users/:username/stats", to: "stats#user_stats"
|
||||
|
||||
resources :ysws_programs, only: [ :index ] do
|
||||
post :claim, on: :collection
|
||||
end
|
||||
|
||||
namespace :my do
|
||||
get "heartbeats/most_recent", to: "heartbeats#most_recent"
|
||||
get "heartbeats", to: "heartbeats#index"
|
||||
end
|
||||
end
|
||||
|
||||
# Everything in this namespace conforms to wakatime.com's API.
|
||||
namespace :hackatime do
|
||||
namespace :v1 do
|
||||
get "/", to: "hackatime#index" # many clients seem to link this as the user's dashboard
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddYswsProgramToHeartbeats < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :heartbeats, :ysws_program, :integer, default: 0, null: false
|
||||
end
|
||||
end
|
||||
3
db/schema.rb
generated
3
db/schema.rb
generated
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_03_24_203539) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_04_25_211619) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_catalog.plpgsql"
|
||||
|
||||
@@ -150,6 +150,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_24_203539) do
|
||||
t.text "fields_hash"
|
||||
t.integer "source_type", null: false
|
||||
t.inet "ip_address"
|
||||
t.integer "ysws_program", default: 0, null: false
|
||||
t.index ["category", "time"], name: "index_heartbeats_on_category_and_time"
|
||||
t.index ["fields_hash"], name: "index_heartbeats_on_fields_hash", unique: true
|
||||
t.index ["user_id"], name: "index_heartbeats_on_user_id"
|
||||
|
||||
Reference in New Issue
Block a user