mirror of
https://github.com/sartography/cr-connect-workflow.git
synced 2025-02-22 12:48:25 +00:00
Create a path to directly download the spreadsheet file (and avoid the weird dance on the front end of making an API call to get file data.)
Fixing pagination. Seems the front end uses a page_index that is 0 based, and sqlAlchemy prefers to start at 1.
This commit is contained in:
parent
a536a79e87
commit
2fc4b44ef3
@ -293,14 +293,21 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
- name : auth_token
|
||||
in : query
|
||||
required : true
|
||||
description : User Auth Toeken
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
operationId: crc.api.study.download_logs_for_study
|
||||
summary: Returns a csv file of logged events that occured within a study
|
||||
security: [] # Will verify manually with provided Auth Token.
|
||||
tags:
|
||||
- Studies
|
||||
responses:
|
||||
'200':
|
||||
description: Returns the csv file of logged events
|
||||
description: Returns the spreadsheet file of logged events
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
|
@ -2,7 +2,6 @@ from datetime import datetime
|
||||
|
||||
from flask import g, send_file
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from crc import session
|
||||
from crc.api.common import ApiError, ApiErrorSchema
|
||||
from crc.models.study import Study, StudyEventType, StudyModel, StudySchema, StudyForUpdateSchema, \
|
||||
@ -15,6 +14,7 @@ from crc.services.user_service import UserService
|
||||
from crc.services.workflow_processor import WorkflowProcessor
|
||||
from crc.services.workflow_service import WorkflowService
|
||||
from crc.services.workflow_spec_service import WorkflowSpecService
|
||||
from crc.api.user import verify_token
|
||||
|
||||
import io
|
||||
|
||||
@ -117,11 +117,16 @@ def get_study_associates(study_id):
|
||||
|
||||
def get_logs_for_study(study_id, body):
|
||||
task_log_query = TaskLogQuery(**body)
|
||||
task_log_query.study_id = study_id # Force the study id
|
||||
return TaskLogQuerySchema().dump(
|
||||
TaskLoggingService.get_logs_for_study_paginated(study_id, task_log_query))
|
||||
|
||||
|
||||
def download_logs_for_study(study_id):
|
||||
def download_logs_for_study(study_id, auth_token):
|
||||
# Download links incorporate an auth token in the request for direct download
|
||||
if not verify_token(auth_token):
|
||||
raise ApiError('not_authenticated', 'You need to include an authorization token in the URL with this')
|
||||
|
||||
title = f'Study {study_id}'
|
||||
logs, headers = TaskLoggingService.get_log_data_for_download(study_id)
|
||||
spreadsheet = SpreadsheetService.create_spreadsheet(logs, headers, title)
|
||||
|
@ -1,6 +1,10 @@
|
||||
import enum
|
||||
import urllib
|
||||
|
||||
import flask
|
||||
import marshmallow
|
||||
from flask import url_for
|
||||
from marshmallow.fields import Method
|
||||
|
||||
from crc import db, ma
|
||||
from crc.models.study import StudyModel
|
||||
@ -62,9 +66,10 @@ class TaskLogModelSchema(ma.Schema):
|
||||
class TaskLogQuery:
|
||||
"""Encapsulates the paginated queries and results when retrieving and filtering task logs over the
|
||||
API"""
|
||||
def __init__(self, code="", level="", user="", page=1, per_page=10,
|
||||
def __init__(self, study_id=None, code="", level="", user="", page=0, per_page=10,
|
||||
sort_column=None, sort_reverse=False, items=None,
|
||||
pages=0, total=0, has_next=False, has_prev=False):
|
||||
pages=0, total=0, has_next=False, has_prev=False, download_url=None):
|
||||
self.study_id = study_id # Filter on Study.
|
||||
self.code = code # Filter on code.
|
||||
self.level = level # Filter on level.
|
||||
self.user = user # Filter on user.
|
||||
@ -77,11 +82,12 @@ class TaskLogQuery:
|
||||
self.pages = pages
|
||||
self.has_next = False
|
||||
self.has_prev = False
|
||||
self.download_url = None
|
||||
|
||||
def update_from_sqlalchemy_paginator(self, paginator):
|
||||
"""Updates this with results that are returned from the paginator"""
|
||||
self.items = paginator.items
|
||||
self.page = paginator.page
|
||||
self.page = paginator.page - 1
|
||||
self.per_page = paginator.per_page
|
||||
self.pages = paginator.pages
|
||||
self.has_next = paginator.has_next
|
||||
@ -94,5 +100,18 @@ class TaskLogQuerySchema(ma.Schema):
|
||||
model = TaskLogModel
|
||||
fields = ["code", "level", "user",
|
||||
"page", "per_page", "sort_column", "sort_reverse", "items", "pages", "total",
|
||||
"has_next", "has_prev"]
|
||||
items = marshmallow.fields.List(marshmallow.fields.Nested(TaskLogModelSchema))
|
||||
"has_next", "has_prev", "download_url"]
|
||||
items = marshmallow.fields.List(marshmallow.fields.Nested(TaskLogModelSchema))
|
||||
download_url = Method("get_url")
|
||||
|
||||
def get_url(self, obj):
|
||||
token = 'not_available'
|
||||
if hasattr(obj, 'study_id') and obj.study_id is not None:
|
||||
file_url = url_for("/v1_0.crc_api_study_download_logs_for_study", study_id=obj.study_id, _external=True)
|
||||
if hasattr(flask.g, 'user'):
|
||||
token = flask.g.user.encode_auth_token()
|
||||
url = file_url + '?auth_token=' + urllib.parse.quote_plus(token)
|
||||
return url
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
@ -89,7 +89,7 @@ class TaskLoggingService(object):
|
||||
sort_column = desc(task_log_query.sort_column)
|
||||
else:
|
||||
sort_column = task_log_query.sort_column
|
||||
paginator = sql_query.order_by(sort_column).paginate(task_log_query.page, task_log_query.per_page,
|
||||
paginator = sql_query.order_by(sort_column).paginate(task_log_query.page + 1, task_log_query.per_page,
|
||||
error_out=False)
|
||||
task_log_query.update_from_sqlalchemy_paginator(paginator)
|
||||
return task_log_query
|
||||
|
@ -153,7 +153,7 @@ class TestTaskLogging(BaseTest):
|
||||
logs = TaskLoggingService().get_logs_for_study_paginated(study.id, TaskLogQuery(per_page=5))
|
||||
self.assertEqual(40, logs.total)
|
||||
self.assertEqual(5, len(logs.items), "I can limit results to 5")
|
||||
self.assertEqual(1, logs.page)
|
||||
self.assertEqual(0, logs.page)
|
||||
self.assertEqual(8, logs.pages)
|
||||
self.assertEqual(5, logs.per_page)
|
||||
self.assertEqual(True, logs.has_next)
|
||||
@ -165,4 +165,6 @@ class TestTaskLogging(BaseTest):
|
||||
|
||||
logs = TaskLoggingService.get_logs_for_study_paginated(study.id, TaskLogQuery(per_page=5, sort_column="level", sort_reverse=True))
|
||||
for i in range(0, 5):
|
||||
self.assertEqual('info', logs.items[i].level, "It is possible to sort on a column")
|
||||
self.assertEqual('info', logs.items[i].level, "It is possible to sort on a column")
|
||||
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
import json
|
||||
|
||||
from tests.base_test import BaseTest
|
||||
|
||||
from crc import session
|
||||
from crc.models.task_log import TaskLogModel
|
||||
from crc.models.task_log import TaskLogModel, TaskLogQuery, TaskLogQuerySchema
|
||||
from crc.models.user import UserModel
|
||||
|
||||
from openpyxl import load_workbook
|
||||
from io import BytesIO
|
||||
@ -40,10 +43,19 @@ class TestDownloadLogsForStudy(BaseTest):
|
||||
'message': 'This is a third message.'}
|
||||
self.add_log(study_id, workflow.id, task.name, 'empty_workflow', log_data)
|
||||
|
||||
rv = self.app.get(f'/v1.0/study/{study_id}/log/download',
|
||||
content_type="application/json",
|
||||
headers=self.logged_in_headers())
|
||||
# Run the query, which should include a 'download_url' link that we can click on.
|
||||
url = f'/v1.0/study/{workflow.study_id}/log'
|
||||
task_log_query = TaskLogQuery()
|
||||
user = session.query(UserModel).filter_by(uid=self.test_uid).first()
|
||||
rv = self.app.put(url, headers=self.logged_in_headers(user), content_type="application/json",
|
||||
data=TaskLogQuerySchema().dump(task_log_query))
|
||||
self.assert_success(rv)
|
||||
log_query = json.loads(rv.get_data(as_text=True))
|
||||
self.assertIsNotNone(log_query['download_url'])
|
||||
|
||||
# Use the provided link to get the file.
|
||||
rv = self.app.get(log_query['download_url'])
|
||||
self.assert_success(rv)
|
||||
wb = load_workbook(BytesIO(rv.data))
|
||||
ws = wb.active
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user