Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7fa7333
dump creation date fixed
May 8, 2023
9f7a1b5
v1 bundle unpacking: use column label as title
May 9, 2023
8be721c
title updated in V1_Leaderboard
May 9, 2023
babe9d4
Merge pull request #856 from codalab/leaderboard_v1_column_label
Didayolo May 9, 2023
915b14d
hostname in server_status
bbearce May 10, 2023
63d0f3e
flake8
bbearce May 10, 2023
d5be648
missing whitespace after ','
bbearce May 10, 2023
eeab5ad
show compeittion in Benchmark Im running when user is collaborator
May 10, 2023
05a73da
white space removed
May 10, 2023
38d6664
collaborator can access a private competition.
May 10, 2023
119b1db
removed unused import
May 10, 2023
42b2e3b
participant can not access a private competition
May 10, 2023
b3eb96c
Update compute_worker.py
bbearce May 10, 2023
70d94e8
Update submissions.py
bbearce May 10, 2023
3267648
Update submissions.py
bbearce May 10, 2023
e0d3fa7
Merge pull request #861 from codalab/hostname-in-server_status
Didayolo May 10, 2023
015e9c4
Merge pull request #859 from codalab/benchmark_im_running
Didayolo May 10, 2023
509e477
fixed the participants part of query
May 10, 2023
55950bb
by default files will be downloaded instead of just keys used in yaml…
May 11, 2023
7c7916d
date-time converted to readbale format
May 11, 2023
6280ab1
queue added to competition while unpacking from YAML
May 11, 2023
4b689f6
Update competitions.py
Didayolo May 11, 2023
547cd0e
participant condition fixed for private competition
May 11, 2023
0737953
conflict fixed
May 11, 2023
92049ed
Update competitions.py (typos)
Didayolo May 11, 2023
1c318d6
queue name changed to vhost
May 11, 2023
a649e98
console log removed
May 11, 2023
1a30f89
Merge pull request #848 from codalab/dumps
Didayolo May 11, 2023
4a9cbff
Merge pull request #865 from codalab/queue_in_yaml
Didayolo May 11, 2023
b7346a5
Merge pull request #860 from codalab/private_benchmark_collaborator
Didayolo May 11, 2023
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
6 changes: 4 additions & 2 deletions compute_worker/compute_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import websockets
import yaml
from billiard.exceptions import SoftTimeLimitExceeded
from celery import Celery, task
from celery import Celery, task, utils
from kombu import Queue, Exchange
from urllib3 import Retry

Expand Down Expand Up @@ -309,6 +309,7 @@ def _update_submission(self, data):
def _update_status(self, status, extra_information=None):
if status not in AVAILABLE_STATUSES:
raise SubmissionException(f"Status '{status}' is not in available statuses: {AVAILABLE_STATUSES}")

data = {
"status": status,
"status_details": extra_information,
Expand Down Expand Up @@ -663,8 +664,9 @@ def prepare(self):
self._get_container_image(self.container_image)

def start(self):
hostname = utils.nodenames.gethostname()
if not self.is_scoring:
self._update_status(STATUS_RUNNING)
self._update_status(STATUS_RUNNING, extra_information=f"hostname-{hostname}")

program_dir = os.path.join(self.root_dir, "program")
ingestion_program_dir = os.path.join(self.root_dir, "ingestion_program")
Expand Down
38 changes: 29 additions & 9 deletions src/apps/api/views/competitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
from leaderboards.models import Leaderboard
from utils.data import make_url_sassy
from api.permissions import IsOrganizerOrCollaborator
import logging
logger = logging.getLogger()


class CompetitionViewSet(ModelViewSet):
Expand All @@ -56,7 +58,14 @@ def get_queryset(self):
mine = self.request.query_params.get('mine', None)

if mine:
qs = qs.filter(created_by=self.request.user)
# either competition is mine
# or
# I am one of the collaborator
qs = Competition.objects.filter(
(Q(created_by=self.request.user)) |
(Q(collaborators__in=[self.request.user]))

)

participating_in = self.request.query_params.get('participating_in', None)

Expand All @@ -69,19 +78,25 @@ def get_queryset(self):
).values_list('status')[:1]
qs = qs.annotate(participant_status=Subquery(participant_status_query))

# new condition for search bar
# `mine` is true when this is called from "Benchmarks I'm Running"
# `participating_in` is true when this is called from "Benchmarks I'm in"
# `mine` and `participating_in` are none when this is called from Search bar
# `mine` and `participating_in` are none when this is called either from Search bar
# or from competition detail page
if (not mine) and (not participating_in):
# User is logged in
# filter his own competitions
# User is logged in then filter
# competitions which this user owns
# or
# competitions in which this user is collaborator
# or
# filter published competitions by other users
# competitions is published and belongs to someone else
# or
# competitions in which this user is participant and status is approved
qs = qs.filter(
(Q(created_by=self.request.user)) |
(Q(published=True) & ~Q(created_by=self.request.user))
)
(Q(collaborators__in=[self.request.user])) |
(Q(published=True) & ~Q(created_by=self.request.user)) |
(Q(participants__user=self.request.user) & Q(participants__status="approved"))
).distinct()
else:
# if user is not authenticated only filter published/public competitions
qs = qs.filter(Q(published=True))
Expand Down Expand Up @@ -111,6 +126,7 @@ def get_queryset(self):
)

search_query = self.request.query_params.get('search')
# search_query is true when called from searchbar
if search_query:
qs = qs.filter(Q(title__icontains=search_query) | Q(description__icontains=search_query))

Expand Down Expand Up @@ -375,7 +391,11 @@ def create_dump(self, request, pk=None):
competition = self.get_object()
if not competition.user_has_admin_permission(request.user):
raise PermissionDenied("You don't have access")
create_competition_dump.delay(pk)

# arg 1: pk: competition primary key
# arg 2: False: keys_instead_of_files (if false: files will be dowloaded in dumps, if true: only keys)
create_competition_dump.delay(pk, False)

serializer = CompetitionCreationTaskStatusSerializer({"status": "Success. Competition dump is being created."})
return Response(serializer.data, status=201)

Expand Down
7 changes: 7 additions & 0 deletions src/apps/api/views/submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ def check_object_permissions(self, request, obj):
raise PermissionDenied("Cannot add task-specific submission re-runs to leaderboards.")
return
if self.request and self.request.method in ('POST', 'PUT', 'PATCH'):
dir(self.request)
# Set hostname of submission
if "status_details" in self.request.data.keys():
if request.data['status_details'].find('hostname') != -1:
hostname = request.data['status_details'].replace('hostname-', '')
obj.worker_hostname = hostname
obj.save()
not_bot_user = self.request.user.is_authenticated and not self.request.user.is_bot

if self.action in ['update_fact_sheet', 're_run_submission']:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.17 on 2023-05-09 04:20

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('competitions', '0031_auto_20230504_1016'),
]

operations = [
migrations.AddField(
model_name='submission',
name='worker_hostname',
field=models.CharField(blank=True, max_length=255, null=True),
),
]
2 changes: 1 addition & 1 deletion src/apps/competitions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ class Submission(ChaHubSaveMixin, models.Model):
started_when = models.DateTimeField(null=True)
is_public = models.BooleanField(default=False)
is_specific_task_re_run = models.BooleanField(default=False)

worker_hostname = models.CharField(max_length=255, blank=True, null=True)
is_migrated = models.BooleanField(default=False)
created_by_migration = models.ForeignKey(Phase, related_name='migrated_submissions', on_delete=models.CASCADE,
null=True,
Expand Down
10 changes: 6 additions & 4 deletions src/apps/competitions/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import re
import traceback
import zipfile
from datetime import timedelta
from datetime import timedelta, datetime

from io import BytesIO
from tempfile import TemporaryDirectory, NamedTemporaryFile

Expand Down Expand Up @@ -423,15 +424,16 @@ def _get_error_string(error_dict):


@app.task(queue='site-worker', soft_time_limit=60 * 10)
def create_competition_dump(competition_pk, keys_instead_of_files=True):
def create_competition_dump(competition_pk, keys_instead_of_files=False):
yaml_data = {"version": "2"}
try:
# -------- SetUp -------

logger.info(f"Finding competition {competition_pk}")
comp = Competition.objects.get(pk=competition_pk)
zip_buffer = BytesIO()
zip_name = f"{comp.title}-{comp.created_when.isoformat()}.zip"
current_date_time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
zip_name = f"{comp.title}-{current_date_time}.zip"
zip_file = zipfile.ZipFile(zip_buffer, "w")

# -------- Main Competition Details -------
Expand Down Expand Up @@ -626,7 +628,7 @@ def create_competition_dump(competition_pk, keys_instead_of_files=True):
bundle_count = CompetitionDump.objects.count() + 1
temp_dataset_bundle = Data.objects.create(
created_by=comp.created_by,
name=f"{comp.title} Dump #{bundle_count} Created {comp.created_when.date()}",
name=f"{comp.title} Dump #{bundle_count} Created {current_date_time}",
type='competition_bundle',
description='Automatically created competition dump',
# 'data_file'=,
Expand Down
2 changes: 1 addition & 1 deletion src/apps/competitions/tests/unpacker_test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
"label": "RESULTS",
"columns": [
{
"title": "prediction_score",
"title": "Prediction score",
"key": "prediction_score",
"index": 0,
"sorting": "desc",
Expand Down
11 changes: 10 additions & 1 deletion src/apps/competitions/unpackers/base_unpacker.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,16 @@ def _unpack_queue(self):
all_queue_organizer_names = queue.organizers.all().values_list('username', flat=True)
if queue.owner != self.creator and self.creator.username not in all_queue_organizer_names:
raise CompetitionUnpackingException("You do not have access to the specified queue!")
self.competition['queue'] = queue.id
self.competition['queue'] = {
'name': queue.name,
'vhost': queue.vhost,
'is_public': queue.is_public,
'owner': queue.owner,
'organizers': queue.organizers,
'broker_url': queue.broker_url,
'created_when': queue.broker_url,
'id': queue.id,
}
except Queue.DoesNotExist:
raise CompetitionUnpackingException("The specified Queue does not exist!")

Expand Down
3 changes: 2 additions & 1 deletion src/apps/competitions/unpackers/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ def _unpack_leaderboards(self):

for index, column in enumerate(columns):
new_col_data = {
'title': column['title'],
# get label as title, if not found, use title by default
'title': column.get('label', column['title']),
'key': column['title'],
'index': index,
'sorting': column.get('sort') or 'desc',
Expand Down
16 changes: 13 additions & 3 deletions src/apps/competitions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ class CompetitionDetail(DetailView):
def get_object(self, *args, **kwargs):
competition = super().get_object(*args, **kwargs)

is_creator, is_collaborator, is_participant = False, False, False
is_admin, is_creator, is_collaborator, is_participant = False, False, False, False

# check if user is loggedin
if self.request.user.is_authenticated:

# check if user is admin
is_admin = self.request.user.is_superuser

# check if user is the creator of this competition
is_creator = self.request.user.is_superuser or self.request.user == competition.created_by
is_creator = self.request.user == competition.created_by

# check if user is collaborator of this competition
is_collaborator = self.request.user in competition.collaborators.all()
Expand All @@ -46,7 +49,14 @@ def get_object(self, *args, **kwargs):
# check if secret key provided is valid
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 or is_participant:
if (
is_admin or
is_creator or
is_collaborator or
competition.published or
valid_secret_key or
is_participant
):
return competition
raise Http404()

Expand Down
2 changes: 2 additions & 0 deletions src/templates/pages/server_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ <h1>Recent submissions (up to 250 or 2 days old)</h1>
<th>Competition</th>
<th>Submission PK</th>
<th>Submitter</th>
<th>Hostname</th>
<th>Submitted at</th>
<th>Status</th>
</thead>
Expand All @@ -26,6 +27,7 @@ <h1>Recent submissions (up to 250 or 2 days old)</h1>
<td>{{ submission.phase.competition }}</td>
<td>{{ submission.pk }}</td>
<td>{{ submission.owner.username }}</td>
<td>{{ submission.worker_hostname }}</td>
<td>{{ submission.created_when|timesince }} ago</td>
<td>{{ submission.status }}</td>
</tr>
Expand Down