Skip to content

Commit

Permalink
Add Curura rankings controller and services (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
lionel-k authored Apr 11, 2024
1 parent ca29489 commit fd5eb75
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 1 deletion.
19 changes: 19 additions & 0 deletions app/controllers/api/v1/curura/games_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module Api
module V1
module Curura
class GamesController < ApplicationController
def create
::Curura::Game.create!(game_params)
end

private

def game_params
params.require(:game).permit(:country, :score, :timezone)
end
end
end
end
end
40 changes: 40 additions & 0 deletions app/controllers/api/v1/curura/rankings_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

module Api
module V1
module Curura
class RankingsController < ApplicationController
def index
set_rankings
set_leaderboards
end

private

def set_rankings
@international_rank, @national_rank =
::Curura::RankingCalculator
.call(games: games, country: country, score: score)
.values_at(:international_rank, :national_rank)
end

def set_leaderboards
@best_players, @players_by_country =
::Curura::Leaderboard.call(games: games).values_at(:best_players, :players_by_country)
end

def games
@games ||= ::Curura::Game.today
end

def country
@country ||= params.require(:country)
end

def score
params.require(:score).to_i
end
end
end
end
end
Empty file removed app/controllers/concerns/.keep
Empty file.
5 changes: 5 additions & 0 deletions app/models/curura.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Curura
def self.table_name_prefix
"curura_"
end
end
7 changes: 7 additions & 0 deletions app/models/curura/game.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Curura::Game < ApplicationRecord
validates :score, :country, :start_time, presence: true

scope :today, -> { where("start_time >= ?", Time.zone.now.beginning_of_day) }
scope :won_above_score, ->(score) { where("score > ?", score) }
scope :country, ->(country) { where(country: country) }
end
31 changes: 31 additions & 0 deletions app/services/curura/leaderboard.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Curura
class Leaderboard
class << self
def call(games:)
@games = games

{ best_players: best_players, players_by_country: players_by_country }
end

private

def best_players
@games
.order(score: :desc)
.limit(10)
.map
.with_index(1) { |game, rank| { rank: rank, score: game.score, country: game.country } }
end

def players_by_country
@games
.group_by(&:country)
.transform_values(&:count)
.sort_by { |country, count| [-count, country] }
.first(10)
.map
.with_index(1) { |(country, count), rank| { rank: rank, country: country, count: count } }
end
end
end
end
30 changes: 30 additions & 0 deletions app/services/curura/ranking_calculator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module Curura
class RankingCalculator
class << self
def call(games:, score:, country:)
@games = games
@score = score
@country = country

{ international_rank: international_rank, national_rank: national_rank }
end

private

def international_rank
return "-" if @games.empty?

position = @games.won_above_score(@score).count.nonzero? || 1
"#{position}/#{@games.size}"
end

def national_rank
games = @games.country(@country)
return "-" if games.empty?
position = @games.country(@country).won_above_score(@score).count.nonzero? || 1

"#{position}/#{games.size}"
end
end
end
end
6 changes: 6 additions & 0 deletions app/views/api/v1/curura/rankings/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

json.national_rank @national_rank
json.international_rank @international_rank
json.best_players @best_players
json.players_by_country @players_by_country
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
resources :missing_words, only: %i[index create]
resources :rankings, only: %i[index]
resources :sms_forwarders, only: %i[create]
namespace :curura do
resources :rankings, only: %i[index]
resources :games, only: %i[create]
end
end
end

Expand Down
11 changes: 11 additions & 0 deletions db/migrate/20240411173830_create_curura_games.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateCururaGames < ActiveRecord::Migration[7.1]
def change
create_table :curura_games do |t|
t.float :score, default: 0.0
t.string :country
t.datetime :start_time

t.timestamps
end
end
end
5 changes: 5 additions & 0 deletions db/migrate/20240411175622_add_timezone_to_curura_games.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddTimezoneToCururaGames < ActiveRecord::Migration[7.1]
def change
add_column :curura_games, :timezone, :string
end
end
11 changes: 10 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2023_05_22_105022) do
ActiveRecord::Schema[7.1].define(version: 2024_04_11_175622) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand All @@ -20,6 +20,15 @@
t.datetime "updated_at", null: false
end

create_table "curura_games", force: :cascade do |t|
t.float "score", default: 0.0
t.string "country"
t.datetime "start_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "timezone"
end

create_table "datasets", force: :cascade do |t|
t.bigint "category_id", null: false
t.string "name"
Expand Down
7 changes: 7 additions & 0 deletions spec/factories/curura/games.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FactoryBot.define do
factory :curura_game, class: "Curura::Game" do
score { 15 }
country { "MyString" }
start_time { "2024-04-11 19:38:30" }
end
end
9 changes: 9 additions & 0 deletions spec/models/curura/game_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require "rails_helper"

RSpec.describe Curura::Game, type: :model do
describe "validations" do
it { is_expected.to validate_presence_of(:score) }
it { is_expected.to validate_presence_of(:country) }
it { is_expected.to validate_presence_of(:start_time) }
end
end

0 comments on commit fd5eb75

Please sign in to comment.