diff options
author | 2017-09-28 10:03:40 -0700 | |
---|---|---|
committer | 2017-09-28 10:14:55 -0700 | |
commit | bd886d918ef2adbabd16c61fdd2e47984e21dfd7 (patch) | |
tree | d41683dffa58fd698df450d148fab3cc2521b0c5 /django/engagementmanager/service/checklist_state_service.py | |
parent | 474554adad912f3edb7ddc3ad14406abb369fb3c (diff) |
initial seed code commit VVP-5
Change-Id: I6560c87ef48a6d0d1fe8197c7c6439c7e6ad653f
Signed-off-by: Paul McGoldrick <paul.mcgoldrick@att.com>
Diffstat (limited to 'django/engagementmanager/service/checklist_state_service.py')
-rwxr-xr-x | django/engagementmanager/service/checklist_state_service.py | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/django/engagementmanager/service/checklist_state_service.py b/django/engagementmanager/service/checklist_state_service.py new file mode 100755 index 0000000..1903c47 --- /dev/null +++ b/django/engagementmanager/service/checklist_state_service.py @@ -0,0 +1,434 @@ +# +# ============LICENSE_START========================================== +# org.onap.vvp/engagementmgr +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from django.db.models import Q +from django.utils import timezone +from engagementmanager.decorator.auth import auth +from engagementmanager.slack_client.api import SlackClient +from engagementmanager.models import ChecklistDecision, Checklist, \ + IceUserProfile, VF, ChecklistLineItem, ChecklistAuditLog, Role +from engagementmanager.service.authorization_service import Permissions +from engagementmanager.service.checklist_audit_log_service import \ + addAuditLogToChecklist +from engagementmanager.service.engagement_service import \ + update_or_insert_to_recent_engagements, update_eng_validation_details +from engagementmanager.utils.constants import CheckListState, \ + CheckListDecisionValue, Roles, RecentEngagementActionType +from engagementmanager.utils.request_data_mgr import request_data_mgr +from engagementmanager.vm_integration.vm_client import \ + send_cl_from_pending_to_automation_event +from rest_framework.exceptions import MethodNotAllowed +import random +from engagementmanager.service.logging_service import LoggingServiceFactory + +logger = LoggingServiceFactory.get_logger() + + +def insert_to_recent_engagements(owner=None, action=None, vf=None): + if vf == None: + # If VF wasn't supplied let's fetch it using checklist and + # checklist.engagement + checkListObj = Checklist.objects.get( + uuid=request_data_mgr.get_cl_uuid()) + vf = VF.objects.get(engagement=checkListObj.engagement) + + logger.debug("Adding vf " + str(vf.uuid) + + " to recent engagements table for user " + owner.full_name) + update_or_insert_to_recent_engagements( + owner.uuid, vf, action) # @UndefinedVariable + + +def description_creator(checklist, next_state, additional_comment=""): + if additional_comment: + description = "The " + checklist.name + " checklist was changed to the " +\ + next_state.lower() + " state. " + "\n" +\ + additional_comment + else: + description = "The " + checklist.name + " checklist was changed to the " +\ + next_state.lower() + " state." + return description + + +''' + If kwargs['isMoveToAutomation']==True than the CL will not be cloned but reverted to automation, else (False) will be cloned and returned in pending +''' + + +def set_state(decline, checklist_uuid, isMoveToAutomation=True, description=None): + logger.debug('set_state(decline=%r,checklist_uuid=%r,get_request_data_vars= %r)', + decline, checklist_uuid, request_data_mgr.get_request_data_vars()) + + if checklist_uuid != None: # was sent explicitly + request_data_mgr.set_cl_uuid(checklist_uuid) + + if any(x is None for x in [checklist_uuid, request_data_mgr.get_user(), description]): + msg = "checklist uuid or user or description is None" + logger.error(msg) + msg = "checklist state wasn't change due to bad parameters" + raise KeyError(msg) + + additional_comment = description + + checklist = retrieve_checklist_object(checklist_uuid) + + # get metadata for slack notifications + slack_client = SlackClient() + checklist_name = checklist.name + engagement = checklist.engagement + reviewer = engagement.reviewer + peer_reviewer = engagement.peer_reviewer + engagement_manual_id = '' + if engagement is not None: + engagement_manual_id = engagement.engagement_manual_id + + vf = VF.objects.get(engagement__uuid=engagement.uuid) + vf_name = "" + if vf is not None: + vf_name = vf.name + + if not checklist: + msg = "checklist state wasn't change due to bad parameters" + raise KeyError(msg) + + # @UndefinedVariable + if checklist.state == CheckListState.closed.name or checklist.state == CheckListState.archive.name: + msg = "attempt to change state to the next one from 'closed'/'archive', no actions were made." + logger.error(msg) + msg = "checklist's state is already closed/archive, can not move forward in states." + raise FileExistsError(msg) + + elif decline and checklist.state != CheckListState.pending.name: # @UndefinedVariable + logger.debug( + 'set_state: decline and not pending -< about to set the state to ARCHIVE and duplicate the checklist') + set_state_to_archive(isMoveToAutomation, description) + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.archive.name, additional_comment) + + elif checklist.state == CheckListState.pending.name: # @UndefinedVariable + logger.debug('set_state: pending to automation') + set_state_to_automation() + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.automation.name, additional_comment) + + # this case is when getting a signal from VM that jenkins has finished all + # tests + elif checklist.state == CheckListState.automation.name: # @UndefinedVariable + logger.debug('set_state: automation to review') + set_state_to_review(checklist) + slack_client.send_notification_to_reviewer_when_automation_completes( + engagement_manual_id, vf_name, reviewer, checklist_name) + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.review.name, additional_comment) + + elif checklist.state == CheckListState.review.name: # @UndefinedVariable + logger.debug('set_state: review to peer review') + set_state_to_peer_review() + slack_client.send_notification_to_peer_reviewer_when_the_review_completes( + engagement_manual_id, vf_name, reviewer, peer_reviewer, checklist_name) + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.peer_review.name, additional_comment) + + elif checklist.state == CheckListState.peer_review.name: # @UndefinedVariable + logger.debug('set_state: peer review to approval') + set_state_to_approval() + admins = IceUserProfile.objects.filter(role__name=Roles.admin.name) + slack_client.send_notification_to_admins_when_the_peer_review_completes( + engagement_manual_id, vf_name, reviewer, peer_reviewer, admins, checklist_name) + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.approval.name, additional_comment) + + elif checklist.state == CheckListState.approval.name: # @UndefinedVariable + logger.debug('set_state: approval to handoff') + set_state_to_handoff() + slack_client.send_notification_to_reviewer_when_approved( + engagement_manual_id, vf_name, reviewer, checklist_name) + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.handoff.name, additional_comment) + + elif checklist.state == CheckListState.handoff.name: # @UndefinedVariable + logger.debug('set_state: handoff to closed') + set_state_to_closed() + admins = IceUserProfile.objects.filter(role__name=Roles.admin.name) + slack_client.send_notifications_when_closed( + engagement_manual_id, vf_name, reviewer, peer_reviewer, admins, checklist_name) + + # @UndefinedVariable + return check_sts(checklist, request_data_mgr.get_user(), CheckListState.closed.name, additional_comment) + + +def duplicate_checklist_and_its_auditlogs(checklist, isMoveToAutomation): + ''' Create the basic duplicated checklist object based on the original one ''' + + newState = CheckListState.pending.name # @UndefinedVariable + checklistDupObject = Checklist.objects.create( + name=checklist.name, + validation_cycle=checklist.validation_cycle + 1, + associated_files=checklist.associated_files, + engagement=checklist.engagement, + template=checklist.template, + creator=checklist.creator, + owner=checklist.creator, + state=newState) + + ''' Fetch all original cl audit logs and attach it to the duplicated one ''' + audits = ChecklistAuditLog.objects.filter(checklist=checklist) + for item in audits: + audit = addAuditLogToChecklist( + checklistDupObject, item.description, item.creator) + + if not audit: + logger.error( + "duplicate_checklist_and_its_auditlogs: Failed to create a duplicated audit log in the DB") + msg = "checklist state wasn't change" + raise Exception(msg) + + ''' Fetch all original line items and attach it to the duplicated one ''' + line_items_list = ChecklistLineItem.objects.filter( + template=checklist.template) + # Implementation is based on space and performance aspect and not particularly one of them + #(could have just change the internal object's cl field to the new object and reset their values) + for lineitem in line_items_list: + old_decisions = ChecklistDecision.objects.filter( + lineitem=lineitem, checklist=checklist, template=checklist.template) + if len(old_decisions) == 0: + new_decision = ChecklistDecision.objects.create( + checklist=checklistDupObject, template=checklistDupObject.template, lineitem=lineitem) + else: + for decision in old_decisions: + new_decision = ChecklistDecision.objects.create( + checklist=checklistDupObject, template=checklist.template, lineitem=lineitem) + old_decision_auditlogs = ChecklistAuditLog.objects.filter( + decision=decision) + for audit in old_decision_auditlogs: + audit = ChecklistAuditLog.objects.create( + decision=new_decision, description=audit.description, category='', creator=audit.creator) + + if isMoveToAutomation == True: # This is a scenario in which we send to VM cl_from_pending_to_automation_event + logger.debug("Cloned Checklist is triggered as to automation") + try: + set_state_to_automation(checklistDupObject) + except KeyError: + # delete new checklist since we don't want duplicate checklist while + # the other one is still not archived + checklistDupObject.delete() + + return checklistDupObject + + +def check_sts(checklist, user, next_state, additional_comment): + description = description_creator( + checklist, next_state, additional_comment=additional_comment) # @UndefinedVariable + if not description: + msg = "failed to set the state to the next one due to invalid parameters." + raise ValueError(msg) + addAuditLogToChecklist(checklist, description, user) + return checklist + + +def check_decision_meet_criterias(checkListObj, review_type): + if not type: + return True + + if review_type == 'review_value': + invalid_decisions = ChecklistDecision.objects.filter(Q(checklist=checkListObj) & + ( + Q(review_value=CheckListDecisionValue.na.name) + | Q(review_value=CheckListDecisionValue.denied.name) + )).count() # @UndefinedVariable + elif review_type == 'peer_review_value': + invalid_decisions = ChecklistDecision.objects.filter(Q(checklist=checkListObj) & + ( + Q(peer_review_value=CheckListDecisionValue.na.name) | + Q(peer_review_value=CheckListDecisionValue.denied.name) + )).count() # @UndefinedVariable + else: + return True + + if invalid_decisions: + msg = "checklist state wasn't change, not all decisions are approved / na" + raise MethodNotAllowed(msg) + + +def retrieve_checklist_and_its_decisions(cluuid, review_type): + checkListObj = retrieve_checklist_object(cluuid) + if not checkListObj: + msg = "checklist state wasn't change" + raise KeyError(msg) + check_decision_meet_criterias(checkListObj, review_type) + return checkListObj + + +def retrieve_checklist_object(cluuid): + checklist = Checklist.objects.get(uuid=cluuid) + return checklist + + +""" +This method is called when an EL / Peer Reviewer declines a CL or creates a Next step for them after declining a specific line item in the CL. +""" + + +@auth(Permissions.set_checklist_decision, is_internal=True) +def set_state_to_archive(isMoveToAutomation=True, description=None): + checkListObj = retrieve_checklist_and_its_decisions( + request_data_mgr.get_cl_uuid(), '') # @UndefinedVariable + + rejection_description = description_creator( + checkListObj, CheckListState.archive.name, description) # @UndefinedVariable + addAuditLogToChecklist( + checkListObj, rejection_description, request_data_mgr.get_user()) + checklistDupObject = duplicate_checklist_and_its_auditlogs( + checkListObj, isMoveToAutomation) + checkListObj.state = CheckListState.archive.name # @UndefinedVariable + checkListObj.owner = checkListObj.creator + checkListObj.update_time = timezone.now() + + checkListObj.save() + + return checklistDupObject + + +def set_state_to_automation(checkListObj=None): + if checkListObj is None: + checkListObj = retrieve_checklist_object(request_data_mgr.get_cl_uuid()) + + if checkListObj.associated_files == [] or not checkListObj.associated_files: + logger.error( + "set_state_to_automation failed: no files were found in the checkListObj.associated_file") + msg = "checklist state wasn't change, please add files to the checklist in order to start Automation state" + raise KeyError(msg) + originalState = checkListObj.state + checkListObj.state = CheckListState.automation.name # @UndefinedVariable + checkListObj.update_time = timezone.now() + + checkListObj.save() + + if originalState == CheckListState.pending.name: # @UndefinedVariable + send_cl_from_pending_to_automation_event(checkListObj) + + +def set_state_to_review(checkListObj): + checkListObj.state = CheckListState.review.name # @UndefinedVariable + checkListObj.update_time = timezone.now() + # set the owner to reviewer and update_or_insert_to_recent_engagements(...) + + checkListObj.save() + + +@auth(Permissions.el_review_checklist, is_internal=True) +def set_state_to_peer_review(): + """ + This method is called when EL approves a review and moves a CL to peer_review + """ + checkListObj = retrieve_checklist_and_its_decisions( + request_data_mgr.get_cl_uuid(), 'review_value') # @UndefinedVariable + checkListObj.state = CheckListState.peer_review.name # @UndefinedVariable + checkListObj.owner = checkListObj.engagement.peer_reviewer + + insert_to_recent_engagements( + owner=checkListObj.owner, action=RecentEngagementActionType.GOT_OWNERSHIP_OVER_ENGAGEMENT.name) # @UndefinedVariable + + checkListObj.update_time = timezone.now() + + checkListObj.save() + + +@auth(Permissions.peer_review_checklist, is_internal=True) +def set_state_to_approval(): + """ + This method is called when Peer Reviewer approves a review and moves a CL to approval state + """ + checkListObj = retrieve_checklist_and_its_decisions( + request_data_mgr.get_cl_uuid(), 'peer_review_value') # @UndefinedVariable + checkListObj.state = CheckListState.approval.name # @UndefinedVariable + admin_role = Role.objects.get(name=Roles.admin.name) # @UndefinedVariable + + admin_list = IceUserProfile.objects.all().filter( + role=admin_role) # @UndefinedVariable + if admin_list.count() < 1: + logger.error("Failed to save the new state of the Checklist to the DB") + msg = "checklist state wasn't change due to server error" + raise Exception(msg) + + rand_admin = admin_list[random.randint(0, admin_list.count() - 1)] + admin = IceUserProfile.objects.get(uuid=rand_admin.uuid) + + checkListObj.update_time = timezone.now() + checkListObj.owner = admin + insert_to_recent_engagements( + owner=checkListObj.owner, action=RecentEngagementActionType.GOT_OWNERSHIP_OVER_ENGAGEMENT.name) # @UndefinedVariable + + checkListObj.save() + + +@auth(Permissions.admin_approve_checklist) +def set_state_to_handoff(): + """ + This method is called when an admin approves a CL and moves it to a handoff state + """ + checkListObj = retrieve_checklist_and_its_decisions( + request_data_mgr.get_cl_uuid(), '') + checkListObj.state = CheckListState.handoff.name # @UndefinedVariable + checkListObj.owner = checkListObj.creator + + insert_to_recent_engagements( + owner=checkListObj.owner, action=RecentEngagementActionType.GOT_OWNERSHIP_OVER_ENGAGEMENT.name) # @UndefinedVariable + + checkListObj.update_time = timezone.now() + + checkListObj.save() + + +@auth(Permissions.handoff_checklist) +def set_state_to_closed(): + """ + This method is called when an EL approves the handoff and moves the CL to closed state + """ + checkListObj = retrieve_checklist_and_its_decisions( + request_data_mgr.get_cl_uuid(), '') + checkListObj.state = CheckListState.closed.name # @UndefinedVariable + checkListObj.owner = checkListObj.creator + checkListObj.update_time = timezone.now() + update_eng_validation_details(checkListObj) + checkListObj.save() |