Skip to content

Commit

Permalink
create rankings table
Browse files Browse the repository at this point in the history
create seperate index for filters

implement backend loading and filters

remove segment

fix stylings in filters

fix gender and region not being filtered

added show filters

implement by regions table

add i18n to resultsfilter

Create can_user_access? for ticket (thewca#10570)

* Create can_user_access? for ticket

* Review changes

Update sv translation.

Check competition dates for upcoming comps while banning (thewca#10573)

Edit Person Requests page in WRT panel (thewca#10451)

* Edit Person Requests page in WRT panel

* Review changes

---------

Co-authored-by: Daniel M James <[email protected]>

Remove @@character_set_server latin1 check (thewca#10584)

* Remove @@character_set_server latin1 check

* change check for utf8mb4

Switch flag to disable Comp Overview React on demand (thewca#10577)

* Switch flag to disable Comp Overview React on demand

* Fix tests

Bump @cubing/icons from 1.1.3 to 2.0.2

Bumps [@cubing/icons](https://github.com/cubing/icons) from 1.1.3 to 2.0.2.
- [Release notes](https://github.com/cubing/icons/releases)
- [Commits](cubing/icons@v1.1.3...v2.0.2)

---
updated-dependencies:
- dependency-name: "@cubing/icons"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>

Only disable qualification button if qualifications are enforced (thewca#10598)

* only disable qualification button if qualifications are enforced

* removed logs

Date Range locale fixes (thewca#10599)

* export time_will_tell i18n

* translate date_range function from time will tell

* use dateRange function in my competitions and competition overview

* make luxon use the I18n locale in the i18n string

* just use luxon Interval

* fix rubocop

Update pt translation.

Added name argument to validators for ticket validations (thewca#10572)

* Added name argument to validators for ticket validations

* Review changes

Bump @stripe/stripe-js from 5.4.0 to 5.5.0

Bumps [@stripe/stripe-js](https://github.com/stripe/stripe-js) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/stripe/stripe-js/releases)
- [Commits](stripe/stripe-js@v5.4.0...v5.5.0)

---
updated-dependencies:
- dependency-name: "@stripe/stripe-js"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

Bump stylelint from 16.12.0 to 16.13.0

Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.12.0 to 16.13.0.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](stylelint/stylelint@16.12.0...16.13.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

Bump glob from 11.0.0 to 11.0.1

Bumps [glob](https://github.com/isaacs/node-glob) from 11.0.0 to 11.0.1.
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](isaacs/node-glob@v11.0.0...v11.0.1)

---
updated-dependencies:
- dependency-name: glob
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Bump eslint-plugin-react from 7.37.3 to 7.37.4

Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.3 to 7.37.4.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](jsx-eslint/eslint-plugin-react@v7.37.3...v7.37.4)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Bump aws-sdk-rds from 1.264.0 to 1.265.0

Bumps [aws-sdk-rds](https://github.com/aws/aws-sdk-ruby) from 1.264.0 to 1.265.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-rds/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-rds
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

Fix typo (thewca#10606)

Remove side effect from const & simplify/rename (thewca#10597)

Move WFC panel to default panel (thewca#10583)

Fix Person trying to serialize non-existing methods in User (thewca#10575)

* Fix Person trying to serialize non-existing methods in User

* Stringify keys upon merge

* Allow serializing teams through Person (grrr)

* Refactor serialization defaults to respect tests

Circumvent cache in WIC->Ethics sync (thewca#10588)

Bump @tanstack/react-query from 5.62.15 to 5.64.0

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.62.15 to 5.64.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Commits](https://github.com/TanStack/query/commits/v5.64.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

Bump rubocop from 1.69.2 to 1.70.0 (thewca#10608)

Replace redirect with panel-page (thewca#10585)

Migrate mysql to 8.4 in Docker compose (thewca#10548)

* update docker compose for mysql8.4

* remove deprecated command

Let dropdowns expand beyond Modal body in EditEvents (thewca#10544)

* Let dropdowns expand beyond Modal body in EditEvents

* Let each individual modal choose whether they want scrolling

Hotfix: Allow mysql_native plugin locally as grace period

Run yarn dedupe after dependency updates

fix competitions_by_id serialization

don't include organizers or delegates in competition serialization

fix indentation

fix country being imported in routes

Update app/webpacker/components/Results/resultsFilter.jsx

Co-authored-by: Kevin Matthews <[email protected]>

mobile changes

Update app/webpacker/components/Results/Rankings/RankingsTable.jsx

Co-authored-by: Kevin Matthews <[email protected]>

change useMemo to try and fix by region rendering

force Table Body to rerender when changing show modes

use reduce instead of map

use a reducer instead of state

add title prop

parse initial State from the URL
  • Loading branch information
FinnIckler committed Jan 13, 2025
1 parent 617c64e commit ec2be7b
Show file tree
Hide file tree
Showing 58 changed files with 1,079 additions and 428 deletions.
14 changes: 7 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -148,19 +148,19 @@ GEM
autoprefixer-rails (9.4.7)
execjs
aws-eventstream (1.3.0)
aws-partitions (1.1031.0)
aws-partitions (1.1035.0)
aws-sdk-cloudfront (1.108.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sigv4 (~> 1.5)
aws-sdk-core (3.214.1)
aws-sdk-core (3.215.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.96.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sigv4 (~> 1.5)
aws-sdk-rds (1.264.0)
aws-sdk-rds (1.265.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.177.0)
Expand All @@ -170,7 +170,7 @@ GEM
aws-sdk-sqs (1.90.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.10.1)
aws-sigv4 (1.11.0)
aws-eventstream (~> 1, >= 1.0.2)
babel-source (5.8.35)
babel-transpiler (0.7.0)
Expand Down Expand Up @@ -407,7 +407,7 @@ GEM
jmespath (1.6.2)
js_cookie_rails (2.2.0)
railties (>= 3.1)
json (2.9.0)
json (2.9.1)
json-schema (5.1.1)
addressable (~> 2.8)
bigdecimal (~> 3.1)
Expand Down Expand Up @@ -604,7 +604,7 @@ GEM
redis-client (>= 0.22.0)
redis-client (0.23.0)
connection_pool
regexp_parser (2.9.3)
regexp_parser (2.10.0)
reline (0.6.0)
io-console (~> 0.5)
representable (3.2.0)
Expand Down Expand Up @@ -650,7 +650,7 @@ GEM
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.13.1)
rubocop (1.69.2)
rubocop (1.70.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v0/competitions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def competition_index

competitions = competitions_scope.search(params[:q], params: params)

serial_methods = ["short_display_name", "city", "country_iso2", "event_ids", "date_range", "latitude_degrees", "longitude_degrees"]
serial_methods = ["short_display_name", "city", "country_iso2", "event_ids", "latitude_degrees", "longitude_degrees"]
serial_includes = {}

serial_includes["delegates"] = { only: ["id", "name"], methods: [], include: ["avatar"] } if admin_mode
Expand Down
7 changes: 5 additions & 2 deletions app/controllers/api/v0/user_roles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,13 @@ def create
user = User.find(user_id)
ban_reason = params[:banReason]
scope = params[:scope]
upcoming_comps_for_user = user.competitions_registered_for.not_over.merge(Registration.not_cancelled).pluck(:id)
upcoming_comps_for_user = user.competitions_registered_for.not_over.merge(Registration.not_cancelled)
if end_date.present?
upcoming_comps_for_user = upcoming_comps_for_user.between_dates(Date.today, end_date)
end
unless upcoming_comps_for_user.empty?
return render status: :unprocessable_entity, json: {
error: "The user has upcoming competitions: #{upcoming_comps_for_user.join(', ')}. Before banning the user, make sure their registrations are deleted.",
error: "The user has upcoming competitions: #{upcoming_comps_for_user.pluck(:id).join(', ')}. Before banning the user, make sure their registrations are deleted.",
}
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/competitions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def index
@competitions = @competitions.select { |competition| competition.pending_results_or_report(days) }
end

@enable_react = params[:legacy]&.to_s == 'off'
@disable_react = params[:legacy]&.to_s == 'on'

respond_to do |format|
format.html {}
Expand Down
9 changes: 4 additions & 5 deletions app/controllers/panel_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ class PanelController < ApplicationController

before_action :authenticate_user!
before_action -> { redirect_to_root_unless_user(:has_permission?, 'can_access_panels', params[:panel_id].to_sym) }, only: [:index]
before_action -> { redirect_to_root_unless_user(:has_permission?, 'can_access_panels', :wfc) }, only: [:wfc]
before_action -> { redirect_to_root_unless_user(:has_permission?, 'can_access_panels', :staff) }, only: [:staff]
before_action -> { redirect_to_root_unless_user(:has_permission?, 'can_access_panels', :admin) }, only: [:generate_db_token]
before_action -> { redirect_to_root_unless_user(:can_access_senior_delegate_panel?) }, only: [:pending_claims_for_subordinate_delegates]
Expand Down Expand Up @@ -51,11 +50,11 @@ def generate_db_token
}
end

def redirect
@panel_page = params.require(:panel_page)
panel_with_panel_page = current_user.panels_with_access&.find { |panel| User.panel_list[panel][:pages].include?(@panel_page) }
def panel_page
panel_page_id = params.require(:id)
panel_with_panel_page = current_user.panels_with_access&.find { |panel| User.panel_list[panel][:pages].include?(panel_page_id) }

return head :unauthorized if panel_with_panel_page.nil?
redirect_to panel_index_path(panel_id: panel_with_panel_page, anchor: @panel_page)
redirect_to panel_index_path(panel_id: panel_with_panel_page, anchor: panel_page_id)
end
end
61 changes: 60 additions & 1 deletion app/controllers/results_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,27 @@ def rankings

else
flash[:danger] = t(".unknown_show")
redirect_to rankings_path
return redirect_to rankings_path
end

@ranking_timestamp = ComputeAuxiliaryData.successful_start_date || Date.current

respond_to do |format|
format.html {}
format.json do
cached_data = Rails.cache.fetch ["results-page-api", *@cache_params, @ranking_timestamp] do
rows = DbHelper.execute_cached_query(@cache_params, @ranking_timestamp, @query)
comp_ids = rows.map { |r| r["competitionId"] }.uniq
if @is_by_region
rows = compute_rankings_by_region(rows, @continent, @country)
end
competitions_by_id = Competition.where(id: comp_ids).index_by(&:id).transform_values { |comp| comp.as_json(methods: %w[country], include: [], only: %w[cellName id]) }
{
rows: rows.as_json, competitionsById: competitions_by_id
}
end
render json: cached_data
end
end
end

Expand Down Expand Up @@ -356,4 +376,43 @@ def records
params[:show] = nil
end
end

private def compute_rankings_by_region(rows, continent, country)
if rows.empty?
return [[], 0, 0]
end
best_value_of_world = rows.first["value"]
best_values_of_continents = {}
best_values_of_countries = {}
world_rows = []
continents_rows = []
countries_rows = []
rows.each do |row|
result = LightResult.new(row)
value = row["value"]

world_rows << row if value == best_value_of_world

if best_values_of_continents[result.country.continent.id].nil? || value == best_values_of_continents[result.country.continent.id]
best_values_of_continents[result.country.continent.id] = value

if (country.present? && country.continent.id == result.country.continent.id) || (continent.present? && continent.id == result.country.continent.id) || params[:region] == "world"
continents_rows << row
end
end

if best_values_of_countries[result.country.id].nil? || value == best_values_of_countries[result.country.id]
best_values_of_countries[result.country.id] = value

if (country.present? && country.id == result.country.id) || params[:region] == "world"
countries_rows << row
end
end
end

first_continent_index = world_rows.length
first_country_index = first_continent_index + continents_rows.length
rows_to_display = world_rows + continents_rows + countries_rows
[rows_to_display, first_continent_index, first_country_index]
end
end
4 changes: 1 addition & 3 deletions app/controllers/server_status_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ class MysqlSettingsCheck < StatusCheck
EXPECTED_MYSQL_SETTINGS = {
"@@innodb_ft_min_token_size" => 2,
"@@ft_min_word_len" => 2,
# The default server character set changed from latin1 to ut8mb4 in mysql 8.0, however our PHP didn't recognize it and failed to connect.
# We reverted it to latin1. The setting only affects the default charset for CREATE DATABASE statements that have no charset specified.
"@@character_set_server" => "latin1",
"@@character_set_server" => "utf8mb4",
}.freeze

def label
Expand Down
57 changes: 45 additions & 12 deletions app/controllers/tickets_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,47 @@
# frozen_string_literal: true

class TicketsController < ApplicationController
include Rails::Pagination

SORT_WEIGHT_LAMBDAS = {
createdAt:
lambda { |ticket| ticket.created_at },
}.freeze

def index
tickets = Ticket

# Filter based on params
type = params[:type]
if type
tickets = tickets.where(metadata_type: type)
end

status = params[:status]
tickets = tickets.select do |ticket|
if status
ticket.metadata&.status == status
else
true
end
end

# Filter based on current_user's permission
tickets = tickets.select do |ticket|
ticket.can_user_access?(current_user)
end

# Sort
sort_param = params[:sort] || ''
tickets = sort(tickets, sort_param, SORT_WEIGHT_LAMBDAS)

# paginate won't help in improving efficiency here because we are fetching all the tickets
# and then filtering and sorting them. We can't use the database to do this because the
# filtering and sorting is based on the metadata of the ticket.
# TODO: Check the feasibility of using the database to filter and sort the tickets.
paginate json: tickets
end

def show
respond_to do |format|
format.html do
Expand All @@ -9,22 +50,13 @@ def show
end
format.json do
ticket = Ticket.find(params.require(:id))
# requester_stakeholders will have the list of stakeholders where the requester is part of.
# For example, if a normal user X requests for a change by creating a ticket, the
# stakeholders list will be [X, WRT] (WRT is added as stakeholder because WRT is
# responsible for taking action on the ticket). If a WRT member fetches the ticket data,
# the value of requester_stakeholders will be [WRT] and if the normal user fetches the
# ticket data, the value of requester_stakeholders will be [X]. If the ticket is created by
# a WRT member, then the value requester_stakeholders will be [X, WRT] because the user can
# be any of the two stakeholders.
requester_stakeholders = ticket.user_stakeholders(current_user)

# Currently only stakeholders can access the ticket.
return head :unauthorized if requester_stakeholders.empty?
return head :unauthorized unless ticket.can_user_access?(current_user)

render json: {
ticket: ticket,
requester_stakeholders: requester_stakeholders,
requester_stakeholders: ticket.user_stakeholders(current_user),
}
end
end
Expand Down Expand Up @@ -58,7 +90,8 @@ def edit_person_validators
ticket.metadata.tickets_edit_person_fields.each do |edit_person_field|
case edit_person_field[:field_name]
when TicketsEditPersonField.field_names[:dob]
dob_validation_issues = ResultsValidators::PersonsValidator.dob_validations(Date.parse(edit_person_field[:new_value]))
dob_to_validate = Date.parse(edit_person_field[:new_value])
dob_validation_issues = ResultsValidators::PersonsValidator.dob_validations(dob_to_validate, nil, name: ticket.metadata.wca_id)
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/helpers/persons_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def odd_rank?(rank)
end

def return_podium_class(result)
if (result.roundTypeId == 'f' || result.roundTypeId == 'c') && !result.best_solve.dnf?
if (['f', 'c'].include?(result.roundTypeId)) && !result.best_solve.dnf?
case result.pos
when 1
"gold-place"
Expand Down
39 changes: 0 additions & 39 deletions app/helpers/results_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,6 @@ def historical_pb_markers(results)
end
end

def compute_rankings_by_region(rows, continent, country)
if rows.empty?
return [[], 0, 0]
end
best_value_of_world = rows.first["value"]
best_values_of_continents = {}
best_values_of_countries = {}
world_rows = []
continents_rows = []
countries_rows = []
rows.each do |row|
result = LightResult.new(row)
value = row["value"]

world_rows << row if value == best_value_of_world

if best_values_of_continents[result.country.continent.id].nil? || value == best_values_of_continents[result.country.continent.id]
best_values_of_continents[result.country.continent.id] = value

if (country.present? && country.continent.id == result.country.continent.id) || (continent.present? && continent.id == result.country.continent.id) || params[:region] == "world"
continents_rows << row
end
end

if best_values_of_countries[result.country.id].nil? || value == best_values_of_countries[result.country.id]
best_values_of_countries[result.country.id] = value

if (country.present? && country.id == result.country.id) || params[:region] == "world"
countries_rows << row
end
end
end

first_continent_index = world_rows.length
first_country_index = first_continent_index + continents_rows.length
rows_to_display = world_rows + continents_rows + countries_rows
[rows_to_display, first_continent_index, first_country_index]
end

def compute_slim_or_separate_records(rows)
single_rows = []
average_rows = []
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/sync_mailing_lists_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def perform
# Special case: WIC is the first committee in our (recent) history that "absorbed" another team's duties:
# They are now a "mix" of WDC and WEC. The structures have been mapped so that WIC reuses WDC's groups,
# so they get WDC access "for free". But they _also_ need to be synced to ethics@ to view old conversations from there.
GsuiteMailingLists.sync_group("[email protected]", GroupsMetadataTeamsCommittees.wic.user_group.active_users.map(&:email))
GsuiteMailingLists.sync_group("[email protected]", GroupsMetadataTeamsCommittees.wic.user_group.active_users.pluck(:email))

treasurers = UserGroup.officers.flat_map(&:active_roles).filter { |role| role.metadata.status == RolesMetadataOfficers.statuses[:treasurer] }
GsuiteMailingLists.sync_group("[email protected]", treasurers.map(&:user).map(&:email))
Expand Down
1 change: 1 addition & 0 deletions app/models/competition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Competition < ApplicationRecord
scope :not_visible, -> { where(showAtAll: false) }
scope :over, -> { where("results_posted_at IS NOT NULL OR end_date < ?", Date.today) }
scope :not_over, -> { where("results_posted_at IS NULL AND end_date >= ?", Date.today) }
scope :between_dates, ->(start_date, end_date) { where("start_date <= ? AND end_date >= ?", end_date, start_date) }
scope :end_date_passed_since, lambda { |num_days| where(end_date: ...(num_days.days.ago)) }
scope :belongs_to_region, lambda { |region_id|
joins(:country).where(
Expand Down
2 changes: 1 addition & 1 deletion app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def fewest_moves?
end

def multiple_blindfolded?
self.id == "333mbf" || self.id == "333mbo"
["333mbf", "333mbo"].include?(self.id)
end

def can_change_time_limit?
Expand Down
19 changes: 18 additions & 1 deletion app/models/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ def self.fields_edit_requestable
methods: ["url", "country_iso2"],
}.freeze

USER_COMMON_SERIALIZE_OPTIONS = {
only: ["name", "gender"],
methods: ["country_iso2"],
# grrr… some tests (and apparently also API endpoints) rely on serializing this data _through_ person.
# Not a good code design decision, but very cumbersome to properly refactor. Signed GB 2025-01-09
include: User::DEFAULT_SERIALIZE_OPTIONS[:include],
}.freeze

def personal_records
[self.ranksAverage, self.ranksSingle].compact.flatten
end
Expand Down Expand Up @@ -306,8 +314,17 @@ def serializable_hash(options = nil)
json[:incorrect_wca_id_claim_count] = incorrect_wca_id_claim_count
end

# Passing down options from Person to User (which are completely different models in the DB!)
# is a horrible idea. Unfortunately, our external APIs have come to rely on it,
# so we need to hack around it.
# - `merge_union` makes sure that only values specified in USER_COMMON_SERIALIZE_OPTIONS kick in
# - `filter` makes sure that when the result of `merge_union` are empty, the defaults from
# User::DEFAULT_SERIALIZE_OPTIONS can override.
user_override_options = USER_COMMON_SERIALIZE_OPTIONS.merge_union(options&.stringify_keys)
.filter { |_, v| v.present? }

# If there's a user for this Person, merge in all their data,
# the Person's data takes priority, though.
(user || User.new).serializable_hash(options).merge(json)
(user || User.new).serializable_hash(user_override_options).merge(json)
end
end
Loading

0 comments on commit ec2be7b

Please sign in to comment.