Merge pull request #376 from sartography/bug/468_missing_file_date

fixes #448 - Missing  file date
This commit is contained in:
Dan Funk 2021-09-22 15:29:32 -04:00 committed by GitHub
commit deff293fff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 41 deletions

View File

@ -1,13 +1,15 @@
import enum import enum
import urllib
import flask
from marshmallow import INCLUDE, EXCLUDE, Schema from marshmallow import INCLUDE, EXCLUDE, Schema
from marshmallow.fields import Method
from marshmallow_enum import EnumField from marshmallow_enum import EnumField
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from sqlalchemy import func, Index from sqlalchemy import func, Index
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import deferred, relationship from sqlalchemy.orm import deferred, relationship
from crc import db, ma from crc import db, ma, app
from crc.models.data_store import DataStoreModel from crc.models.data_store import DataStoreModel
@ -144,9 +146,17 @@ class FileSchema(Schema):
fields = ["id", "name", "is_status", "is_reference", "content_type", fields = ["id", "name", "is_status", "is_reference", "content_type",
"primary", "primary_process_id", "workflow_spec_id", "workflow_id", "primary", "primary_process_id", "workflow_spec_id", "workflow_id",
"irb_doc_code", "last_modified", "latest_version", "type", "size", "data_store", "irb_doc_code", "last_modified", "latest_version", "type", "size", "data_store",
"document", "user_uid"] "document", "user_uid", "url"]
unknown = INCLUDE unknown = INCLUDE
type = EnumField(FileType) type = EnumField(FileType)
url = Method("get_url")
def get_url(self, obj):
token = 'not_available'
if hasattr(flask.g, 'user'):
token = flask.g.user.encode_auth_token()
return (app.config['APPLICATION_ROOT'] + 'file/' +
str(obj.id) + '/download?auth_token=' + urllib.parse.quote_plus(token))
class LookupFileModel(db.Model): class LookupFileModel(db.Model):

View File

@ -14,7 +14,7 @@ from crc import db, session, app
from crc.api.common import ApiError from crc.api.common import ApiError
from crc.models.data_store import DataStoreModel from crc.models.data_store import DataStoreModel
from crc.models.email import EmailModel from crc.models.email import EmailModel
from crc.models.file import FileModel, File from crc.models.file import FileModel, File, FileSchema
from crc.models.ldap import LdapSchema from crc.models.ldap import LdapSchema
from crc.models.protocol_builder import ProtocolBuilderStudy, ProtocolBuilderStatus from crc.models.protocol_builder import ProtocolBuilderStudy, ProtocolBuilderStatus
@ -294,15 +294,10 @@ class StudyService(object):
token = 'not_available' token = 'not_available'
if hasattr(flask.g, 'user'): if hasattr(flask.g, 'user'):
token = flask.g.user.encode_auth_token() token = flask.g.user.encode_auth_token()
for file in doc_files: for file_model in doc_files:
file_data = {'file_id': file.id, file = File.from_models(file_model, FileService.get_file_data(file_model.id), [])
'name': file.name, file_data = FileSchema().dump(file)
'url': app.config['APPLICATION_ROOT'] + del file_data['document']
'file/' + str(file.id) +
'/download?auth_token=' +
urllib.parse.quote_plus(token),
'workflow_id': file.workflow_id
}
data = db.session.query(DataStoreModel).filter(DataStoreModel.file_id == file.id).all() data = db.session.query(DataStoreModel).filter(DataStoreModel.file_id == file.id).all()
data_store_data = {} data_store_data = {}
for d in data: for d in data:

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1j7idla" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.0"> <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1j7idla" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.10.0">
<bpmn:process id="Process_18biih5" isExecutable="true"> <bpmn:process id="Process_18biih5" isExecutable="true">
<bpmn:startEvent id="StartEvent_1"> <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_1pnq3kg</bpmn:outgoing> <bpmn:outgoing>SequenceFlow_1pnq3kg</bpmn:outgoing>
@ -16,7 +16,7 @@
<bpmn:outgoing>Flow_0z7kamo</bpmn:outgoing> <bpmn:outgoing>Flow_0z7kamo</bpmn:outgoing>
<bpmn:script>filelist = list(documents.keys()) <bpmn:script>filelist = list(documents.keys())
fileid = documents['UVACompl_PRCAppr'].files[0]['file_id'] fileid = documents['UVACompl_PRCAppr'].files[0]['id']
fileurl = documents['UVACompl_PRCAppr'].files[0]['url'] fileurl = documents['UVACompl_PRCAppr'].files[0]['url']
@ -43,6 +43,22 @@ file_data_set(file_id=fileid,key='test',value='me')</bpmn:script>
</bpmn:process> </bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_18biih5"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_18biih5">
<bpmndi:BPMNEdge id="Flow_02bgcrp_di" bpmnElement="Flow_02bgcrp">
<di:waypoint x="860" y="117" />
<di:waypoint x="962" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_15mmymi_di" bpmnElement="Flow_15mmymi">
<di:waypoint x="690" y="117" />
<di:waypoint x="760" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0z7kamo_di" bpmnElement="Flow_0z7kamo">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xqewuk_di" bpmnElement="Flow_1xqewuk">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="SequenceFlow_1pnq3kg_di" bpmnElement="SequenceFlow_1pnq3kg"> <bpmndi:BPMNEdge id="SequenceFlow_1pnq3kg_di" bpmnElement="SequenceFlow_1pnq3kg">
<di:waypoint x="215" y="117" /> <di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" /> <di:waypoint x="270" y="117" />
@ -53,34 +69,18 @@ file_data_set(file_id=fileid,key='test',value='me')</bpmn:script>
<bpmndi:BPMNShape id="Activity_01ekdl8_di" bpmnElement="Task_Has_Bananas"> <bpmndi:BPMNShape id="Activity_01ekdl8_di" bpmnElement="Task_Has_Bananas">
<dc:Bounds x="270" y="77" width="100" height="80" /> <dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1xqewuk_di" bpmnElement="Flow_1xqewuk">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Activity_0g5namy_di" bpmnElement="Activity_0yikdu7"> <bpmndi:BPMNShape id="Activity_0g5namy_di" bpmnElement="Activity_0yikdu7">
<dc:Bounds x="430" y="77" width="100" height="80" /> <dc:Bounds x="430" y="77" width="100" height="80" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1pdyoyv_di" bpmnElement="Event_1pdyoyv"> <bpmndi:BPMNShape id="Event_1pdyoyv_di" bpmnElement="Event_1pdyoyv">
<dc:Bounds x="962" y="99" width="36" height="36" /> <dc:Bounds x="962" y="99" width="36" height="36" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0z7kamo_di" bpmnElement="Flow_0z7kamo">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_15mmymi_di" bpmnElement="Flow_15mmymi">
<di:waypoint x="690" y="117" />
<di:waypoint x="760" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Activity_0ma7ela_di" bpmnElement="Activity_19x6e2e"> <bpmndi:BPMNShape id="Activity_0ma7ela_di" bpmnElement="Activity_19x6e2e">
<dc:Bounds x="590" y="77" width="100" height="80" /> <dc:Bounds x="590" y="77" width="100" height="80" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0oaeqxs_di" bpmnElement="Activity_0oaeqxs"> <bpmndi:BPMNShape id="Activity_0oaeqxs_di" bpmnElement="Activity_0oaeqxs">
<dc:Bounds x="760" y="77" width="100" height="80" /> <dc:Bounds x="760" y="77" width="100" height="80" />
</bpmndi:BPMNShape> </bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_02bgcrp_di" bpmnElement="Flow_02bgcrp">
<di:waypoint x="860" y="117" />
<di:waypoint x="962" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane> </bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram> </bpmndi:BPMNDiagram>
</bpmn:definitions> </bpmn:definitions>

View File

@ -156,7 +156,7 @@ class TestStudyService(BaseTest):
self.assertEqual("not_started", docs["UVACompl_PRCAppr"]['status']) self.assertEqual("not_started", docs["UVACompl_PRCAppr"]['status'])
self.assertEqual(1, docs["UVACompl_PRCAppr"]['count']) self.assertEqual(1, docs["UVACompl_PRCAppr"]['count'])
self.assertIsNotNone(docs["UVACompl_PRCAppr"]['files'][0]) self.assertIsNotNone(docs["UVACompl_PRCAppr"]['files'][0])
self.assertIsNotNone(docs["UVACompl_PRCAppr"]['files'][0]['file_id']) self.assertIsNotNone(docs["UVACompl_PRCAppr"]['files'][0]['id'])
self.assertEqual(workflow.id, docs["UVACompl_PRCAppr"]['files'][0]['workflow_id']) self.assertEqual(workflow.id, docs["UVACompl_PRCAppr"]['files'][0]['workflow_id'])
def test_get_all_studies(self): def test_get_all_studies(self):

View File

@ -1,3 +1,6 @@
import io
import json
from tests.base_test import BaseTest from tests.base_test import BaseTest
from crc.scripts.study_info import StudyInfo from crc.scripts.study_info import StudyInfo
from crc import app from crc import app
@ -13,15 +16,15 @@ class TestStudyInfoScript(BaseTest):
def do_work(self, info_type): def do_work(self, info_type):
app.config['PB_ENABLED'] = True app.config['PB_ENABLED'] = True
self.load_example_data() self.load_example_data()
workflow = self.create_workflow('study_info_script') self.workflow = self.create_workflow('study_info_script')
workflow_api = self.get_workflow_api(workflow) self.workflow_api = self.get_workflow_api(self.workflow)
# grab study_info directly from script # grab study_info directly from script
study_info = StudyInfo().do_task(workflow_api.study_id, workflow.study.id, workflow.id, info_type) study_info = StudyInfo().do_task(self.workflow_api.study_id, self.workflow.study.id, self.workflow.id, info_type)
# grab study info through a workflow # grab study info through a workflow
first_task = workflow_api.next_task first_task = self.workflow_api.next_task
self.complete_form(workflow, first_task, {'which': info_type}) self.complete_form(self.workflow, first_task, {'which': info_type})
workflow_api = self.get_workflow_api(workflow) workflow_api = self.get_workflow_api(self.workflow)
second_task = workflow_api.next_task second_task = workflow_api.next_task
return study_info, second_task return study_info, second_task
@ -81,9 +84,29 @@ class TestStudyInfoScript(BaseTest):
self.assertEqual(response['IND_2'], second_task.data['info']['IND_2']) self.assertEqual(response['IND_2'], second_task.data['info']['IND_2'])
self.assertEqual(response['IND_3'], second_task.data['info']['IND_3']) self.assertEqual(response['IND_3'], second_task.data['info']['IND_3'])
# def test_info_script_documents(self): def test_info_script_documents(self):
# study_info, second_task = self.do_work(info_type='documents') study_info, second_task = self.do_work(info_type='documents')
# self.assertEqual(study_info, second_task.data['info']) self.assertEqual(study_info, second_task.data['info'])
self.assertEqual(0, len(study_info['Grant_App']['files']), "Grant_App has not files yet.")
# Add a grant app file
data = {'file': (io.BytesIO(b"abcdef"), 'random_fact.svg')}
rv = self.app.post('/v1.0/file?study_id=%i&workflow_id=%s&task_spec_name=%s&form_field_key=%s' %
(self.workflow.study_id, self.workflow.id, second_task.name, 'Grant_App'), data=data, follow_redirects=True,
content_type='multipart/form-data', headers=self.logged_in_headers())
self.assert_success(rv)
file_data = json.loads(rv.get_data(as_text=True))
# Now get the study info again.
study_info = StudyInfo().do_task(self.workflow_api.study_id, self.workflow.study.id, self.workflow.id,
'documents')
# The data should contain a file.
self.assertEqual(1, len(study_info['Grant_App']['files']), "Grant_App has exactly one file.")
# This file data returned should be the same as what we get back about the file when we uploaded it,
# but the details on the document should be removed, because that would be recursive.
del file_data['document']
self.assertEqual(file_data, study_info['Grant_App']['files'][0])
@patch('crc.services.protocol_builder.requests.get') @patch('crc.services.protocol_builder.requests.get')
def test_info_script_sponsors(self, mock_get): def test_info_script_sponsors(self, mock_get):