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
135 changes: 95 additions & 40 deletions Campaign/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
from Campaign.models import CampaignTeam
from Campaign.models import TrustedUser
from EvalData.admin import BaseMetadataAdmin

from django.http import HttpResponse
import csv
import zipfile
from io import StringIO
import importlib

class DropdownFilter(AllValuesFieldListFilter):
"""
Experimental dropdown filter.
"""

template = 'Campaign/filter_select.html'
template = "Campaign/filter_select.html"


class CampaignTeamAdmin(BaseMetadataAdmin):
Expand All @@ -27,33 +31,33 @@ class CampaignTeamAdmin(BaseMetadataAdmin):
"""

list_display = [
'teamName',
'owner',
'teamMembers',
'requiredAnnotations',
'requiredHours',
'completionStatus',
"teamName",
"owner",
"teamMembers",
"requiredAnnotations",
"requiredHours",
"completionStatus",
] + BaseMetadataAdmin.list_display # type: ignore
list_filter = ['owner'] + BaseMetadataAdmin.list_filter # type: ignore
list_filter = ["owner"] + BaseMetadataAdmin.list_filter # type: ignore
search_fields = [
'teamName',
'owner__username',
'owner__first_name',
'owner__last_name',
"teamName",
"owner__username",
"owner__first_name",
"owner__last_name",
] + BaseMetadataAdmin.search_fields # type: ignore

filter_horizontal = ['members']
filter_horizontal = ["members"]

fieldsets = (
(
None,
{
'fields': (
'teamName',
'owner',
'members',
'requiredAnnotations',
'requiredHours',
"fields": (
"teamName",
"owner",
"members",
"requiredAnnotations",
"requiredHours",
)
},
),
Expand All @@ -66,22 +70,22 @@ class CampaignDataAdmin(BaseMetadataAdmin):
"""

list_display = [
'dataName',
'market',
'metadata',
'dataValid',
'dataReady',
"dataName",
"market",
"metadata",
"dataValid",
"dataReady",
] + BaseMetadataAdmin.list_display # type: ignore
list_filter = [
'dataValid',
'dataReady',
"dataValid",
"dataReady",
] + BaseMetadataAdmin.list_filter # type: ignore
search_fields = [
# nothing model specific
] + BaseMetadataAdmin.search_fields # type: ignore

fieldsets = (
(None, {'fields': ('dataFile', 'market', 'metadata')}),
(None, {"fields": ("dataFile", "market", "metadata")}),
) + BaseMetadataAdmin.fieldsets # type: ignore


Expand All @@ -90,47 +94,98 @@ class CampaignAdmin(BaseMetadataAdmin):
Model admin for Campaign instances.
"""

list_display = ['campaignName'] + BaseMetadataAdmin.list_display + ['id'] # type: ignore
list_display = ["campaignName"] + \
BaseMetadataAdmin.list_display + ["id"] # type: ignore
list_filter = [
# nothing model specific
] + BaseMetadataAdmin.list_filter # type: ignore
search_fields = [
# nothing model specific
] + BaseMetadataAdmin.search_fields # type: ignore

filter_horizontal = ['batches']
filter_horizontal = ["batches"]

fieldsets = (
(
None,
{
'fields': (
'campaignName',
'packageFile',
'teams',
'batches',
'campaignOptions',
"fields": (
"campaignName",
"packageFile",
"teams",
"batches",
"campaignOptions",
)
},
),
) + BaseMetadataAdmin.fieldsets # type: ignore


actions = ["export_results"]

def _retrieve_csv(self, current_campaign):
# Get the task type corresponding to the campaign
qs_name = current_campaign.get_campaign_type().lower()
qs_attr = "evaldata_{0}_campaign".format(qs_name)
qs_obj = getattr(current_campaign, qs_attr, None)
cls = type(qs_obj.all()[0])
cls_name = cls.__name__
cls_name = cls_name.replace("Task", "Result")
module = importlib.import_module(cls.__module__)
cls = getattr(module, cls_name)

# Now get the content
f = StringIO()
writer = csv.writer(f)
csv_content = cls.get_system_data(current_campaign.id, extended_csv=True)
for r in csv_content:
writer.writerow(r)

f.seek(0)
return f


def export_results(self, request, queryset):
if len(queryset) == 1:
current_campaign = queryset[0]
csv_content = self._retrieve_csv(current_campaign)
filename = f"results_{current_campaign.campaignName}.csv"
response = HttpResponse(csv_content, content_type="text/csv")
response["Content-Disposition"] = f"attachment; filename={filename}"
else:
response = HttpResponse(content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="campaign_results.zip"'

# Create a zip file with selected objects
with zipfile.ZipFile(response, 'w') as zipf:
for current_campaign in queryset:

csv_content = self._retrieve_csv(current_campaign)
# Add objects to the zip file, customize as per your model's data
# For example, you can add an object's name and description to a text file in the zip
filename = f"results_{current_campaign.campaignName}.csv"
zipf.writestr(filename, csv_content.getvalue())
return response

export_results.short_description = "Download results"



class TrustedUserAdmin(admin.ModelAdmin):
"""
Model admin for Campaign instances.
"""

list_display = ['user', 'campaign']
list_display = ["user", "campaign"]
list_filter = [
('campaign__campaignName', DropdownFilter),
# 'campaign'
("campaign__campaignName", DropdownFilter),
# "campaign"
]
search_fields = [ # type: ignore
# nothing model specific
]

fieldsets = ((None, {'fields': ('user', 'campaign')}),)
fieldsets = ((None, {"fields": ("user", "campaign")}),)


admin.site.register(CampaignTeam, CampaignTeamAdmin)
Expand Down
30 changes: 15 additions & 15 deletions Campaign/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,15 @@ def campaign_status_esa(campaign) -> str:
"""
out_str += f"<h1>{campaign.campaignName}</h1>\n"
out_str += "<table>\n"
out_str += "<tr>" + "".join(
f"<th>{x}</th>" for x in ["Username", "Progress", "First Modified", "Last Modified", "Time (Last-First)", "Time (Real)"]
) + "</tr>\n"

out_str += """<tr>
<th>Username</th>
<th>Progress</th>
<th>First Modified</th>
<th>Last Modified</th>
<th style="cursor: pointer" title="Very coarse upper bound estimate between the last and the first interaction with the system.">Time (Coarse ❔)</th>
<th style="cursor: pointer" title="Sum of times between any two interactions that are not longer than 10 minutes.">Time (Real ❔)</th>
</tr>\n
"""
for team in campaign.teams.all():
for user in team.members.all():
if user.is_staff:
Expand Down Expand Up @@ -298,6 +303,7 @@ def campaign_status_esa(campaign) -> str:
_data = DirectAssessmentDocumentResult.objects.filter(
createdBy=user, completed=True, task__campaign=campaign.id
)
_data_uniq_len = len({item.id for item in _data})

# If no data, show 0 progress or show that no task is assigned
if not _data:
Expand Down Expand Up @@ -331,11 +337,11 @@ def campaign_status_esa(campaign) -> str:
continue

total_count = task.items.count()
if total_count == len(_data):
if total_count == _data_uniq_len:
out_str += f"<td>{user.username} ✅</td>"
else:
out_str += f"<td>{user.username} 🛠️</td>"
out_str += f"<td>{len(_data)}/{total_count} ({len(_data) / total_count:.0%})</td>"
out_str += f"<td>{_data_uniq_len}/{total_count} ({_data_uniq_len / total_count:.0%})</td>"
first_modified = min([x.start_time for x in _data])
last_modified = max([x.end_time for x in _data])

Expand All @@ -351,15 +357,9 @@ def campaign_status_esa(campaign) -> str:
annotation_time_upper = f'{int(floor(annotation_time_upper / 3600)):0>2d}h {int(floor((annotation_time_upper % 3600) / 60)):0>2d}m'
out_str += f"<td>{annotation_time_upper}</td>"

times = collections.defaultdict(list)
for item in _data:
times[(item.item.documentID, item.item.targetID)].append((item.start_time, item.end_time))
times = [
(min([x[0] for x in doc_v]), max([x[1] for x in doc_v]))
for doc, doc_v in times.items()
]

annotation_time = sum([b-a for a, b in times])
# consider time that's in any action within 10 minutes
times = sorted([item.start_time for item in _data] + [item.end_time for item in _data])
annotation_time = sum([b-a for a, b in zip(times, times[1:]) if (b-a) < 10*60])
annotation_time = f'{int(floor(annotation_time / 3600)):0>2d}h {int(floor((annotation_time % 3600) / 60)):0>2d}m'

out_str += f"<td>{annotation_time}</td>"
Expand Down
7 changes: 2 additions & 5 deletions EvalData/models/data_assessment.py
Original file line number Diff line number Diff line change
Expand Up @@ -890,18 +890,15 @@ def get_system_data(
for result in qs.values_list(*attributes_to_extract):
user_id = result[0]

_fixed_ids = result[1].replace('Transformer+R2L', 'Transformer_R2L')
_fixed_ids = _fixed_ids.replace('R2L+Back', 'R2L_Back')

if expand_multi_sys:
system_ids = _fixed_ids.split('+')
system_ids = result[1].split('+')

for system_id in system_ids:
data = (user_id,) + (system_id,) + result[2:]
system_data.append(data)

else:
system_id = _fixed_ids
system_id = result[1]
data = (user_id,) + (system_id,) + result[2:]
system_data.append(data)

Expand Down
7 changes: 2 additions & 5 deletions EvalData/models/direct_assessment.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,18 +751,15 @@ def get_system_data(
for result in qs.values_list(*attributes_to_extract):
user_id = result[0]

_fixed_ids = result[1].replace('Transformer+R2L', 'Transformer_R2L')
_fixed_ids = _fixed_ids.replace('R2L+Back', 'R2L_Back')

if expand_multi_sys:
system_ids = _fixed_ids.split('+')
system_ids = result[1].split('+')

for system_id in system_ids:
data = (user_id,) + (system_id,) + result[2:]
system_data.append(data)

else:
system_id = _fixed_ids
system_id = result[1]
data = (user_id,) + (system_id,) + result[2:]
system_data.append(data)

Expand Down
5 changes: 1 addition & 4 deletions EvalData/models/direct_assessment_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,11 +836,8 @@ def get_system_data(
for result in qs.values_list(*attributes_to_extract):
user_id = result[0]

_fixed_ids = result[1].replace('Transformer+R2L', 'Transformer_R2L')
_fixed_ids = _fixed_ids.replace('R2L+Back', 'R2L_Back')

if expand_multi_sys:
system_ids = _fixed_ids.split('+')
system_ids = result[1].split('+')

for system_id in system_ids:
data = (user_id,) + (system_id,) + result[2:]
Expand Down
Loading
Loading