Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Evolveum/midpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
katkav committed Apr 15, 2020
2 parents 8da5755 + ccd9470 commit b0c86bf
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 55 deletions.
Expand Up @@ -1923,6 +1923,7 @@ public String getBubbleLabel() {
AuthorizationConstants.AUTZ_UI_CASES_ALL_URL, AuthorizationConstants.AUTZ_GUI_ALL_URL)) {
addMenuItem(item, "PageWorkItemsClaimable.title", PageWorkItemsClaimable.class);
}
createFocusPageViewMenu(item.getItems(), "PageAdmin.menu.top.case.view", PageCase.class);
createFocusPageViewMenu(item.getItems(), "PageAdmin.menu.top.caseWorkItems.view", PageCaseWorkItem.class);

return item;
Expand Down
Expand Up @@ -490,10 +490,9 @@ public static <T extends ObjectType> void deleteObject(Class<T> type, String oid
subResult = new OperationResult(OPERATION_DELETE_OBJECT);
}
try {
Task task = createSimpleTask(result.getOperation(), principal, page.getTaskManager());
Task task = createSimpleTask(subResult.getOperation(), principal, page.getTaskManager());

ObjectDelta delta = page.getPrismContext().deltaFactory().object().create(type, ChangeType.DELETE);
delta.setOid(oid);
ObjectDelta<T> delta = page.getPrismContext().deltaFactory().object().createDeleteDelta(type, oid);

page.getModelService().executeChanges(MiscUtil.createCollection(delta), options, task, subResult);
} catch (Exception ex) {
Expand Down
Expand Up @@ -46,8 +46,8 @@ protected void initLayout(UserProfileStorage.TableId tableId, int pageSize) {
List<IColumn<DecisionDto, String>> columns = new ArrayList<>();
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.user"), DecisionDto.F_USER));
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.attorney"), DecisionDto.F_ATTORNEY));
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.originalActor"), DecisionDto.F_ORIGINAL_ACTOR));
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.originalAssignee"), DecisionDto.F_ORIGINAL_ASSIGNEE));
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.assigneeChange"), DecisionDto.F_ASSIGNEE_CHANGE));
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.stage"), DecisionDto.F_STAGE));
columns.add(createOutcomeColumn());
columns.add(new PropertyColumn<>(createStringResource("DecisionsPanel.comment"), DecisionDto.F_COMMENT));
Expand Down Expand Up @@ -84,7 +84,7 @@ public String getCssClass() {

private String choose(IModel<DecisionDto> rowModel, String inProgress, String forwarded, String approved, String rejected) {
DecisionDto dto = rowModel.getObject();
if (StringUtils.isNotEmpty(dto.getOriginalAssignee())){
if (StringUtils.isNotEmpty(dto.getAssigneeChange())){
return forwarded;
}
if (dto.getOutcome() == null) {
Expand Down
Expand Up @@ -19,6 +19,7 @@
import org.jetbrains.annotations.Nullable;

import java.util.Date;
import java.util.List;

/**
* @author lazyman
Expand All @@ -27,7 +28,7 @@ public class DecisionDto extends Selectable {

public static final String F_USER = "user";
public static final String F_ATTORNEY = "attorney";
public static final String F_ORIGINAL_ACTOR = "originalActor";
public static final String F_ASSIGNEE_CHANGE = "assigneeChange";
public static final String F_ORIGINAL_ASSIGNEE = "originalAssignee";
public static final String F_STAGE = "stage";
public static final String F_OUTCOME = "outcome";
Expand All @@ -37,8 +38,8 @@ public class DecisionDto extends Selectable {

private String user;
private String attorney;
private String originalActor;
private String originalAssignee;
private String assigneeChange;
private String stage;
private Boolean outcome;
private String comment;
Expand All @@ -57,14 +58,14 @@ public String getAttorney() {
return attorney;
}

public String getOriginalActor() {
return originalActor;
}

public String getOriginalAssignee() {
return originalAssignee;
}

public String getAssigneeChange() {
return assigneeChange;
}

public String getStage() {
return stage;
}
Expand Down Expand Up @@ -115,16 +116,18 @@ public static DecisionDto create(CaseEventType e, @Nullable PageBase pageBase) {
rv.escalationLevelNumber = ApprovalContextUtil.getEscalationLevelNumber(completionEvent);
if (completionEvent.getOriginalAssigneeRef() != null && pageBase != null) {
// TODO optimize repo access
rv.originalActor = WebModelServiceUtils.resolveReferenceName(completionEvent.getOriginalAssigneeRef(), pageBase);
rv.originalAssignee = WebModelServiceUtils.resolveReferenceName(completionEvent.getOriginalAssigneeRef(), pageBase);
}
return rv;
} else if (e instanceof WorkItemDelegationEventType){
WorkItemDelegationEventType event = (WorkItemDelegationEventType) e;
ObjectReferenceType origAssigneeRef = CollectionUtils.isNotEmpty(event.getAssigneeBefore()) ? event.getAssigneeBefore().get(0) : null;
if (event.getComment() != null){
rv.comment = event.getComment();
}
rv.originalAssignee = origAssigneeRef != null ? WebModelServiceUtils.resolveReferenceName(origAssigneeRef, pageBase) : null;

String assigneeBeforeNamesList = WebComponentUtil.getReferencedObjectDisplayNamesAndNames(event.getAssigneeBefore(), false);
String assigneeAfterNamesList = WebComponentUtil.getReferencedObjectDisplayNamesAndNames(event.getDelegatedTo(), false);
rv.assigneeChange = assigneeBeforeNamesList + " -> " + assigneeAfterNamesList;
return rv;
} else if (e instanceof StageCompletionEventType) {
StageCompletionEventType completion = (StageCompletionEventType) e;
Expand Down
Expand Up @@ -43,6 +43,7 @@
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import com.evolveum.midpoint.common.ActivationComputer;
Expand Down Expand Up @@ -1511,8 +1512,14 @@ public MidPointPrincipal assumePowerOfAttorney(PrismObject<UserType> donor, Task
MidPointPrincipal donorPrincipal = securityEnforcer.createDonorPrincipal(attorneyPrincipal, ModelAuthorizationAction.ATTORNEY.getUrl(), donor, task, result);

// TODO: audit switch

securityContextManager.setupPreAuthenticatedSecurityContext(donorPrincipal);
Authentication authentication = securityContextManager.getAuthentication();
if (authentication instanceof MidpointAuthentication) {
((MidpointAuthentication) authentication).setPrincipal(donorPrincipal);
((MidpointAuthentication) authentication).setCredential(null);
((MidpointAuthentication) authentication).setAuthorities(donorPrincipal.getAuthorities());
} else {
securityContextManager.setupPreAuthenticatedSecurityContext(donorPrincipal);
}

return donorPrincipal;
}
Expand All @@ -1531,7 +1538,14 @@ public MidPointPrincipal dropPowerOfAttorney(Task task, OperationResult result)
// TODO: audit switch

// TODO: maybe refresh previous principal using userProfileService?
securityContextManager.setupPreAuthenticatedSecurityContext(previousPrincipal);
Authentication authentication = securityContextManager.getAuthentication();
if (authentication instanceof MidpointAuthentication) {
((MidpointAuthentication) authentication).setPrincipal(previousPrincipal);
((MidpointAuthentication) authentication).setCredential(null);
((MidpointAuthentication) authentication).setAuthorities(previousPrincipal.getAuthorities());
} else {
securityContextManager.setupPreAuthenticatedSecurityContext(previousPrincipal);
}

return previousPrincipal;
}
Expand Down
Expand Up @@ -23,6 +23,8 @@
import javax.xml.namespace.QName;

import com.evolveum.midpoint.model.api.context.SynchronizationIntent;
import com.evolveum.midpoint.wf.api.WorkflowManager;

import org.apache.commons.lang.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand Down Expand Up @@ -99,7 +101,8 @@ public class ChangeExecutor {
private static final String OPERATION_UNLINK_ACCOUNT = ChangeExecutor.class.getName() + ".unlinkShadow";
private static final String OPERATION_UPDATE_SITUATION_IN_SHADOW = ChangeExecutor.class.getName() + ".updateSituationInShadow";

@Autowired private transient TaskManager taskManager;
@Autowired private TaskManager taskManager;
@Autowired private WorkflowManager workflowManager;
@Autowired @Qualifier("cacheRepositoryService") private transient RepositoryService cacheRepositoryService;
@Autowired private ProvisioningService provisioning;
@Autowired private PrismContext prismContext;
Expand Down Expand Up @@ -1417,6 +1420,8 @@ private <T extends ObjectType, F extends ObjectType> PrismObject<T> executeDelet
taskManager.deleteTask(oid, result);
} else if (NodeType.class.isAssignableFrom(objectTypeClass)) {
taskManager.deleteNode(oid, result);
} else if (CaseType.class.isAssignableFrom(objectTypeClass)) {
workflowManager.deleteCase(oid, task, result);
} else if (ObjectTypes.isClassManagedByProvisioning(objectTypeClass)) {
ProvisioningOperationOptions provisioningOptions = getProvisioningOptions(context, options,
(PrismObject<ShadowType>) objectContext.getObjectCurrent(), (ObjectDelta<ShadowType>) change);
Expand Down
Expand Up @@ -22,16 +22,12 @@

/**
* TODO specify and clean-up error handling
*
* @author mederly
*/

public interface WorkflowManager {

//region Work items
/**
* Approves or rejects a work item
* @param decision true = approve, false = reject
*/
void completeWorkItem(WorkItemId workItemId, AbstractWorkItemOutputType output,
WorkItemEventCauseInformationType causeInformation, Task task,
Expand All @@ -53,18 +49,29 @@ void delegateWorkItem(WorkItemId workItemId, WorkItemDelegationRequestType deleg

//region Process instances (cases)

/**
* Cancels a case and its subcases. Carries out the authorization.
*/
void cancelCase(String caseOid, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, SecurityViolationException,
CommunicationException, ConfigurationException, ExpressionEvaluationException;

/**
* Cancels and deletes a case and its subcases. Carries out authorization but only for
* subcases. For the root it is expected that this is done by the caller (usually the ChangeExecutor).
*/
void deleteCase(String caseOid, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, SecurityViolationException,
CommunicationException, ConfigurationException, ExpressionEvaluationException;

//endregion

/*
* MISC
* ====
*/

public boolean isEnabled();
boolean isEnabled();

// TODO remove this
PrismContext getPrismContext();
Expand Down
Expand Up @@ -107,6 +107,14 @@ public void cancelCase(String caseOid, Task task, OperationResult parentResult)
CommunicationException, ConfigurationException, ExpressionEvaluationException {
caseManager.cancelCase(caseOid, task, parentResult);
}

@Override
public void deleteCase(String caseOid, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, SecurityViolationException,
CommunicationException, ConfigurationException, ExpressionEvaluationException {
caseManager.deleteCase(caseOid, task, parentResult);
}

//endregion

/*
Expand Down
Expand Up @@ -21,9 +21,12 @@
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.TreeNode;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.wf.api.WorkflowManager;
import com.evolveum.midpoint.wf.api.request.CancelCaseRequest;
import com.evolveum.midpoint.wf.impl.engine.WorkflowEngine;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseWorkItemType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType;
Expand All @@ -38,6 +41,8 @@
@Component("wfCaseManager")
public class CaseManager {

private static final Trace LOGGER = TraceManager.getTrace(CaseManager.class);

@Autowired private PrismContext prismContext;
@Autowired private WorkflowEngine workflowEngine;
@Autowired private SecurityEnforcer securityEnforcer;
Expand All @@ -48,21 +53,20 @@ public class CaseManager {

private static final String DOT_INTERFACE = WorkflowManager.class.getName() + ".";

private static final String OPERATION_STOP_PROCESS_INSTANCE = DOT_INTERFACE + "cancelCase";
//private static final String OPERATION_DELETE_PROCESS_INSTANCE = DOT_INTERFACE + "deleteProcessInstance";
private static final String OPERATION_CANCEL_CASE = DOT_INTERFACE + "cancelCase";
private static final String OPERATION_DELETE_CASE = DOT_INTERFACE + "deleteCase";

public void cancelCase(String caseOid, Task task, OperationResult parentResult)
throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ConfigurationException,
CommunicationException, SecurityViolationException, ExpressionEvaluationException {
OperationResult result = parentResult.createSubresult(OPERATION_STOP_PROCESS_INSTANCE);
OperationResult result = parentResult.createSubresult(OPERATION_CANCEL_CASE);
result.addParam("caseOid", caseOid);
try {
TreeNode<CaseType> caseTree = getCaseTree(caseOid, result);
System.out.println(caseTree.debugDump());
cancelCaseTree(caseTree, task, result);
} catch (RuntimeException | SchemaException | ObjectAlreadyExistsException | ObjectNotFoundException |
SecurityViolationException | ExpressionEvaluationException | ConfigurationException | CommunicationException e) {
result.recordFatalError("Case couldn't be stopped: " + e.getMessage(), e);
result.recordFatalError("Case couldn't be cancelled: " + e.getMessage(), e);
throw e;
} finally {
result.computeStatusIfUnknown();
Expand Down Expand Up @@ -130,19 +134,44 @@ private void addChildren(TreeNode<CaseType> tree, OperationResult result) throws
}
}

// TODO cleanup and delete cases

// private void deleteCase(String caseOid, OperationResult parentResult) {
// OperationResult result = parentResult.createSubresult(OPERATION_DELETE_PROCESS_INSTANCE);
// result.addParam("caseOid", caseOid);
// try {
// repositoryService.deleteObject(CaseType.class, )
// } catch (RuntimeException e) {
// result.recordFatalError("Case couldn't be deleted: " + e.getMessage(), e);
// throw e;
// } finally {
// result.computeStatusIfUnknown();
// }
// }
public void deleteCase(String caseOid, Task task, OperationResult parentResult)
throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, ConfigurationException,
CommunicationException, SecurityViolationException, ExpressionEvaluationException {
OperationResult result = parentResult.createSubresult(OPERATION_DELETE_CASE);
result.addParam("caseOid", caseOid);
try {
TreeNode<CaseType> caseTree = getCaseTree(caseOid, result);
cancelCaseTree(caseTree, task, result); // if this fails, deletion will not be tried
deleteCaseTree(caseTree, true, task, result);
} catch (RuntimeException | SchemaException | ObjectAlreadyExistsException | ObjectNotFoundException |
SecurityViolationException | ExpressionEvaluationException | ConfigurationException | CommunicationException e) {
result.recordFatalError("Case couldn't be cancelled/deleted: " + e.getMessage(), e);
throw e;
} finally {
result.computeStatusIfUnknown();
}
}

private void deleteCaseTree(TreeNode<CaseType> caseTree, boolean isRoot, Task task, OperationResult result)
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
CaseType aCase = caseTree.getUserObject();
if (!isRoot) {
securityEnforcer.authorize(ModelAuthorizationAction.DELETE.getUrl(), AuthorizationPhaseType.EXECUTION,
AuthorizationParameters.Builder.buildObjectDelete(aCase.asPrismObject()), null, task, result);
}

for (TreeNode<CaseType> child : caseTree.getChildren()) {
deleteCaseTree(child, false, task, result);
}
String caseOid = aCase.getOid();
try {
repositoryService.deleteObject(CaseType.class, caseOid, result);
} catch (ObjectNotFoundException e) {
LOGGER.warn("Case {} has been already deleted", caseOid);
// no auditing needed
} catch (Throwable t) {
throw t;
}
}
}
Expand Up @@ -176,7 +176,6 @@ protected void removeAllAssignments(String oid, OperationResult result) throws E

protected CaseWorkItemType getWorkItem(Task task, OperationResult result)
throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException {
//Collection<SelectorOptions<GetOperationOptions>> options = GetOperationOptions.resolveItemsNamed(CaseWorkItemType.F_TASK_REF);
SearchResultList<CaseWorkItemType> itemsAll = modelService.searchContainers(CaseWorkItemType.class, getOpenItemsQuery(), null, task, result);
if (itemsAll.size() != 1) {
System.out.println("Unexpected # of work items: " + itemsAll.size());
Expand Down Expand Up @@ -328,4 +327,33 @@ protected ObjectQuery getOpenItemsQuery() {
.item(CaseWorkItemType.F_CLOSE_TIMESTAMP).isNull()
.build();
}

public class RelatedCases {
private CaseType approvalCase;
private CaseType requestCase;

public CaseType getApprovalCase() {
return approvalCase;
}

public CaseType getRequestCase() {
return requestCase;
}

public RelatedCases find(Task task, OperationResult result) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException,
ExpressionEvaluationException, CommunicationException {
CaseWorkItemType workItem = getWorkItem(task, result);
display("Work item", workItem);
approvalCase = getCase(CaseWorkItemUtil.getCaseRequired(workItem).getOid());
display("Approval case", approvalCase);
assertHasArchetype(approvalCase.asPrismObject(), SystemObjectsType.ARCHETYPE_APPROVAL_CASE.value());
ObjectReferenceType parentRef = approvalCase.getParentRef();
assertNotNull(parentRef);
requestCase = modelObjectResolver.resolve(parentRef, CaseType.class, null, null, task, result);
display("Request case", requestCase);
assertNotNull(requestCase);
assertHasArchetype(requestCase.asPrismObject(), SystemObjectsType.ARCHETYPE_OPERATION_REQUEST.value());
return this;
}
}
}

0 comments on commit b0c86bf

Please sign in to comment.