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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ If you wish to configure your own instance of Codabench platform, here are the i

```
$ cp .env_sample .env
$ docker-compose up -d
$ docker-compose exec django ./manage.py migrate
$ docker-compose exec django ./manage.py generate_data
$ docker-compose exec django ./manage.py collectstatic --noinput
$ docker compose up -d
$ docker compose exec django ./manage.py migrate
$ docker compose exec django ./manage.py generate_data
$ docker compose exec django ./manage.py collectstatic --noinput
```

You can now login as username "admin" with password "admin" at http://localhost/
Expand Down
6 changes: 3 additions & 3 deletions src/apps/api/views/submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,18 +312,18 @@ def re_run_many_submissions(self, request):
submission.re_run()
return Response({})

# New methods impleted!
@action(detail=False, methods=['get'])
def download_many(self, request):
pks = request.query_params.get('pks')
if pks:
pks = json.loads(pks) # Convert JSON string to list

# Doing a local import here to avoid circular imports
from competitions.tasks import stream_batch_download
# Call the task and get the result (stream)

# in_memory_zip = stream_batch_download.apply_async((pks,)).get()
in_memory_zip = stream_batch_download(pks)
# Stream the response

response = StreamingHttpResponse(in_memory_zip, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="bulk_submissions.zip"'
return response
Expand Down
17 changes: 17 additions & 0 deletions src/apps/api/views/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,26 @@ def get_serializer_context(self):
return context

def update(self, request, *args, **kwargs):

# Get task
task = self.get_object()

# Raise error if user is not the creator of the task or not a super user
if request.user != task.created_by and not request.user.is_superuser:
raise PermissionDenied("Cannot update a task that is not yours")

# If the key is not in the request data, set the corresponding field to None
# No condition for scoring program because a task must have a scoring program
if "ingestion_program" not in request.data:
task.ingestion_program = None
if "input_data" not in request.data:
task.input_data = None
if "reference_data" not in request.data:
task.reference_data = None

# Save the task to apply the changes
task.save()

return super().update(request, *args, **kwargs)

def destroy(self, request, *args, **kwargs):
Expand Down
7 changes: 1 addition & 6 deletions src/apps/competitions/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,10 @@ def retrieve_data(url, data=None):

def zip_generator(submission_pks):
in_memory_zip = BytesIO()
# logger.info("IN zip generator")
with zipfile.ZipFile(in_memory_zip, 'w', zipfile.ZIP_DEFLATED) as zip_file:
for submission_id in submission_pks:
submission = Submission.objects.get(id=submission_id)
# logger.info(submission.data.data_file)

short_name = submission.data.data_file.name.split('/')[-1]
short_name = "ID_" + str(submission_id) + '_' + submission.data.data_file.name.split('/')[-1]
url = make_url_sassy(path=submission.data.data_file.name)
for block in retrieve_data(url):
zip_file.writestr(short_name, block)
Expand All @@ -310,8 +307,6 @@ def zip_generator(submission_pks):

@app.task(queue='site-worker', soft_time_limit=60 * 60)
def stream_batch_download(submission_pks):
# logger.info("In stream_batch_download")
# logger.info(submission_pks)
return zip_generator(submission_pks)


Expand Down
1 change: 1 addition & 0 deletions src/apps/pages/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
path('search', views.SearchView.as_view(), name="search"),
path('organize', views.OrganizeView.as_view(), name="organize"),
path('server_status', views.ServerStatusView.as_view(), name="server_status"),
path('monitor_queues', views.MonitorQueuesView.as_view(), name="monitor_queues"),
# path('test', views.CompetitionListTestView.as_view()),
]
29 changes: 23 additions & 6 deletions src/apps/pages/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from datetime import timedelta
from django.utils.timezone import now
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.views.generic import TemplateView
from django.db.models import Count, Q

Expand Down Expand Up @@ -55,6 +54,8 @@ class ServerStatusView(TemplateView):
def get_context_data(self, *args, **kwargs):

show_child_submissions = self.request.GET.get('show_child_submissions', False)
page = self.request.GET.get('page', 1)
submissions_per_page = 50

# Get all submissions
qs = Submission.objects.all()
Expand All @@ -73,18 +74,27 @@ def get_context_data(self, *args, **kwargs):
else:
qs = qs.none() # This returns an empty queryset

# Filter for fetching last 2 days submissions
qs = qs.filter(created_when__gte=now() - timedelta(days=2))

# Filter out child submissions i.e. submission has no parent
if not show_child_submissions:
qs = qs.filter(parent__isnull=True)

qs = qs.order_by('-created_when')
qs = qs.select_related('phase__competition', 'owner')

# Paginate the queryset
paginator = Paginator(qs, submissions_per_page)

try:
submissions = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver the first page.
submissions = paginator.page(1)
except EmptyPage:
# If page is out of range, deliver last page of results.
submissions = paginator.page(paginator.num_pages)

context = super().get_context_data(*args, **kwargs)
context['submissions'] = qs[:250]
context['submissions'] = submissions
context['show_child_submissions'] = show_child_submissions

for submission in context['submissions']:
Expand All @@ -103,6 +113,9 @@ def get_context_data(self, *args, **kwargs):
# Add submission owner display name
submission.owner_display_name = submission.owner.display_name if submission.owner.display_name else submission.owner.username

context['paginator'] = paginator
context['is_paginated'] = paginator.num_pages > 1

return context

def format_file_size(self, file_size):
Expand All @@ -123,6 +136,10 @@ def format_file_size(self, file_size):
return f"{n:.1f} {units[i]}"


class MonitorQueuesView(TemplateView):
template_name = 'pages/monitor_queues.html'


def page_not_found_view(request, exception):
print(request)
return render(request, '404.html', status=404)
37 changes: 31 additions & 6 deletions src/static/riot/tasks/management.tag
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@
<label>Scoring Program</label>
<div class="ui fluid left icon labeled input search dataset" data-name="scoring_program">
<i class="search icon"></i>
<input type="text" class="prompt" id="editscoring_program" value="{selected_task.scoring_program?.name || ''}">
<input type="text" class="prompt" id="edit_scoring_program" value="{selected_task.scoring_program?.name || ''}" name="edit_scoring_program">
<div class="results"></div>
</div>
</div>
Expand All @@ -283,7 +283,7 @@
<label>Ingestion Program</label>
<div class="ui fluid left icon labeled input search dataset" data-name="ingestion_program">
<i class="search icon"></i>
<input type="text" class="prompt" id="edit_ingestion_program" value="{selected_task.ingestion_program?.name || ''}">
<input type="text" class="prompt" id="edit_ingestion_program" value="{selected_task.ingestion_program?.name || ''}" name="edit_ingestion_program">
<div class="results"></div>
</div>
</div>
Expand All @@ -294,7 +294,7 @@
<label>Reference Data</label>
<div class="ui fluid left icon labeled input search dataset" data-name="reference_data">
<i class="search icon"></i>
<input type="text" class="prompt" id="edit_reference_data" value="{selected_task.reference_data?.name || ''}">
<input type="text" class="prompt" id="edit_reference_data" value="{selected_task.reference_data?.name || ''}" name="edit_reference_data">
<div class="results"></div>
</div>
</div>
Expand All @@ -303,7 +303,7 @@
<label>Input Data</label>
<div class="ui fluid left icon labeled input search dataset" data-name="input_data">
<i class="search icon"></i>
<input type="text" class="prompt" id="edit_input_data" value="{selected_task.input_data?.name || ''}">
<input type="text" class="prompt" id="edit_input_data" value="{selected_task.input_data?.name || ''}" name="edit_input_data">
<div class="results"></div>
</div>
</div>
Expand Down Expand Up @@ -540,7 +540,7 @@
}

self.edit_form_updated = () => {
self.edit_modal_is_valid = $(self.refs.edit_name).val() && $(self.refs.edit_description).val() && self.form_datasets.scoring_program
self.edit_modal_is_valid = $(self.refs.edit_name).val() && $(self.refs.edit_description).val()
self.update()
}

Expand All @@ -555,17 +555,42 @@
self.edit_modal_is_valid = false
}
self.update_task = () => {
// Get filled data from the edit fom
let data = get_form_data($(self.refs.edit_form))

// Show error when there is no scoring program in the task
if(data.edit_scoring_program == ""){
toastr.error('Scoring program is required in a task!')
return
}

// replace property names in the data object
data.name = data.edit_name;
data.description = data.edit_description;

// If ingestion program is not removed, add the new ingestion program from form_datasets to data
if(data.edit_ingestion_program != ""){
data.ingestion_program = self.form_datasets.ingestion_program
}
// If input data is not removed, add the new input data from form_datasets to data
if(data.edit_input_data != ""){
data.input_data = self.form_datasets.input_data
}
// If reference data is not removed, add the new reference data from form_datasets to data
if(data.edit_reference_data != ""){
data.reference_data = self.form_datasets.reference_data
}
// add the new scoring from form_datasets to data
data.scoring_program = self.form_datasets.scoring_program

// delete the old property names
delete data.edit_name
delete data.edit_description
delete data.edit_ingestion_program
delete data.edit_scoring_program
delete data.edit_input_data
delete data.edit_reference_data

_.assign(data, self.form_datasets)
task_id = self.selected_task.id
CODALAB.api.update_task(task_id, data)
.done((response) => {
Expand Down
1 change: 1 addition & 0 deletions src/static/stylus/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
@import "src/static/stylus/simple_page.styl"
@import "src/static/stylus/toastr.styl"
@import "src/static/stylus/forum.styl"
@import "src/static/stylus/server_status.styl"

19 changes: 19 additions & 0 deletions src/static/stylus/server_status.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.pagination-nav
padding 10px 0
width 100%
margin-bottom 20px
display flex
justify-content center
align-items center
position relative

.float-left
position absolute
left 0

.float-right
position absolute
right 0

.center
text-align center
1 change: 1 addition & 0 deletions src/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
{# <a class="item" href="#">Customize Codalab</a>#}
<a class="item" href="{% url "pages:server_status" %}">Server Status</a>
{% if request.user.is_staff %}
<a class="item" href="{% url "pages:monitor_queues" %}">Monitor Queues</a>
<a class="item" href="{% url "admin:index" %}">Django Admin</a>
<a class="item" href="{% url "su_login" %}">Change User</a>
<a class="item" href="{% url "analytics:analytics" %}">Analytics</a>
Expand Down
11 changes: 8 additions & 3 deletions src/templates/emails/base_email.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
background-color: #ffffff;
}
.header_img {
width: 40%;
width: 100%;
height: 100%;
object-fit: contain;
box-sizing: border-box;
}
.header {
width: 100%;
Expand All @@ -31,6 +34,8 @@
justify-content: center;
align-items: center;
margin-bottom: 10px;
padding: 10px;
box-sizing: border-box;
}
.content{
padding: 20px;
Expand Down Expand Up @@ -105,13 +110,13 @@ <h3>Hello{% if user %} {{ user.username }}{% endif %},</h3>
<p>Thanks,</p>
<p>Codabench Team</p>
<div class = "header">
<img class = "header_img" src = "../../static/img/codabench.png" alt = "codabench_logo" />
<img class = "header_img" src = "https://www.codabench.org/static/img/codabench.png" alt = "Codabench Logo" />
</div>
</div>
{% endif %}
</div>
<div id="footer">
<p><a href="http://{{ site.domain }}">Unsubscribe or manage notification settings</a> | <a href="https://github.com/codalab/codalab-competitions/wiki/Privacy">Privacy policy</a></p>
<p><a href="https://github.com/codalab/codalab-competitions/wiki/Privacy">Privacy policy</a></p>
</div>
</div>
</body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{% extends 'emails/base_email.html' %}

{% block content %}
<p>We're writing to inform you that user {{ participant.user.username }} has been accepted into your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.You can manage all participants from the admin panel of your competition.</p>
<p>
User <strong>{{ participant.user.username }}</strong> has been accepted into your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.
<br>
You can manage all participants from the admin panel of your competition.
</p>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{% extends 'emails/base_email.html' %}

{% block content %}
<p>We're writing to inform you that user {{ participant.user.username }} has been accepted into your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.You can manage all participants from the admin panel of your competition.</p>
<p>
User <strong>{{ participant.user.username }}</strong> has been accepted into your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.
<br>
You can manage all participants from the admin panel of your competition.
</p>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{% extends 'emails/base_email.html' %}

{% block content %}
<p>We're writing to inform you that user {{ participant.user.username }} has been denied to your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.You can manage all participants from the admin panel of your competition.</p>
<p>
A user <strong>{{ participant.user.username }}</strong> has been denied access to your competition.
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.
<br>
You can manage all participants from the admin panel of your competition.
</p>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{% extends 'emails/base_email.html' %}

{% block content %}
<p>We're writing to inform you that user {{ participant.user.username }} has been denied to your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.You can manage all participants from the admin panel of your competition.</p>
<p>
A user <strong>{{ participant.user.username }}</strong> has been denied access to your competition.
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.
<br>
You can manage all participants from the admin panel of your competition.
</p>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{% extends 'emails/base_email.html' %}

{% block content %}
<p>We're writing to inform you that user {{ participant.user.username }} has requested access to your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.You can manage all participants from the admin panel of your competition.</p>
<p>
A user <strong>{{ participant.user.username }}</strong> has requested access to your competition
<a href="http://{{ site.domain }}{{ participant.competition.get_absolute_url }}">{{ participant.competition.title }}</a>.
<br>
You can manage all participants from the admin panel of your competition.
</p>
{% endblock %}
Loading