Skip to content

Commit

Permalink
add api_format in get_objects(), update modify_time field (#2045)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Dec 11, 2024
1 parent db1ef94 commit 5a82dc6
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Added
- **Irodsbackend**
- Token auth support in ``BasicAuthView`` (#1999)
- Django checks for enabled authentication methods (#1999)
- ``api_format`` arg in ``get_objects()`` and ``get_objs_recursively()`` (#2045)
- REST API compatible date format support in ``get_objects()`` (#2045)
- **Irodsinfo**
- Alert on token usage for OIDC users (#1999)
- **Landingzones**
Expand Down
1 change: 1 addition & 0 deletions docs_manual/source/sodar_release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ REST API Updates
+ Return ``503`` if project is locked
* ``ProjectIrodsFileListAPIView``
+ Return results as list without ``irods_data`` object
+ Return ``modify_time`` field in standard REST API format
- Landing Zones API
* ``ZoneCreateAPIView``
+ Return ``503`` if Taskflow is not enabled
Expand Down
21 changes: 18 additions & 3 deletions irodsbackend/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,18 @@ def _init_irods(self):
raise ex

@classmethod
def _get_datetime(cls, naive_dt):
def _get_datetime(cls, naive_dt, api_format=False):
"""
Return a printable datetime in the system timezone from a naive
datetime object.
:param naive_dt: Naive DateTime object
:param api_format: Return in REST API format (bool, default=False)
"""
dt = naive_dt.replace(tzinfo=pytz.timezone('GMT'))
dt = dt.astimezone(timezone.get_default_timezone())
if api_format:
return dt.isoformat()
return dt.strftime('%Y-%m-%d %H:%M')

@classmethod
Expand Down Expand Up @@ -581,7 +586,13 @@ def get_colls_recursively(cls, coll):
return [iRODSCollection(coll.manager, row) for row in query]

def get_objs_recursively(
self, irods, coll, include_md5=False, name_like=None, limit=None
self,
irods,
coll,
include_md5=False,
name_like=None,
limit=None,
api_format=False,
):
"""
Return objects below a coll recursively. Replacement for the
Expand All @@ -593,6 +604,7 @@ def get_objs_recursively(
:param include_md5: if True, include .md5 files
:param name_like: Filtering of file names (string or list of strings)
:param limit: Limit retrieval to n rows (int)
:param api_format: Format data for REST API (bool, default=False)
:return: List
"""
ret = []
Expand Down Expand Up @@ -645,7 +657,7 @@ def _do_query(irods, nl=None):
'path': obj_path,
'size': row[DataObject.size],
'modify_time': self._get_datetime(
row[DataObject.modify_time]
row[DataObject.modify_time], api_format
),
}
)
Expand Down Expand Up @@ -683,6 +695,7 @@ def get_objects(
include_colls=False,
name_like=None,
limit=None,
api_format=False,
):
"""
Return a flat iRODS object list recursively under a given path.
Expand All @@ -693,6 +706,7 @@ def get_objects(
:param include_colls: Include collections (bool)
:param name_like: Filtering of file names (string or list of strings)
:param limit: Limit search to n rows (int)
:param api_format: Format data for REST API (bool, default=False)
:return: List
:raise: FileNotFoundError if collection is not found
"""
Expand All @@ -711,6 +725,7 @@ def get_objects(
include_md5=include_md5,
name_like=name_like,
limit=limit,
api_format=api_format,
)

# Add collections if enabled
Expand Down
36 changes: 33 additions & 3 deletions irodsbackend/tests/test_api_taskflow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for the API in the irodsbackend app with Taskflow and iRODS"""

import pytz
import random
import string

Expand Down Expand Up @@ -108,15 +109,20 @@ def test_get_objects(self):
self.assertIsNotNone(obj_list)
self.assertEqual(len(obj_list), 2)

obj = obj_list[0]
data_obj = self.irods.data_objects.get(path + '/' + TEST_FILE_NAME)
modify_time = (
data_obj.modify_time.replace(tzinfo=pytz.timezone('GMT'))
.astimezone(pytz.timezone(settings.TIME_ZONE))
.strftime('%Y-%m-%d %H:%M')
)
expected = {
'name': TEST_FILE_NAME,
'type': 'obj',
'path': path + '/' + TEST_FILE_NAME,
'size': 0,
'modify_time': obj['modify_time'],
'modify_time': modify_time,
}
self.assertEqual(obj, expected)
self.assertEqual(obj_list[0], expected)

def test_get_objects_with_colls(self):
"""Test get_objects() with collections included"""
Expand Down Expand Up @@ -228,6 +234,30 @@ def test_get_objects_limit(self):
self.assertIsNotNone(obj_list)
self.assertEqual(len(obj_list), 1) # Limited to 1

def test_get_objects_api_format(self):
"""Test get_objects() with api_format=True"""
self.make_irods_colls(self.investigation)
path = self.irods_backend.get_path(self.assay)
self.irods.data_objects.create(path + '/' + TEST_FILE_NAME)
obj_list = self.irods_backend.get_objects(
self.irods, path, api_format=True
)
self.assertEqual(len(obj_list), 1)
data_obj = self.irods.data_objects.get(path + '/' + TEST_FILE_NAME)
modify_time = (
data_obj.modify_time.replace(tzinfo=pytz.timezone('GMT'))
.astimezone(pytz.timezone(settings.TIME_ZONE))
.isoformat()
)
expected = {
'name': TEST_FILE_NAME,
'type': 'obj',
'path': path + '/' + TEST_FILE_NAME,
'size': 0,
'modify_time': modify_time,
}
self.assertEqual(obj_list[0], expected)

def test_issue_ticket(self):
"""Test issue_ticket()"""
self.make_irods_colls(self.investigation)
Expand Down
10 changes: 9 additions & 1 deletion samplesheets/tests/test_views_api_taskflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
import os
import pytz

from datetime import timedelta, datetime

Expand Down Expand Up @@ -1249,7 +1250,7 @@ def test_get_empty_collection(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, [])

def test_get_collection_with_files(self):
def test_get_files(self):
"""Test GET with files"""
# Set up iRODS collections
self.make_irods_colls(self.investigation)
Expand All @@ -1263,3 +1264,10 @@ def test_get_collection_with_files(self):
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['name'], IRODS_FILE_NAME)
self.assertEqual(response.data[0]['type'], 'obj')
data_obj = self.irods.data_objects.get(coll_path + '/' + 'test1.txt')
aware_dt = timezone.make_aware(
data_obj.modify_time, pytz.timezone('GMT')
)
self.assertEqual(
response.data[0]['modify_time'], self.get_drf_datetime(aware_dt)
)
6 changes: 4 additions & 2 deletions samplesheets/views_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ class ProjectIrodsFileListAPIView(
- ``type``: iRODS item type type (``obj`` for file)
- ``path``: Full path to file
- ``size``: Size in bytes
- ``modify_time``: Datetime of last modification (YYYY-MM-DD HH:MM)
- ``modify_time``: Datetime of last modification (YYYY-MM-DDThh:mm:ssZ)
"""

http_method_names = ['get']
Expand All @@ -951,7 +951,9 @@ def get(self, request, *args, **kwargs):
path = irods_backend.get_sample_path(project)
try:
with irods_backend.get_session() as irods:
obj_list = irods_backend.get_objects(irods, path)
obj_list = irods_backend.get_objects(
irods, path, api_format=True
)
except Exception as ex:
return Response(
{'detail': '{}: {}'.format(IRODS_QUERY_ERROR_MSG, ex)},
Expand Down

0 comments on commit 5a82dc6

Please sign in to comment.