diff --git a/frontend/src/Files.js b/frontend/src/Files.js
index 76ea9fb9d..4a53cf8c2 100644
--- a/frontend/src/Files.js
+++ b/frontend/src/Files.js
@@ -201,6 +201,7 @@ class DisplayFiles extends React.PureComponent {
const filter = this.props.filter;
this.refs.key.value = filter.key || "";
this.refs.size.value = filter.size || "";
+ this.refs.upload_type.value = filter.upload_type || "";
this.refs.created_at.value = filter.created_at || "";
this.refs.bucketName.value = filter.bucket_name || "";
}
@@ -209,6 +210,7 @@ class DisplayFiles extends React.PureComponent {
event.preventDefault();
const key = this.refs.key.value.trim();
const size = this.refs.size.value.trim();
+ const upload_type = this.refs.upload_type.value.trim();
const created_at = this.refs.created_at.value.trim();
const bucketName = this.refs.bucketName.value.trim();
this.props.updateFilter({
@@ -217,6 +219,7 @@ class DisplayFiles extends React.PureComponent {
size,
created_at,
bucket_name: bucketName,
+ upload_type: upload_type,
});
};
@@ -224,6 +227,7 @@ class DisplayFiles extends React.PureComponent {
this.refs.key.value = "";
this.refs.size.value = "";
this.refs.bucketName.value = "";
+ this.refs.upload_type.value = "";
this.refs.created_at.value = "";
this.submitForm(event);
};
@@ -238,6 +242,7 @@ class DisplayFiles extends React.PureComponent {
Key |
Size |
Bucket |
+ Upload type |
Uploaded |
Time to complete |
+
@@ -282,6 +288,15 @@ class DisplayFiles extends React.PureComponent {
style={{ width: 140 }}
/>
|
+
+
+
+
+ |
| {formatFileSize(file.size)} |
{file.bucket_name} |
+
+ {file.upload && file.upload.upload_type === "try" ? (
+
+ try
+
+ ) : (
+
+ {file.upload.upload_type}
+
+ )}
+ |
{file.upload ? (
)}{" "}
- {file.upload && file.upload.try_symbols ? (
-
- Try
-
- ) : null}
|
{BooleanIcon(file.update)} |
{BooleanIcon(file.compressed)} |
diff --git a/tecken/api/forms.py b/tecken/api/forms.py
index c466265be..2d4a8156f 100644
--- a/tecken/api/forms.py
+++ b/tecken/api/forms.py
@@ -209,6 +209,9 @@ class FileUploadsForm(UploadsForm):
size = forms.CharField(required=False)
created_at = forms.CharField(required=False)
completed_at = forms.CharField(required=False)
+ upload_type = forms.ChoiceField(
+ choices=[("", ""), ("try", "try"), ("regular", "regular")], required=False
+ )
key = forms.CharField(required=False)
update = forms.BooleanField(required=False)
compressed = forms.BooleanField(required=False)
diff --git a/tecken/api/views.py b/tecken/api/views.py
index 76e4eec23..91b9094fd 100644
--- a/tecken/api/views.py
+++ b/tecken/api/views.py
@@ -387,16 +387,19 @@ def _upload_files_build_qs(request):
form = forms.FileUploadsForm(request.GET)
if not form.is_valid():
return http.JsonResponse({"errors": form.errors}, status=400)
+
qs = FileUpload.objects.all()
for operator, value in form.cleaned_data["size"]:
orm_operator = "size__{}".format(ORM_OPERATORS[operator])
qs = qs.filter(**{orm_operator: value})
+
qs = filter_form_dates(qs, form, ("created_at", "completed_at"))
if form.cleaned_data.get("key"):
key_q = Q(key__icontains=form.cleaned_data["key"][0])
for other in form.cleaned_data["key"][1:]:
key_q &= Q(key__icontains=other)
qs = qs.filter(key_q)
+
include_bucket_names = []
for operator, bucket_name in form.cleaned_data["bucket_name"]:
if operator == "!":
@@ -405,6 +408,14 @@ def _upload_files_build_qs(request):
include_bucket_names.append(bucket_name)
if include_bucket_names:
qs = qs.filter(bucket_name__in=include_bucket_names)
+
+ if form.cleaned_data.get("upload_type", ""):
+ # NOTE(willkg): we have two upload types: try and regular. The try_symbols field
+ # is a boolean where try=True and regular=False, so we convert from a general
+ # upload types domain to the boolean domain of whether it's try upload or not.
+ # In the future, we may want to support other types by fixing the Upload model.
+ try_symbols = form.cleaned_data["upload_type"] == "try"
+ qs = qs.filter(upload__try_symbols=try_symbols)
return qs
@@ -455,6 +466,7 @@ def hydrate_upload(upload_id):
upload = uploads[upload_id]
uploads_cache[upload_id] = {
"id": upload.id,
+ "upload_type": "try" if upload.try_symbols else "regular",
"try_symbols": upload.try_symbols,
"user": {"id": upload.user.id, "email": upload.user.email},
"created_at": upload.created_at,
diff --git a/tecken/tests/test_api.py b/tecken/tests/test_api.py
index 7a1f931c2..9e202812b 100644
--- a/tecken/tests/test_api.py
+++ b/tecken/tests/test_api.py
@@ -852,6 +852,62 @@ def test_upload_files(client, settings):
assert [x["id"] for x in data["files"]] == [file_upload2.id]
+@pytest.mark.django_db
+def test_upload_files_filter_upload_type(client, settings):
+ url = reverse("api:upload_files")
+
+ user = User.objects.create(username="user1", email="user1@example.com")
+ user.set_password("secret")
+ user.save()
+ assert client.login(username="user1", password="secret")
+
+ permission = Permission.objects.get(codename="view_all_uploads")
+ user.user_permissions.add(permission)
+
+ # Create upload data
+ regular_upload = Upload.objects.create(user=user, size=123_456)
+ regular_file = FileUpload.objects.create(
+ upload=regular_upload,
+ size=1234,
+ bucket_name="symbols-public",
+ key="bar.pdb/46A0ADB3F299A70B4C4C44205044422E1/bar.sym",
+ )
+
+ try_upload = Upload.objects.create(user=user, size=123_456, try_symbols=True)
+ try_file = FileUpload.objects.create(
+ upload=try_upload,
+ size=100,
+ bucket_name="symbols-public",
+ key="v1/libxul.so/A772CC9A3E852CF48965ED79FB65E3150/libxul.so.sym",
+ )
+
+ # Request all files--should return both files
+ response = client.get(url)
+ assert response.status_code == 200
+ data = response.json()
+ assert data["files"]
+ all_ids = {regular_file.id, try_file.id}
+ assert {x["id"] for x in data["files"]} == all_ids
+
+ # Request upload_type=""--should return both files
+ response = client.get(url, {"upload_type": ""})
+ assert response.status_code == 200
+ data = response.json()
+ assert {x["id"] for x in data["files"]} == all_ids
+
+ # Request upload_type="try"--should return only try file
+ response = client.get(url, {"upload_type": "try"})
+ assert response.status_code == 200
+ data = response.json()
+ assert {x["id"] for x in data["files"]} == {try_file.id}
+
+ # Request upload_type="regular"--should return only regular file
+ response = client.get(url, {"upload_type": "regular"})
+ assert response.status_code == 200
+ data = response.json()
+ assert {x["id"] for x in data["files"]} == {regular_file.id}
+
+
@pytest.mark.django_db
def test_upload_files_count(client):
url = reverse("api:upload_files")
@@ -863,14 +919,23 @@ def test_upload_files_count(client):
assert client.login(username="user1", password="secret")
# Create data
- upload = Upload.objects.create(user=user, size=123_456)
- file_upload_1 = FileUpload.objects.create(
- upload=upload,
+ regular_upload = Upload.objects.create(user=user, size=123_456)
+ regular_file_upload = FileUpload.objects.create(
+ upload=regular_upload,
size=1234,
bucket_name="symbols-public",
- key="v1/bar.pdb/46A0ADB3F299A70B4C4C44205044422E1/bar.sym",
+ key="bar.pdb/46A0ADB3F299A70B4C4C44205044422E1/bar.sym",
+ )
+
+ try_upload = Upload.objects.create(user=user, size=123_456, try_symbols=True)
+ try_file_upload = FileUpload.objects.create(
+ upload=try_upload,
+ size=50,
+ bucket_name="symbols-public",
+ key="libxul.so/9B6C6BD630483C5F453471EE0EEEB09A0/libxul.so.sym",
)
- file_upload_2 = FileUpload.objects.create(
+
+ file_upload = FileUpload.objects.create(
size=100,
bucket_name="symbols-public",
key="libxul.so/A772CC9A3E852CF48965ED79FB65E3150/libxul.so.sym",
@@ -883,7 +948,7 @@ def test_upload_files_count(client):
data = response.json()
assert data["files"] == [
{
- "id": file_upload_2.id,
+ "id": file_upload.id,
"key": "libxul.so/A772CC9A3E852CF48965ED79FB65E3150/libxul.so.sym",
"update": False,
"compressed": True,
@@ -894,7 +959,24 @@ def test_upload_files_count(client):
"upload": None,
},
{
- "id": file_upload_1.id,
+ "bucket_name": "symbols-public",
+ "completed_at": None,
+ "compressed": False,
+ "created_at": ANY,
+ "id": try_file_upload.id,
+ "key": "libxul.so/9B6C6BD630483C5F453471EE0EEEB09A0/libxul.so.sym",
+ "size": 50,
+ "update": False,
+ "upload": {
+ "created_at": ANY,
+ "id": try_upload.id,
+ "try_symbols": True,
+ "upload_type": "try",
+ "user": {"id": user.id, "email": "user1@example.com"},
+ },
+ },
+ {
+ "id": regular_file_upload.id,
"key": "bar.pdb/46A0ADB3F299A70B4C4C44205044422E1/bar.sym",
"update": False,
"compressed": False,
@@ -903,8 +985,9 @@ def test_upload_files_count(client):
"completed_at": None,
"created_at": ANY,
"upload": {
- "id": upload.id,
+ "id": regular_upload.id,
"try_symbols": False,
+ "upload_type": "regular",
"user": {"id": user.id, "email": "user1@example.com"},
"created_at": ANY,
},
@@ -925,14 +1008,15 @@ def test_upload_files_count(client):
"completed_at": None,
"compressed": False,
"created_at": ANY,
- "id": file_upload_1.id,
+ "id": regular_file_upload.id,
"key": "bar.pdb/46A0ADB3F299A70B4C4C44205044422E1/bar.sym",
"size": 1234,
"update": False,
"upload": {
"created_at": ANY,
- "id": upload.id,
+ "id": regular_upload.id,
"try_symbols": False,
+ "upload_type": "regular",
"user": {
"email": "user1@example.com",
"id": user.id,