Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/apps/api/serializers/leaderboards.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Meta:
'sorting',
'index',
'hidden',
'precision',
)

def validate(self, attrs):
Expand Down
13 changes: 13 additions & 0 deletions src/apps/api/views/competitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,21 @@ def get_leaderboard(self, request, pk):
'organization': submission['organization'],
})
for score in submission['scores']:

# default precision is set to 2
precision = 2

# loop over columns to find a column with the same index
# replace default precision with column precision
for col in columns:
if col["index"] == score["index"]:
precision = col["precision"]
break

tempScore = score
tempScore['task_id'] = submission['task']
# round the score to 'precision' decimal points
tempScore['score'] = str(round(float(tempScore["score"]), precision))
response['submissions'][submissions_keys[submission_key]]['scores'].append(tempScore)

for task in query['tasks']:
Expand Down
18 changes: 18 additions & 0 deletions src/apps/competitions/migrations/0031_auto_20230504_1016.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.17 on 2023-05-04 10:16

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('competitions', '0030_submission_started_when'),
]

operations = [
migrations.AlterField(
model_name='competition',
name='docker_image',
field=models.CharField(default='codalab/codalab-legacy:py37', max_length=128),
),
]
2 changes: 1 addition & 1 deletion src/apps/competitions/tests/test_v15_unpacker.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ def test_page_unpacking(self):

def test_leaderboard_unpacking(self):
self.unpacker._unpack_leaderboards()
assert self.unpacker.competition['leaderboards'] == test_data.LEADERBOARDS
assert self.unpacker.competition['leaderboards'] == test_data.V1_LEADERBOARDS
2 changes: 1 addition & 1 deletion src/apps/competitions/tests/test_v2_unpacker.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_page_unpacking(self):

def test_leaderboard_unpacking(self):
self.unpacker._unpack_leaderboards()
assert self.unpacker.competition['leaderboards'] == test_data.LEADERBOARDS
assert self.unpacker.competition['leaderboards'] == test_data.V2_LEADERBOARDS

def test_competition_type_if_not_set(self):
assert self.unpacker.competition['competition_type'] == 'competition'
23 changes: 22 additions & 1 deletion src/apps/competitions/tests/unpacker_test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,28 @@
# Truth Data
# -------------------------------------------------

LEADERBOARDS = [{
V1_LEADERBOARDS = [{
"title": "Results",
"key": "Results",
"columns": [
{
"title": "prediction_score",
"key": "prediction_score",
"index": 0,
"sorting": "desc",
"precision": 4,
},
{
"title": "Duration",
"key": "Duration",
"index": 1,
"sorting": "desc",
"precision": 2,
}
]
}]

V2_LEADERBOARDS = [{
"title": "Results",
"key": "Results",
"columns": [
Expand Down
4 changes: 3 additions & 1 deletion src/apps/competitions/unpackers/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ def _unpack_leaderboards(self):
'title': column['title'],
'key': column['title'],
'index': index,
'sorting': column.get('sort') or 'desc'
'sorting': column.get('sort') or 'desc',
# get precision as numeric_format, if not found, use default value = 2
'precision': column.get('numeric_format', 2)
}

for leaderboard_data in self.competition['leaderboards']:
Expand Down
8 changes: 6 additions & 2 deletions src/apps/competitions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.http import Http404
from django.views.generic import TemplateView, DetailView

from .models import Competition
from .models import Competition, CompetitionParticipant


class CompetitionManagement(LoginRequiredMixin, TemplateView):
Expand All @@ -29,8 +29,12 @@ def get_object(self, *args, **kwargs):
competition = super().get_object(*args, **kwargs)
is_creator = self.request.user.is_superuser or self.request.user == competition.created_by
is_collaborator = self.request.user in competition.collaborators.all()

# get participants from CompetitionParticipant where user=user and competition=competition
is_participant = CompetitionParticipant.objects.filter(user=self.request.user, competition=competition).count() > 0

valid_secret_key = self.request.GET.get('secret_key') == str(competition.secret_key)
if is_creator or is_collaborator or competition.published or valid_secret_key:
if is_creator or is_collaborator or competition.published or valid_secret_key or is_participant:
return competition
raise Http404()

Expand Down
18 changes: 18 additions & 0 deletions src/apps/leaderboards/migrations/0008_column_precision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.17 on 2023-05-04 10:16

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('leaderboards', '0007_auto_20201110_1731'),
]

operations = [
migrations.AddField(
model_name='column',
name='precision',
field=models.IntegerField(default=2),
),
]
1 change: 1 addition & 0 deletions src/apps/leaderboards/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Column(models.Model):
index = models.PositiveIntegerField()
leaderboard = models.ForeignKey(Leaderboard, on_delete=models.CASCADE, related_name="columns")
hidden = models.BooleanField(default=False)
precision = models.IntegerField(default=2)

class Meta:
unique_together = ('leaderboard', 'key')
Expand Down
24 changes: 24 additions & 0 deletions src/apps/profiles/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth import get_user_model

User = get_user_model()


class EmailAuthenticationBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
else:
return None
except ObjectDoesNotExist:
return None

def get_user(self, user_id):
try:
user = User.objects.get(id=user_id)
return user
except ObjectDoesNotExist:
return None
6 changes: 6 additions & 0 deletions src/apps/profiles/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ class Meta:

model = User
fields = ("username", "email", "password1", "password2")


class LoginForm(forms.Form):

username = forms.CharField(max_length=150)
password = forms.CharField(max_length=150, widget=forms.PasswordInput)
3 changes: 2 additions & 1 deletion src/apps/profiles/urls_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

urlpatterns = [
url(r'^signup', views.sign_up, name="signup"),
path('login/', views.log_in, name='login'),
# url(r'^user_profile', views.user_profile, name="user_profile"),
# path('login/', auth_views.LoginView.as_view(extra_context=extra_context), name='login'),
path('login/', views.LoginView.as_view(), name='login'),
# path('login/', views.LoginView.as_view(), name='login'),
# path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('logout/', views.LogoutView.as_view(), name='logout'),
path('password_reset/', views.CustomPasswordResetView.as_view(), name='password_reset'),
Expand Down
31 changes: 29 additions & 2 deletions src/apps/profiles/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django.conf import settings
from django.contrib import messages
from django.contrib.auth import authenticate
from django.contrib.auth import authenticate, login
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import EmailMessage, EmailMultiAlternatives
from django.http import Http404
Expand All @@ -18,7 +18,7 @@

from api.serializers.profiles import UserSerializer, OrganizationDetailSerializer, OrganizationEditSerializer, \
UserNotificationSerializer
from .forms import SignUpForm
from .forms import SignUpForm, LoginForm
from .models import User, Organization, Membership
from .tokens import account_activation_token

Expand Down Expand Up @@ -128,6 +128,33 @@ def sign_up(request):
return render(request, 'registration/signup.html', context)


def log_in(request):

context = {}
context['chahub_signup_url'] = "{}/profiles/signup?next={}/social/login/chahub".format(
settings.SOCIAL_AUTH_CHAHUB_BASE_URL,
settings.SITE_DOMAIN
)
if request.method == 'POST':
form = LoginForm(request.POST)

if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user:
login(request, user)
return redirect('pages:home')
else:
messages.error(request, "Wrong Credentials!")
else:
context['form'] = form

if not context.get('form'):
context['form'] = LoginForm()
return render(request, 'registration/login.html', context)


# Password Reset views/forms below
# auth_forms
class CustomPasswordResetForm(auth_forms.PasswordResetForm):
Expand Down
1 change: 1 addition & 0 deletions src/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
'utils.oauth_backends.ChahubOAuth2',
'django.contrib.auth.backends.ModelBackend',
'django_su.backends.SuBackend',
'profiles.backends.EmailAuthenticationBackend',
)

SOCIAL_AUTH_PIPELINE = (
Expand Down
34 changes: 34 additions & 0 deletions src/static/riot/competitions/detail/_tabs.tag
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,40 @@
})
})

// loop over competition phases to mark if phase has started or ended
self.competition.phases.forEach(function (phase, index) {

phase_ended = false
phase_started = false

// check if phase has started
if((Date.parse(phase["start"]) - Date.parse(new Date())) > 0){
// start date is in the future, phase started = NO
phase_started = false
}else{
// start date is not in the future, phase started = YES
phase_started = true
}

if(phase_started){
// check if end data exists for this phase
if(phase["end"]){
if((Date.parse(phase["end"]) - Date.parse(new Date())) < 0){
// Phase cannote accept submissions if end date is in the past
phase_ended = true
}else{
// Phase can accept submissions if end date is in the future
phase_ended = false
}
}else{
// Phase can accept submissions if end date is not given
phase_ended = false
}
}
self.competition.phases[index]["phase_ended"] = phase_ended
self.competition.phases[index]["phase_started"] = phase_started
})

self.competition.is_admin = CODALAB.state.user.has_competition_admin_privileges(competition)
self.selected_phase_index = _.get(_.find(self.competition.phases, {'status': 'Current'}), 'id')
if (self.selected_phase_index == null) {
Expand Down
4 changes: 1 addition & 3 deletions src/static/riot/competitions/detail/leaderboards.tag
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<td if="{submission.organization === null}"><a href="{submission.slug_url}">{ submission.owner }</a></td>
<td if="{submission.organization !== null}"><a href="{submission.organization.url}">{ submission.organization.name }</a></td>
<td each="{ column in filtered_columns }">{ get_score(column, submission) } </td>
<td if="{enable_detailed_results}"><a href="detailed_results/{submission.id}">Show detailed results</a></td>
<td if="{enable_detailed_results}"><a href="detailed_results/{submission.id}" target="_blank">Show detailed results</a></td>
</tr>
</tbody>
</table>
Expand Down Expand Up @@ -121,8 +121,6 @@
CODALAB.api.get_leaderboard_for_render(self.phase_id)
.done(responseData => {
self.selected_leaderboard = responseData


self.columns = []
// Make fake task and columns for Metadata so it can be filtered like columns
if(self.selected_leaderboard.fact_sheet_keys){
Expand Down
38 changes: 28 additions & 10 deletions src/static/riot/competitions/detail/submission_upload.tag
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

<div class="submission-form">
<h1>Submission upload</h1>
<div if="{_.get(selected_phase, 'phase_ended')}" class="ui red message">This phase has ended and no longer accepts submissions!</div>
<div if="{!_.get(selected_phase, 'phase_started')}" class="ui yellow message">This phase hasn't started yet!</div>
<form class="ui form coda-animated {error: errors}" ref="form" enctype="multipart/form-data">
<div class="submission-form" ref="fact_sheet_form" if="{ opts.fact_sheet !== null}">
<h2>Metadata or Fact Sheet</h2>
Expand Down Expand Up @@ -349,17 +351,33 @@
}

self.check_can_upload = function () {
CODALAB.api.can_make_submissions(self.selected_phase.id)
.done(function (data) {
if (data.can) {
self.prepare_upload(self.upload)()
} else {
toastr.error(data.reason)

// Check if selected phase accepts submissions (within the deadline of the phase)
if(self.selected_phase.phase_started && !self.selected_phase.phase_ended){

CODALAB.api.can_make_submissions(self.selected_phase.id)
.done(function (data) {
if (data.can) {
self.prepare_upload(self.upload)()
} else {
toastr.error(data.reason)
}
})
.fail(function (data) {
toastr.error('Could not verify your ability to make a submission')
})
}else{
// Error when phase is not accepting submissions
if(!self.selected_phase.phase_started){
toastr.error('This phase has not started yet. Please check the phase start date!')

}else {
if(self.selected_phase.phase_ended){
toastr.error('This phase has ended and no longer accepts submissions!')
}
})
.fail(function (data) {
toastr.error('Could not verify your ability to make a submission')
})
}
self.clear_form()
}
}

self.get_fact_sheet_answers = function () {
Expand Down
Loading