From 1d3f98b381730fdd3db4bca80dd1aba027dbd1d0 Mon Sep 17 00:00:00 2001 From: Aaron Louie Date: Fri, 5 Jun 2020 22:19:37 -0400 Subject: [PATCH] Adds endpoint to quickly get counts of approvals in each status group for a user --- crc/api.yml | 46 ++++++++++++++++++++++++++++++++++++- crc/api/approval.py | 55 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/crc/api.yml b/crc/api.yml index 638eb787..3a0875cc 100644 --- a/crc/api.yml +++ b/crc/api.yml @@ -806,12 +806,34 @@ paths: type: array items: $ref: "#/components/schemas/Script" + /approval-counts: + parameters: + - name: as_user + in: query + required: false + description: If provided, returns the approval counts for that user. + schema: + type: string + get: + operationId: crc.api.approval.get_approval_counts + summary: Provides counts for approvals by status for the given user, or all users if no user is provided + tags: + - Approvals + responses: + '200': + description: An dictionary of Approval Statuses and the counts for each + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ApprovalCounts" /approval: parameters: - name: status in: query required: false - description: If set to true, returns all the approvals with any status. + description: If provided, returns just approvals for the given status. schema: type: string - name: as_user @@ -1286,4 +1308,26 @@ components: type: number format: integer example: 5 + ApprovalCounts: + properties: + PENDING: + type: number + format: integer + example: 5 + APPROVED: + type: number + format: integer + example: 5 + DECLINED: + type: number + format: integer + example: 5 + CANCELED: + type: number + format: integer + example: 5 + AWAITING: + type: number + format: integer + example: 5 diff --git a/crc/api/approval.py b/crc/api/approval.py index b23315df..bc20c624 100644 --- a/crc/api/approval.py +++ b/crc/api/approval.py @@ -13,6 +13,56 @@ from crc.services.approval_service import ApprovalService from crc.services.ldap_service import LdapService +# Returns counts of approvals in each status group assigned to the given user. +# The goal is to return results as quickly as possible. +def get_approval_counts(as_user=None): + uid = as_user or g.user.uid + + db_user_approvals = db.session.query(ApprovalModel)\ + .filter_by(approver_uid=uid)\ + .filter(ApprovalModel.status != ApprovalStatus.CANCELED.name)\ + .all() + + study_ids = [a.study_id for a in db_user_approvals] + print('study_ids', study_ids) + + db_other_approvals = db.session.query(ApprovalModel)\ + .filter(ApprovalModel.study_id.in_(study_ids))\ + .filter(ApprovalModel.approver_uid != uid)\ + .filter(ApprovalModel.status != ApprovalStatus.CANCELED.name)\ + .all() + + # Make a dict of the other approvals where the key is the study id and the value is the approval + # TODO: This won't work if there are more than 2 approvals with the same study_id + other_approvals = {} + for approval in db_other_approvals: + other_approvals[approval.study_id] = approval + + counts = {} + for status in ApprovalStatus: + counts[status.name] = 0 + + for approval in db_user_approvals: + # Check if another approval has the same study id + if approval.study_id in other_approvals: + other_approval = other_approvals[approval.study_id] + + # Other approval takes precedence over this one + if other_approval.id < approval.id: + if other_approval.status == ApprovalStatus.PENDING.name: + counts[ApprovalStatus.AWAITING.name] += 1 + elif other_approval.status == ApprovalStatus.DECLINED.name: + counts[ApprovalStatus.DECLINED.name] += 1 + elif other_approval.status == ApprovalStatus.CANCELED.name: + counts[ApprovalStatus.CANCELED.name] += 1 + elif other_approval.status == ApprovalStatus.APPROVED.name: + counts[approval.status] += 1 + else: + counts[approval.status] += 1 + + return counts + + def get_approvals(status=None, as_user=None): #status = ApprovalStatus.PENDING.value user = g.user.uid @@ -31,7 +81,7 @@ def get_approvals_for_study(study_id=None): return results -# ----- Being decent into madness ---- # +# ----- Begin descent into madness ---- # def get_csv(): """A damn lie, it's a json file. A huge bit of a one-off for RRT, but 3 weeks of midnight work can convince a man to do just about anything""" @@ -81,12 +131,14 @@ def get_csv(): errors.append("Error pulling data for workflow #%i: %s" % (approval.workflow_id, str(e))) return {"results": output, "errors": errors } + def extract_value(task, key): if key in task['data']: return pickle.loads(b64decode(task['data'][key]['__bytes__'])) else: return "" + def find_task(uuid, task): if task['id']['__uuid__'] == uuid: return task @@ -96,6 +148,7 @@ def find_task(uuid, task): return task # ----- come back to the world of the living ---- # + def update_approval(approval_id, body): if approval_id is None: raise ApiError('unknown_approval', 'Please provide a valid Approval ID.')