Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Cloud-CV/EvalAI
Browse files Browse the repository at this point in the history
  • Loading branch information
Suryansh5545 committed Sep 11, 2023
2 parents 00858bf + 4556fcf commit 47603f7
Show file tree
Hide file tree
Showing 16 changed files with 824 additions and 49 deletions.
16 changes: 16 additions & 0 deletions apps/challenges/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
PWCChallengeLeaderboard,
StarChallenge,
UserInvitation,
ChallengeSponsor,
ChallengePrize,
)


Expand Down Expand Up @@ -432,3 +434,17 @@ def get_challenge_name_and_id(self, obj):

get_challenge_name_and_id.short_description = "Challenge Name - ID"
get_challenge_name_and_id.admin_order_field = "challenge_phase__challenge"


@admin.register(ChallengeSponsor)
class ChallengeSponsorAdmin(ImportExportTimeStampedAdmin):
list_display = ("id", "name", "website")
list_filter = ("name",)
search_fields = ("id", "name")


@admin.register(ChallengePrize)
class ChallengePrizeAdmin(ImportExportTimeStampedAdmin):
list_display = ("id", "amount", "rank")
list_filter = ("rank",)
search_fields = ("id", "rank")
89 changes: 43 additions & 46 deletions apps/challenges/challenge_config_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from django.core.files.base import ContentFile

import re
from os.path import basename, isfile, join
from challenges.models import ChallengePhase, ChallengePhaseSplit, DatasetSplit, Leaderboard, Challenge
from rest_framework import status
Expand Down Expand Up @@ -258,19 +259,15 @@ def get_value_from_field(data, base_location, field_name):
"dataset_split_schema_errors": "ERROR: Dataset split {} has the following schema errors:\n {}",
"dataset_split_addition": "ERROR: Dataset split {} doesn't exist. Addition of a new dataset split after challenge creation is not allowed.",
"missing_existing_dataset_split_id": "ERROR: Dataset split {} not found in config. Deletion of existing dataset split after challenge creation is not allowed.",
"challenge_phase_split_not_exist": "ERROR: Challenge phase split (leaderboard_id: {}, challenge_phase_id: {}, dataset_split_id: {}) doesn't exist. Addition of challenge phase split after challenge creation is not allowed.",
"challenge_phase_split_schema_errors": "ERROR: Challenge phase split {} has the following schema errors:\n {}",
"missing_keys_in_challenge_phase_splits": "ERROR: The following keys are missing in the challenge phase splits of YAML file (phase_split: {}): {}",
"challenge_phase_split_not_found": "ERROR: Challenge phase split (leaderboard_id: {}, challenge_phase_id: {}, dataset_split_id: {}) not found in config. Deletion of existing challenge phase split after challenge creation is not allowed.",
"no_key_for_challenge_phase_splits": "ERROR: There is no key for challenge phase splits.",
"no_codename_for_challenge_phase": "ERROR: No codename found for the challenge phase. Please add a codename and try again!",
"duplicate_codename_for_phase": "ERROR: Duplicate codename {} for phase {}. Please ensure codenames are unique",
"no_test_annotation_file_found": "ERROR: No test annotation file found in the zip file for challenge phase {}",
"submission_meta_attribute_option_missing": "ERROR: Please include at least one option in the attribute for challenge phase {}",
"missing_submission_meta_attribute_fields": "ERROR: Please enter the following fields for the submission meta attribute in challenge phase {}: {}",
"challenge_phase_schema_errors": "ERROR: Challenge phase {} has the following schema errors:\n {}",
"challenge_phase_addition": "ERROR: Challenge phase {} doesn't exist. Addition of a new challenge phase after challenge creation is not allowed.",
"challenge_phase_not_found": "ERROR: Challenge phase {} not found in config. Deletion of existing challenge phase after challenge creation is not allowed.",
"is_submission_public_restricted": "ERROR: is_submission_public can't be 'True' for challenge phase '{}' with is_restricted_to_select_one_submission 'True'. Please change is_submission_public to 'False' and try again!",
"missing_option_in_submission_meta_attribute": "ERROR: Please include at least one option in the attribute for challenge phase {}",
"missing_fields_in_submission_meta_attribute": "ERROR: Please enter the following fields for the submission meta attribute in challenge phase {}: {}",
Expand All @@ -281,6 +278,11 @@ def get_value_from_field(data, base_location, field_name):
"extra_tags": "ERROR: Tags are limited to 4. Please remove extra tags then try again!",
"wrong_domain": "ERROR: Domain name is incorrect. Please enter correct domain name then try again!",
"duplicate_combinations_in_challenge_phase_splits": "ERROR: Duplicate combinations of leaderboard_id {}, challenge_phase_id {} and dataset_split_id {} found in challenge phase splits.",
"sponsor_not_found": "ERROR: Sponsor name or url not found in YAML data.",
"prize_not_found": "ERROR: Prize rank or amount not found in YAML data.",
"duplicate_rank": "ERROR: Duplicate rank {} found in YAML data.",
"prize_amount_wrong": "ERROR: Invalid amount value {}. Amount should be in decimal format with three-letter currency code (e.g. 100.00USD, 500EUR, 1000INR).",
"prize_rank_wrong": "ERROR: Invalid rank value {}. Rank should be an integer.",
}


Expand Down Expand Up @@ -782,23 +784,8 @@ def validate_challenge_phases(self, current_phase_config_ids):
].format(data["id"], serializer_error)
self.error_messages.append(message)
else:
if (
current_phase_config_ids
and int(data["id"]) not in current_phase_config_ids
):
message = self.error_messages_dict[
"challenge_phase_addition"
].format(data["id"])
self.error_messages.append(message)
self.phase_ids.append(data["id"])

for current_challenge_phase_id in current_phase_config_ids:
if current_challenge_phase_id not in self.phase_ids:
message = self.error_messages_dict[
"challenge_phase_not_found"
].format(current_challenge_phase_id)
self.error_messages.append(message)

def validate_challenge_phase_splits(self, current_phase_split_ids):
challenge_phase_splits = self.yaml_file_data.get(
"challenge_phase_splits"
Expand Down Expand Up @@ -849,31 +836,13 @@ def validate_challenge_phase_splits(self, current_phase_split_ids):
"challenge_phase_id",
}
if expected_keys.issubset(data.keys()):
if (
current_phase_split_ids
and (
challenge_phase_split_uuids.append(
(
data["leaderboard_id"],
data["challenge_phase_id"],
data["dataset_split_id"],
)
not in current_phase_split_ids
):
message = self.error_messages_dict[
"challenge_phase_split_not_exist"
].format(
data["leaderboard_id"],
data["challenge_phase_id"],
data["dataset_split_id"],
)
self.error_messages.append(message)
else:
challenge_phase_split_uuids.append(
(
data["leaderboard_id"],
data["challenge_phase_id"],
data["dataset_split_id"],
)
)
)

(
is_mapping_valid,
Expand Down Expand Up @@ -904,12 +873,6 @@ def validate_challenge_phase_splits(self, current_phase_split_ids):
"missing_keys_in_challenge_phase_splits"
].format(phase_split, missing_keys_string)
self.error_messages.append(message)
for uuid in current_phase_split_ids:
if uuid not in challenge_phase_split_uuids:
message = self.error_messages_dict[
"challenge_phase_split_not_found"
].format(uuid[0], uuid[1], uuid[2])
self.error_messages.append(message)
else:
message = self.error_messages_dict[
"no_key_for_challenge_phase_splits"
Expand Down Expand Up @@ -991,6 +954,35 @@ def check_domain(self):
message = self.error_messages_dict["wrong_domain"]
self.error_messages.append(message)

def check_sponsor(self):
# Verify Sponsor is correct
if "sponsors" in self.yaml_file_data:
for sponsor in self.yaml_file_data["sponsors"]:
if 'name' not in sponsor or 'website' not in sponsor:
message = self.error_messages_dict["sponsor_not_found"]
self.error_messages.append(message)

def check_prizes(self):
# Verify Prizes are correct
if "prizes" in self.yaml_file_data:
rank_set = set()
for prize in self.yaml_file_data["prizes"]:
if 'rank' not in prize or 'amount' not in prize:
message = self.error_messages_dict["prize_not_found"]
self.error_messages.append(message)
# Check for duplicate rank.
rank = prize['rank']
if rank in rank_set:
message = self.error_messages_dict["duplicate_rank"].format(rank)
self.error_messages.append(message)
rank_set.add(rank)
if not isinstance(rank, int) or rank < 1:
message = self.error_messages_dict["prize_rank_wrong"].format(rank)
self.error_messages.append(message)
if not re.match(r'^\d+(\.\d{1,2})?[A-Z]{3}$', prize["amount"]):
message = self.error_messages_dict["prize_amount_wrong"].format(prize["amount"])
self.error_messages.append(message)


def validate_challenge_config_util(
request,
Expand Down Expand Up @@ -1106,6 +1098,11 @@ def validate_challenge_config_util(

# Validate domain
val_config_util.check_domain()
# Check for Sponsor
# val_config_util.check_sponsor()

# Check for Prize
val_config_util.check_prizes()

return (
val_config_util.error_messages,
Expand Down
53 changes: 53 additions & 0 deletions apps/challenges/migrations/0105_challenge_sponsors_prizes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 2.2.20 on 2023-08-11 17:02

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('challenges', '0104_challenge_evaluation_module_error'),
]

operations = [
migrations.AddField(
model_name='challenge',
name='has_prize',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='challenge',
name='has_sponsors',
field=models.BooleanField(default=False),
),
migrations.CreateModel(
name='ChallengeSponsor',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('modified_at', models.DateTimeField(auto_now=True)),
('name', models.CharField(blank=True, max_length=200, null=True)),
('website', models.URLField(blank=True, null=True)),
('challenge', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='challenges.Challenge')),
],
options={
'db_table': 'challenge_sponsor',
},
),
migrations.CreateModel(
name='ChallengePrize',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('modified_at', models.DateTimeField(auto_now=True)),
('amount', models.CharField(max_length=10)),
('description', models.CharField(blank=True, max_length=25, null=True)),
('rank', models.PositiveIntegerField()),
('challenge', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='challenges.Challenge')),
],
options={
'db_table': 'challenge_prize',
},
),
]
43 changes: 43 additions & 0 deletions apps/challenges/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ def __init__(self, *args, **kwargs):
)
domain = models.CharField(max_length=50, choices=DOMAIN_OPTIONS, null=True, blank=True)
list_tags = ArrayField(models.TextField(null=True, blank=True), default=list, blank=True)
has_prize = models.BooleanField(default=False)
has_sponsors = models.BooleanField(default=False)
published = models.BooleanField(
default=False, verbose_name="Publicly Available", db_index=True
)
Expand Down Expand Up @@ -666,3 +668,44 @@ class PWCChallengeLeaderboard(TimeStampedModel):
class Meta:
app_label = "challenges"
db_table = "pwc_challenge_leaderboard"


class ChallengeSponsor(TimeStampedModel):
"""
Model to store challenge sponsors
Arguments:
TimeStampedModel {[model class]} -- An abstract base class model that provides self-managed `created_at` and
`modified_at` fields.
"""

challenge = models.ForeignKey("Challenge", on_delete=models.CASCADE)
name = models.CharField(max_length=200, blank=True, null=True)
website = models.URLField(max_length=200, blank=True, null=True)

class Meta:
app_label = "challenges"
db_table = "challenge_sponsor"

def __str__(self):
return f"Sponsor for {self.challenge}: {self.name}"


class ChallengePrize(TimeStampedModel):
"""
Model to store challenge prizes
Arguments:
TimeStampedModel {[model class]} -- An abstract base class model that provides self-managed `created_at` and
`modified_at` fields.
"""

challenge = models.ForeignKey("Challenge", on_delete=models.CASCADE)
amount = models.CharField(max_length=10)
description = models.CharField(max_length=25, blank=True, null=True)
rank = models.PositiveIntegerField()

class Meta:
app_label = "challenges"
db_table = "challenge_prize"

def __str__(self):
return f"Prize for {self.challenge}: Rank {self.rank}, Amount {self.amount}"
49 changes: 49 additions & 0 deletions apps/challenges/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
PWCChallengeLeaderboard,
StarChallenge,
UserInvitation,
ChallengePrize,
ChallengeSponsor,
)


Expand Down Expand Up @@ -53,6 +55,8 @@ class Meta:
"domain",
"domain_name",
"list_tags",
"has_prize",
"has_sponsors",
"published",
"submission_time_limit",
"is_registration_open",
Expand Down Expand Up @@ -560,3 +564,48 @@ class Meta:
"result",
"error",
)


class ChallengePrizeSerializer(serializers.ModelSerializer):
"""
Serialize the ChallengePrize Model.
"""

def __init__(self, *args, **kwargs):
super(ChallengePrizeSerializer, self).__init__(*args, **kwargs)
context = kwargs.get("context")
if context:
challenge = context.get("challenge")
if challenge:
kwargs["data"]["challenge"] = challenge.pk

class Meta:
model = ChallengePrize
fields = (
"challenge",
"amount",
"rank",
"description"
)


class ChallengeSponsorSerializer(serializers.ModelSerializer):
"""
Serialize the ChallengeSponsor Model.
"""

def __init__(self, *args, **kwargs):
super(ChallengeSponsorSerializer, self).__init__(*args, **kwargs)
context = kwargs.get("context")
if context:
challenge = context.get("challenge")
if challenge:
kwargs["data"]["challenge"] = challenge.pk

class Meta:
model = ChallengeSponsor
fields = (
"challenge",
"name",
"website"
)
10 changes: 10 additions & 0 deletions apps/challenges/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,16 @@
views.update_challenge_approval,
name="update_challenge_approval",
),
url(
r"^challenge/(?P<challenge_pk>[0-9]+)/prizes/$",
views.get_prizes_by_challenge,
name="get_prizes_by_challenge",
),
url(
r"^challenge/(?P<challenge_pk>[0-9]+)/sponsors/$",
views.get_sponsors_by_challenge,
name="get_sponsors_by_challenge",
),
]

app_name = "challenges"
Loading

0 comments on commit 47603f7

Please sign in to comment.