Fix merge conflicts

feature/appm-store/pbac
lasanthaDLPDS 6 years ago
commit a79b600922

@ -67,7 +67,7 @@ import org.wso2.carbon.device.application.mgt.core.exception.UnexpectedServerErr
import org.wso2.carbon.device.application.mgt.core.exception.ValidationException; import org.wso2.carbon.device.application.mgt.core.exception.ValidationException;
import org.wso2.carbon.device.application.mgt.core.exception.VisibilityManagementDAOException; import org.wso2.carbon.device.application.mgt.core.exception.VisibilityManagementDAOException;
import org.wso2.carbon.device.application.mgt.core.internal.DataHolder; import org.wso2.carbon.device.application.mgt.core.internal.DataHolder;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil; import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil;
import org.wso2.carbon.device.application.mgt.core.util.Constants; import org.wso2.carbon.device.application.mgt.core.util.Constants;
import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.DeviceManagementException;
@ -104,11 +104,11 @@ public class ApplicationManagerImpl implements ApplicationManager {
private ApplicationDAO applicationDAO; private ApplicationDAO applicationDAO;
private ApplicationReleaseDAO applicationReleaseDAO; private ApplicationReleaseDAO applicationReleaseDAO;
private LifecycleStateDAO lifecycleStateDAO; private LifecycleStateDAO lifecycleStateDAO;
private LifecycleStateManger lifecycleStateManger; private LifecycleStateManager lifecycleStateManager;
public ApplicationManagerImpl() { public ApplicationManagerImpl() {
initDataAccessObjects(); initDataAccessObjects();
lifecycleStateManger = DataHolder.getInstance().getLifecycleStateManager(); lifecycleStateManager = DataHolder.getInstance().getLifecycleStateManager();
} }
private void initDataAccessObjects() { private void initDataAccessObjects() {
@ -122,8 +122,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
* The responsbility of this method is the creating an application. * The responsbility of this method is the creating an application.
* @param applicationWrapper ApplicationDTO that need to be created. * @param applicationWrapper ApplicationDTO that need to be created.
* @return {@link ApplicationDTO} * @return {@link ApplicationDTO}
* @throws RequestValidatingException if application creating request is invalid, returns {@link RequestValidatingException} * @throws RequestValidatingException if application creating request is invalid,
* @throws ApplicationManagementException Catch all other throwing exceptions and returns {@link ApplicationManagementException} * @throws ApplicationManagementException Catch all other throwing exceptions and throw {@link ApplicationManagementException}
*/ */
@Override @Override
public Application createApplication(ApplicationWrapper applicationWrapper, public Application createApplication(ApplicationWrapper applicationWrapper,
@ -504,7 +504,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
String packageName = this.applicationReleaseDAO.getPackageName(applicationId, tenantId); String packageName = this.applicationReleaseDAO.getPackageName(applicationId, tenantId);
if (packageName != null && !packageName.equals(applicationRelease.getPackageName())) { if (packageName != null && !packageName.equals(applicationRelease.getPackageName())) {
throw new BadRequestException( throw new BadRequestException(
"Package name in the payload is different from the existing package name of other application releases."); "Package name in the payload is different from the existing package name of other application" +
" releases.");
} }
applicationRelease = this.applicationReleaseDAO applicationRelease = this.applicationReleaseDAO
.createRelease(applicationRelease, existingApplication.getId(), tenantId); .createRelease(applicationRelease, existingApplication.getId(), tenantId);
@ -810,8 +811,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
.getLatestLifeCycleState(applicationId, applicationRelease.getUuid()); .getLatestLifeCycleState(applicationId, applicationRelease.getUuid());
LifecycleStateDTO newAppLifecycleState = getLifecycleStateInstance(AppLifecycleState.REMOVED.toString(), LifecycleStateDTO newAppLifecycleState = getLifecycleStateInstance(AppLifecycleState.REMOVED.toString(),
appLifecycleState.getCurrentState()); appLifecycleState.getCurrentState());
if (lifecycleStateManger.isValidStateChange(newAppLifecycleState.getPreviousState(), if (lifecycleStateManager.isValidStateChange(newAppLifecycleState.getPreviousState(),
newAppLifecycleState.getCurrentState())) { newAppLifecycleState.getCurrentState(), userName, tenantId)) {
this.lifecycleStateDAO this.lifecycleStateDAO
.addLifecycleState(newAppLifecycleState, applicationId, applicationRelease.getUuid(), .addLifecycleState(newAppLifecycleState, applicationId, applicationRelease.getUuid(),
tenantId); tenantId);
@ -821,7 +822,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
AppLifecycleState.REMOVED.toString()); AppLifecycleState.REMOVED.toString());
for (String nextState : lifecycleFlow) { for (String nextState : lifecycleFlow) {
LifecycleStateDTO lifecycleState = getLifecycleStateInstance(nextState, currentState); LifecycleStateDTO lifecycleState = getLifecycleStateInstance(nextState, currentState);
if (lifecycleStateManger.isValidStateChange(currentState, nextState)) { if (lifecycleStateManager.isValidStateChange(currentState, nextState, userName, tenantId)) {
this.lifecycleStateDAO this.lifecycleStateDAO
.addLifecycleState(lifecycleState, applicationId, applicationRelease.getUuid(), .addLifecycleState(lifecycleState, applicationId, applicationRelease.getUuid(),
tenantId); tenantId);
@ -871,7 +872,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
if (currentNode.equals(finish)) { if (currentNode.equals(finish)) {
break; break;
} else { } else {
Set<String> nextStates = lifecycleStateManger.getNextLifecycleStates(currentNode); Set<String> nextStates = lifecycleStateManager.getNextLifecycleStates(currentNode);
if (nextStates.contains(finish)) { if (nextStates.contains(finish)) {
queue = new LinkedList<>(); queue = new LinkedList<>();
queue.add(finish); queue.add(finish);
@ -940,8 +941,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
.equals(currentState) || AppLifecycleState.UNPUBLISHED.toString().equals(currentState)) { .equals(currentState) || AppLifecycleState.UNPUBLISHED.toString().equals(currentState)) {
LifecycleStateDTO newAppLifecycleState = getLifecycleStateInstance(AppLifecycleState.REMOVED.toString(), LifecycleStateDTO newAppLifecycleState = getLifecycleStateInstance(AppLifecycleState.REMOVED.toString(),
appLifecycleState.getCurrentState()); appLifecycleState.getCurrentState());
if (lifecycleStateManger.isValidStateChange(newAppLifecycleState.getPreviousState(), if (lifecycleStateManager.isValidStateChange(newAppLifecycleState.getPreviousState(),
newAppLifecycleState.getCurrentState())) { newAppLifecycleState.getCurrentState(), userName, tenantId)) {
this.lifecycleStateDAO this.lifecycleStateDAO
.addLifecycleState(newAppLifecycleState, applicationId, applicationRelease.getUuid(), .addLifecycleState(newAppLifecycleState, applicationId, applicationRelease.getUuid(),
tenantId); tenantId);
@ -951,7 +952,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
AppLifecycleState.REMOVED.toString()); AppLifecycleState.REMOVED.toString());
for (String nextState : lifecycleFlow) { for (String nextState : lifecycleFlow) {
LifecycleStateDTO lifecycleState = getLifecycleStateInstance(nextState, currentState); LifecycleStateDTO lifecycleState = getLifecycleStateInstance(nextState, currentState);
if (lifecycleStateManger.isValidStateChange(currentState, nextState)) { if (lifecycleStateManager.isValidStateChange(currentState, nextState, userName, tenantId)) {
this.lifecycleStateDAO this.lifecycleStateDAO
.addLifecycleState(lifecycleState, applicationId, applicationRelease.getUuid(), .addLifecycleState(lifecycleState, applicationId, applicationRelease.getUuid(),
tenantId); tenantId);
@ -1187,7 +1188,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
} }
/** /**
* To validate a app release creating request and app updating request to make sure all the pre-conditions satisfied. * To validate a app release creating request and app updating request to make sure all the pre-conditions
* satisfied.
* *
* @param applicationRelease ApplicationReleaseDTO that need to be created. * @param applicationRelease ApplicationReleaseDTO that need to be created.
* @throws ApplicationManagementException ApplicationDTO Management Exception. * @throws ApplicationManagementException ApplicationDTO Management Exception.
@ -1210,8 +1212,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
if (lifecycleState == null) { if (lifecycleState == null) {
return null; return null;
} }
lifecycleState.setNextStates( lifecycleState.setNextStates(new ArrayList<>(lifecycleStateManager.getNextLifecycleStates(lifecycleState.getCurrentState())));
new ArrayList<>(lifecycleStateManger.getNextLifecycleStates(lifecycleState.getCurrentState())));
} catch (LifeCycleManagementDAOException e) { } catch (LifeCycleManagementDAOException e) {
throw new ApplicationManagementException("Failed to get lifecycle state from database", e); throw new ApplicationManagementException("Failed to get lifecycle state from database", e);
@ -1241,12 +1242,12 @@ public class ApplicationManagerImpl implements ApplicationManager {
+ " and application release UUID: " + releaseUuid); + " and application release UUID: " + releaseUuid);
} }
state.setPreviousState(currentState.getCurrentState()); state.setPreviousState(currentState.getCurrentState());
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
state.setUpdatedBy(userName); state.setUpdatedBy(userName);
if (state.getCurrentState() != null && state.getPreviousState() != null) { if (state.getCurrentState() != null && state.getPreviousState() != null) {
if (lifecycleStateManger.isValidStateChange(state.getPreviousState(), state.getCurrentState())) { if (lifecycleStateManager.isValidStateChange(state.getPreviousState(), state.getCurrentState(),
userName, tenantId)) {
//todo if current state of the adding lifecycle state is PUBLISHED, need to check whether is there //todo if current state of the adding lifecycle state is PUBLISHED, need to check whether is there
//todo any other application release in PUBLISHED state for the application( i.e for the appid) //todo any other application release in PUBLISHED state for the application( i.e for the appid)
this.lifecycleStateDAO.addLifecycleState(state, applicationId, releaseUuid, tenantId); this.lifecycleStateDAO.addLifecycleState(state, applicationId, releaseUuid, tenantId);

@ -31,7 +31,7 @@ import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager;
import org.wso2.carbon.device.application.mgt.common.config.UIConfiguration; import org.wso2.carbon.device.application.mgt.common.config.UIConfiguration;
import org.wso2.carbon.device.application.mgt.core.dao.common.ApplicationManagementDAOFactory; import org.wso2.carbon.device.application.mgt.core.dao.common.ApplicationManagementDAOFactory;
import org.wso2.carbon.device.application.mgt.core.impl.AppmDataHandlerImpl; import org.wso2.carbon.device.application.mgt.core.impl.AppmDataHandlerImpl;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState; import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
import org.wso2.carbon.device.application.mgt.core.util.ApplicationManagementUtil; import org.wso2.carbon.device.application.mgt.core.util.ApplicationManagementUtil;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
@ -78,10 +78,10 @@ public class ApplicationManagementServiceComponent {
List<LifecycleState> lifecycleStates = ConfigurationManager.getInstance(). List<LifecycleState> lifecycleStates = ConfigurationManager.getInstance().
getConfiguration().getLifecycleStates(); getConfiguration().getLifecycleStates();
LifecycleStateManger lifecycleStateManger = ApplicationManagementUtil.getLifecycleStateMangerInstance(); LifecycleStateManager lifecycleStateManager = ApplicationManagementUtil.getLifecycleStateMangerInstance();
lifecycleStateManger.init(lifecycleStates); lifecycleStateManager.init(lifecycleStates);
DataHolder.getInstance().setLifecycleStateManger(lifecycleStateManger); DataHolder.getInstance().setLifecycleStateManger(lifecycleStateManager);
bundleContext.registerService(LifecycleStateManger.class.getName(), lifecycleStateManger, null); bundleContext.registerService(LifecycleStateManager.class.getName(), lifecycleStateManager, null);
ApplicationManager applicationManager = ApplicationManagementUtil.getApplicationManagerInstance(); ApplicationManager applicationManager = ApplicationManagementUtil.getApplicationManagerInstance();
applicationManager applicationManager

@ -23,7 +23,7 @@ import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorage
import org.wso2.carbon.device.application.mgt.common.services.AppmDataHandler; import org.wso2.carbon.device.application.mgt.common.services.AppmDataHandler;
import org.wso2.carbon.device.application.mgt.common.services.ReviewManager; import org.wso2.carbon.device.application.mgt.common.services.ReviewManager;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
@ -44,7 +44,7 @@ public class DataHolder {
private ApplicationStorageManager applicationStorageManager; private ApplicationStorageManager applicationStorageManager;
private LifecycleStateManger lifecycleStateManger; private LifecycleStateManager lifecycleStateManager;
private AppmDataHandler configManager; private AppmDataHandler configManager;
@ -106,12 +106,12 @@ public class DataHolder {
return applicationStorageManager; return applicationStorageManager;
} }
public LifecycleStateManger getLifecycleStateManager() { public LifecycleStateManager getLifecycleStateManager() {
return lifecycleStateManger; return lifecycleStateManager;
} }
public void setLifecycleStateManger(LifecycleStateManger lifecycleStateManger) { public void setLifecycleStateManger(LifecycleStateManager lifecycleStateManager) {
this.lifecycleStateManger = lifecycleStateManger; this.lifecycleStateManager = lifecycleStateManager;
} }
public AppmDataHandler getConfigManager() { public AppmDataHandler getConfigManager() {

@ -0,0 +1,157 @@
/* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file 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.
*/
package org.wso2.carbon.device.application.mgt.core.lifecycle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException;
import org.wso2.carbon.device.application.mgt.core.internal.DataHolder;
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
import org.wso2.carbon.device.mgt.core.permission.mgt.PermissionUtils;
import org.wso2.carbon.device.mgt.core.search.mgt.Constants;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class represents the activities related to lifecycle management
*/
public class LifecycleStateManager {
private Map<String, State> lifecycleStates;
private static Log log = LogFactory.getLog(LifecycleStateManager.class);
public void init(List<LifecycleState> states) throws LifecycleManagementException {
lifecycleStates = new HashMap<>();
for (LifecycleState s : states) {
if (s.getProceedingStates() != null) {
s.getProceedingStates().replaceAll(String::toUpperCase);
}
lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(),
s.getProceedingStates(), s.getPermission(), s.isAppUpdatable(), s.isAppInstallable(),
s.isInitialState(), s.isEndState()));
try {
PermissionUtils.putPermission(s.getPermission());
} catch (PermissionManagementException e) {
String msg = "Error when adding permission " + s.getPermission() + " related to the state: "
+ s.getName();
log.error(msg, e);
throw new LifecycleManagementException(msg, e);
}
}
}
public Set<String> getNextLifecycleStates(String currentLifecycleState) {
return lifecycleStates.get(currentLifecycleState.toUpperCase()).getProceedingStates();
}
public boolean isValidStateChange(String currentState, String nextState, String username, int tenantId) throws
LifecycleManagementException {
UserRealm userRealm;
String permission = getPermissionForStateChange(nextState);
if (permission != null) {
try {
userRealm = DataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId);
if (userRealm != null && userRealm.getAuthorizationManager() != null &&
userRealm.getAuthorizationManager().isUserAuthorized(username,
PermissionUtils.getAbsolutePermissionPath(permission),
Constants.UI_EXECUTE)) {
if (currentState.equalsIgnoreCase(nextState)) {
return true;
}
State state = getMatchingState(currentState);
if (state != null) {
return getMatchingNextState(state.getProceedingStates(), nextState);
}
return false;
}
return false;
} catch (UserStoreException e) {
throw new LifecycleManagementException(
"UserStoreException exception from changing the state from : " + currentState + " to: "
+ nextState + " with username : " + username + " and tenant Id : " + tenantId, e);
}
} else {
throw new LifecycleManagementException(
"Required permissions cannot be found for the state : " + nextState);
}
}
private State getMatchingState(String currentState) {
Iterator it = lifecycleStates.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
if (pair.getKey().toString().equalsIgnoreCase(currentState)) {
return lifecycleStates.get(pair.getKey().toString());
}
}
return null;
}
private boolean getMatchingNextState(Set<String> proceedingStates, String nextState) {
for (String state : proceedingStates) {
if (state.equalsIgnoreCase(nextState)) {
return true;
}
}
return false;
}
private String getPermissionForStateChange(String nextState) {
Iterator it = lifecycleStates.entrySet().iterator();
State nextLifecycleState;
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
if (pair.getKey().toString().equalsIgnoreCase(nextState)) {
nextLifecycleState = lifecycleStates.get(nextState);
return nextLifecycleState.getPermission();
}
it.remove();
}
return null;
}
public boolean isUpdatable(String state) {
State currentState = getMatchingState(state);
if (currentState.getIsAppUpdatable()) {
return true;
}
return false;
}
public boolean isInstallable(String state) {
State currentState = getMatchingState(state);
if (currentState.getIsAppInstallable()) {
return true;
}
return false;
}
public void setLifecycleStates(Map<String, State> lifecycleStates) {
this.lifecycleStates = lifecycleStates;
}
}

@ -1,66 +0,0 @@
package org.wso2.carbon.device.application.mgt.core.lifecycle;
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class represents the activities related to lifecycle management
*/
public class LifecycleStateManger {
private Map<String, State> lifecycleStates;
public void init(List<LifecycleState> states){
lifecycleStates = new HashMap<>();
for (LifecycleState s : states) {
if (s.getProceedingStates() != null) {
s.getProceedingStates().replaceAll(String::toUpperCase);
}
lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(), s.getProceedingStates()));
}
}
public Set<String> getNextLifecycleStates(String currentLifecycleState) {
return lifecycleStates.get(currentLifecycleState.toUpperCase()).getProceedingStates();
}
public boolean isValidStateChange(String currentState, String nextState) {
if (currentState.equalsIgnoreCase(nextState)) {
return true;
}
State state = getMatchingState(currentState);
if (state != null) {
return getMatchingNextState(state.getProceedingStates(), nextState);
}
return false;
}
private State getMatchingState(String currentState) {
Iterator it = lifecycleStates.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
if(pair.getKey().toString().equalsIgnoreCase(currentState)) {
return lifecycleStates.get(pair.getKey().toString());
}
it.remove();
}
return null;
}
private boolean getMatchingNextState(Set<String> proceedingStates, String nextState) {
for (String state: proceedingStates) {
if (state.equalsIgnoreCase(nextState)) {
return true;
}
}
return false;
}
}

@ -11,9 +11,21 @@ public class State {
private Set<String> proceedingStates; private Set<String> proceedingStates;
private String stateName; private String stateName;
private String permission;
private List<String> allowedActions;
private boolean isAppUpdatable;
private boolean isAppInstallable;
private boolean isInitialState;
private boolean isEndState;
public State(String stateName, List<String> states) { public State(String stateName, List<String> states, String permission, boolean isAppUpdatable,
boolean isAppInstallable, boolean isInitialState, boolean isEndState) {
this.stateName = stateName; this.stateName = stateName;
this.permission = permission;
this.isAppUpdatable=isAppUpdatable;
this.isAppInstallable=isAppInstallable;
this.isInitialState=isInitialState;
this.isEndState=isEndState;
if (states != null && !states.isEmpty()) { if (states != null && !states.isEmpty()) {
proceedingStates = new HashSet<>(states); proceedingStates = new HashSet<>(states);
} }
@ -27,4 +39,14 @@ public class State {
return proceedingStates; return proceedingStates;
} }
public String getPermission(){ return permission;}
public boolean getIsAppUpdatable(){ return isAppUpdatable;}
public boolean getIsAppInstallable(){ return isAppInstallable;}
public boolean getIsInitialState(){ return isInitialState;}
public boolean getIsEndState(){ return isEndState;}
} }

@ -3,16 +3,22 @@ package org.wso2.carbon.device.application.mgt.core.lifecycle.config;
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List; import java.util.List;
/** /**
* This class represents the lifecycle state config * This class represents the lifecycle state config
*/ */
@XmlRootElement(name = "LifecycleState")
public class LifecycleState { public class LifecycleState {
private String name; private String name;
private String permission;
private List<String> proceedingStates; private List<String> proceedingStates;
private boolean isAppInstallable;
private boolean isAppUpdatable;
private boolean isInitialState;
private boolean isEndState;
@XmlAttribute(name = "name") @XmlAttribute(name = "name")
public String getName() { public String getName() {
@ -32,4 +38,50 @@ public class LifecycleState {
public void setProceedingStates(List<String> proceedingStates) { public void setProceedingStates(List<String> proceedingStates) {
this.proceedingStates = proceedingStates; this.proceedingStates = proceedingStates;
} }
@XmlElement(name = "Permission")
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
@XmlElement(name = "IsAppInstallable")
public boolean isAppInstallable() {
return isAppInstallable;
}
public void setAppInstallable(boolean isAppInstallable) {
this.isAppInstallable = isAppInstallable;
}
@XmlElement(name = "IsAppUpdatable")
public boolean isAppUpdatable() {
return isAppUpdatable;
}
public void setAppUpdatable(boolean isAppUpdatable) {
this.isAppUpdatable = isAppUpdatable;
}
@XmlElement(name = "IsInitialState")
public boolean isInitialState() {
return isInitialState;
}
public void setInitialState(boolean isInitialState) {
this.isInitialState = isInitialState;
}
@XmlElement(name = "IsEndState")
public boolean isEndState() {
return isEndState;
}
public void setEndState(boolean isEndState) {
this.isEndState = isEndState;
}
} }

@ -27,7 +27,7 @@ import org.wso2.carbon.device.application.mgt.common.services.ReviewManager;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager; import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager;
import org.wso2.carbon.device.application.mgt.core.config.Extension; import org.wso2.carbon.device.application.mgt.core.config.Extension;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -64,10 +64,10 @@ public class ApplicationManagementUtil {
return getInstance(extension, ApplicationStorageManager.class); return getInstance(extension, ApplicationStorageManager.class);
} }
public static LifecycleStateManger getLifecycleStateMangerInstance() throws InvalidConfigurationException { public static LifecycleStateManager getLifecycleStateMangerInstance() throws InvalidConfigurationException {
ConfigurationManager configurationManager = ConfigurationManager.getInstance(); ConfigurationManager configurationManager = ConfigurationManager.getInstance();
Extension extension = configurationManager.getExtension(Extension.Name.LifecycleStateManager); Extension extension = configurationManager.getExtension(Extension.Name.LifecycleStateManager);
return getInstance(extension, LifecycleStateManger.class); return getInstance(extension, LifecycleStateManager.class);
} }
private static <T> T getInstance(Extension extension, Class<T> cls) throws InvalidConfigurationException { private static <T> T getInstance(Extension extension, Class<T> cls) throws InvalidConfigurationException {

@ -0,0 +1,25 @@
package org.wso2.carbon.device.application.mgt.core;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
import org.wso2.carbon.device.application.mgt.core.lifecycle.State;
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
import java.util.HashMap;
import java.util.List;
public class LifeCycleStateManagerTest extends LifecycleStateManager {
public void initializeLifeCycleDetails(List<LifecycleState> states) {
HashMap<String, State> lifecycleStates = new HashMap<>();
for (LifecycleState s : states) {
if (s.getProceedingStates() != null) {
s.getProceedingStates().replaceAll(String::toUpperCase);
}
lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(),
s.getProceedingStates(), s.getPermission(), s.isAppUpdatable(), s.isAppInstallable(),
s.isInitialState(), s.isEndState()));
}
setLifecycleStates(lifecycleStates);
}
}

@ -3,9 +3,10 @@ package org.wso2.carbon.device.application.mgt.core;
import org.junit.Assert; import org.junit.Assert;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException;
import org.wso2.carbon.device.application.mgt.core.config.Configuration; import org.wso2.carbon.device.application.mgt.core.config.Configuration;
import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager; import org.wso2.carbon.device.application.mgt.core.config.ConfigurationManager;
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger; import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState; import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
import java.util.List; import java.util.List;
@ -14,45 +15,70 @@ import java.util.Set;
public class LifecycleManagementTest { public class LifecycleManagementTest {
private List<LifecycleState> lifecycleStates; private List<LifecycleState> lifecycleStates;
private LifecycleStateManger lifecycleStateManger; private LifecycleStateManager lifecycleStateManager;
private final String CURRENT_STATE = "Approved"; private final String CURRENT_STATE = "Approved";
private final String NEXT_STATE = "Published"; private final String NEXT_STATE = "Published";
private final String BOGUS_STATE = "Removed"; private final String BOGUS_STATE = "Removed";
private final String UPDATABLE_STATE = "Created";
private final String NON_UPDATABLE_STATE = "Removed";
private final String INSTALLABLE_STATE = "Published";
private final String UNINSTALlABLE_STATE = "Removed";
@BeforeClass @BeforeClass
public void init() { public void init() throws LifecycleManagementException {
ConfigurationManager configurationManager = ConfigurationManager.getInstance(); ConfigurationManager configurationManager = ConfigurationManager.getInstance();
Configuration configuration = configurationManager.getConfiguration(); Configuration configuration = configurationManager.getConfiguration();
lifecycleStates = configuration.getLifecycleStates(); lifecycleStates = configuration.getLifecycleStates();
lifecycleStateManger = new LifecycleStateManger(); lifecycleStateManager = new LifeCycleStateManagerTest();
lifecycleStateManger.init(lifecycleStates); ((LifeCycleStateManagerTest) lifecycleStateManager).initializeLifeCycleDetails(lifecycleStates);
} }
@Test @Test
public void checkValidNextLifecycleState() { public void checkValidNextLifecycleState() {
Set<String> proceedingStates = lifecycleStateManger.getNextLifecycleStates(CURRENT_STATE); Set<String> proceedingStates = lifecycleStateManager.getNextLifecycleStates(CURRENT_STATE);
Assert.assertTrue("Invalid proceeding state of: " + CURRENT_STATE, Assert.assertTrue("Invalid proceeding state of: " + CURRENT_STATE,
proceedingStates.contains(NEXT_STATE.toUpperCase())); proceedingStates.contains(NEXT_STATE.toUpperCase()));
} }
@Test @Test
public void checkInvalidNextLifecycleState() { public void checkInvalidNextLifecycleState() {
Set<String> proceedingStates = lifecycleStateManger.getNextLifecycleStates(CURRENT_STATE); Set<String> proceedingStates = lifecycleStateManager.getNextLifecycleStates(CURRENT_STATE);
Assert.assertFalse("Invalid proceeding state of: " + CURRENT_STATE, Assert.assertFalse("Invalid proceeding state of: " + CURRENT_STATE,
proceedingStates.contains(BOGUS_STATE.toUpperCase())); proceedingStates.contains(BOGUS_STATE.toUpperCase()));
}
@Test
public void CheckUpdatableState() {
Boolean isUpdatable = lifecycleStateManager.isUpdatable(UPDATABLE_STATE);
System.out.println(isUpdatable);
Assert.assertTrue("Updatable state: " + UPDATABLE_STATE, isUpdatable);
} }
@Test @Test
public void checkValidStateChange() { public void CheckNonUpdatableState() {
Assert.assertTrue("Invalid state transition from: " + CURRENT_STATE + " to: " + NEXT_STATE, Boolean isUpdatable = lifecycleStateManager.isUpdatable(NON_UPDATABLE_STATE);
lifecycleStateManger.isValidStateChange(CURRENT_STATE, NEXT_STATE)); Assert.assertFalse("Non Updatable state: " + NON_UPDATABLE_STATE, isUpdatable);
} }
@Test @Test
public void checkInvalidStateChange() { public void CheckInstallableState() {
Assert.assertFalse("Invalid state transition from: " + CURRENT_STATE + " to: " + BOGUS_STATE, Boolean isInstallable = lifecycleStateManager.isInstallable(INSTALLABLE_STATE);
lifecycleStateManger.isValidStateChange(CURRENT_STATE, BOGUS_STATE)); Assert.assertTrue("Installable state: " + INSTALLABLE_STATE, isInstallable);
}
@Test
public void CheckUnInstallableState() {
Boolean isInstallable = lifecycleStateManager.isInstallable(UNINSTALlABLE_STATE);
Assert.assertFalse("UnInstallable state: " + UNINSTALlABLE_STATE, isInstallable);
}
@Test
public void check() {
Set<String> proceedingStates = lifecycleStateManager.getNextLifecycleStates(CURRENT_STATE);
Assert.assertFalse("Invalid proceeding state of: " + CURRENT_STATE,
proceedingStates.contains(BOGUS_STATE.toUpperCase()));
} }
} }

@ -16,7 +16,6 @@
~ specific language governing permissions and limitations ~ specific language governing permissions and limitations
~ under the License. ~ under the License.
--> -->
<ApplicationManagementConfiguration> <ApplicationManagementConfiguration>
<!-- ApplicationDTO Mgt DB schema --> <!-- ApplicationDTO Mgt DB schema -->
@ -30,54 +29,143 @@
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl</ClassName> <ClassName>org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl</ClassName>
</Extension> </Extension>
<Extension name="LifecycleStateManager"> <Extension name="LifecycleStateManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger</ClassName> <ClassName>org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager</ClassName>
</Extension> </Extension>
<Extension name="SubscriptionManager"> <Extension name="SubscriptionManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl</ClassName> <ClassName>org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl</ClassName>
</Extension> </Extension>
<Extension name="ApplicationStorageManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ApplicationStorageManagerImpl</ClassName>
<Parameters>
<Parameter name="StoragePath">repository/resources/apps/</Parameter>
<Parameter name="MaxScreenShotCount">6</Parameter>
</Parameters>
</Extension>
</Extensions> </Extensions>
<!-- This is for publisher lifecycle -->
<!-- The current lifecycle as follows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Created] -> [In-Review] -> [Approved] -> [Published] -> [Unpublished] -> [Removed]
^ | ^
| | |
| |-> [Deprecated] - - - - - - - -|
| |
|-> [Rejected] - - - - - - - - - - - - - - - - - - - - - - - - |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If there is a requirement to introduce a new state to the lifecycle, please refer above
diagram and add relevant state to the below configuration appropriately.
-->
<!-- a lifecyclestate can have following properties
<LifecycleState name="In-Review">
<IsAppInstallable>false</IsAppInstallable>
<IsAppUpdatable>true</IsAppUpdatable>
<IsInitialState>false</IsInitialState>
<IsEndState>false</IsEndState>
<Permission>
/device-mgt/applications/life-cycle/in-review
</Permission>
<ProceedingStates>
<State>Rejected</State>
<State>Approved</State>
</ProceedingStates>
</LifecycleState>
-->
<LifecycleStates> <LifecycleStates>
<LifecycleState name="Created"> <LifecycleState name="Created">
<IsAppUpdatable>true</IsAppUpdatable>
<IsInitialState>true</IsInitialState>
<Permission>/device-mgt/applications/life-cycle/create</Permission>
<ProceedingStates> <ProceedingStates>
<State>In-Review</State> <State>In-Review</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="In-Review"> <LifecycleState name="In-Review">
<Permission>/device-mgt/applications/life-cycle/in-review</Permission>
<ProceedingStates> <ProceedingStates>
<State>Rejected</State> <State>Rejected</State>
<State>Approved</State> <State>Approved</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Approved"> <LifecycleState name="Approved">
<Permission>/device-mgt/applications/life-cycle/approve</Permission>
<ProceedingStates> <ProceedingStates>
<State>Published</State> <State>Published</State>
<State>Created</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Rejected"> <LifecycleState name="Rejected">
<Permission>/device-mgt/applications/life-cycle/reject</Permission>
<ProceedingStates> <ProceedingStates>
<State>In-Review</State> <State>Created</State>
<State>Removed</State> <State>Removed</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Published"> <LifecycleState name="Published">
<IsAppInstallable>true</IsAppInstallable>
<Permission>/device-mgt/applications/life-cycle/publish</Permission>
<ProceedingStates> <ProceedingStates>
<State>Unpublished</State> <State>Unpublished</State>
<State>Deprecated</State> <State>Deprecated</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Unpublished"> <LifecycleState name="Unpublished">
<Permission>/device-mgt/applications/life-cycle/unpublish</Permission>
<ProceedingStates> <ProceedingStates>
<State>Published</State>
<State>In-Review</State>
<State>Removed</State> <State>Removed</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Deprecated"> <LifecycleState name="Deprecated">
<Permission>/device-mgt/applications/life-cycle/deprecate</Permission>
<ProceedingStates> <ProceedingStates>
<State>Removed</State> <State>Removed</State>
<State>In-Review</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Removed"> <LifecycleState name="Removed">
<IsEndState>true</IsEndState>
<Permission>/device-mgt/applications/life-cycle/remove</Permission>
</LifecycleState> </LifecycleState>
</LifecycleStates> </LifecycleStates>
<UIConfigs>
<EnableOAuth>true</EnableOAuth>
<EnableSSO>false</EnableSSO>
<EnableSSO>false</EnableSSO>
<AppRegistration>
<Tags>
<Tag>application_management</Tag>
<Tag>device_management</Tag>
<Tag>subscription_management</Tag>
<Tag>review_management</Tag>
</Tags>
<AllowToAllDomains>true</AllowToAllDomains>
</AppRegistration>
<Scopes>
<Scope>perm:app:review:view</Scope>
<Scope>perm:app:review:update</Scope>
<Scope>perm:app:publisher:view</Scope>
<Scope>perm:app:publisher:update</Scope>
</Scopes>
<SSOConfiguration>
<Issuer>app-mgt</Issuer>
</SSOConfiguration>
<LoginResponse>
<SuccessCallback>/application-mgt</SuccessCallback>
<FailureCallback>
<BadRequest>/pages/error/client-errors/400</BadRequest>
<Unauthorized>/pages/error/client-errors/401</Unauthorized>
<Forbidden>/pages/error/client-errors/403</Forbidden>
<NotFound>/pages/error/client-errors/404</NotFound>
<MethodNotAllowed>/pages/error/client-errors/405</MethodNotAllowed>
<NotAcceptable>/pages/error/client-errors/406</NotAcceptable>
<UnsupportedMediaType>/pages/error/client-errors/415</UnsupportedMediaType>
<InternalServerError>/pages/error/server-errors/500</InternalServerError>
<DefaultPage>/pages/error/default</DefaultPage>
</FailureCallback>
</LoginResponse>
</UIConfigs>
</ApplicationManagementConfiguration> </ApplicationManagementConfiguration>

@ -14,6 +14,7 @@
"antd": "^3.15.0", "antd": "^3.15.0",
"react": "^16.8.4", "react": "^16.8.4",
"react-dom": "^16.8.4", "react-dom": "^16.8.4",
"react-highlight-words": "^0.16.0",
"react-router-config": "^5.0.0", "react-router-config": "^5.0.0",
"react-router-dom": "latest", "react-router-dom": "latest",
"react-scripts": "2.1.8" "react-scripts": "2.1.8"

@ -1,19 +1,26 @@
import React from "react"; import React from "react";
import "antd/dist/antd.css"; import "antd/dist/antd.css";
import { renderRoutes } from "react-router-config"; import RouteWithSubRoutes from "./components/RouteWithSubRoutes";
import {
BrowserRouter as Router,
Link,
} from 'react-router-dom';
class App extends React.Component { class App extends React.Component {
routes;
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.routes = props.routes;
route : props.route
}
} }
render() { render() {
return ( return (
<div> <Router>
{renderRoutes(this.state.route.routes)} <div>
</div> {this.routes.map((route) => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</div>
</Router>
); );
} }

@ -0,0 +1,19 @@
import React from 'react';
import {Route} from 'react-router-dom';
class RouteWithSubRoutes extends React.Component{
props;
constructor(props){
super(props);
this.props = props;
}
render() {
return(
<Route path={this.props.path} render={(props) => (
<this.props.component {...props} routes={this.props.routes}/>
)}/>
);
}
}
export default RouteWithSubRoutes;

@ -1,3 +1,27 @@
.App { .App {
padding: 20px; padding: 20px;
}
.ant-layout-header{
padding: 0;
height: auto;
box-shadow: 0 2px 8px #f0f1f2;
}
.steps-content {
margin-top: 16px;
border: 1px dashed #e9e9e9;
border-radius: 6px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
padding-top: 80px;
}
.steps-action {
margin-top: 24px;
}
.ant-input-affix-wrapper .ant-input{
min-height: 0;
} }

@ -1,41 +1,39 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker'; import * as serviceWorker from './serviceWorker';
import { renderRoutes } from "react-router-config"; import App from "./App";
import Dashboard from "./pages/dashboard/Dashboard"
import Login from "./pages/Login"; import Login from "./pages/Login";
import {BrowserRouter} from "react-router-dom"; import Dashboard from "./pages/dashboard/Dashboard";
import Apps from "./pages/dashboard/apps/Apps";
import AddNewApp from "./pages/dashboard/add-new-app/AddNewApp";
import './index.css';
const routes = [ const routes = [
{ {
component: App, path: '/publisher/Login',
component: Login
},
{
path: '/publisher/dashboard',
component: Dashboard,
routes: [ routes: [
{ {
path: "/publisher", path: '/publisher/dashboard/apps',
exact: true, component: Apps
component: Dashboard,
routes: [
{
path: "/publisher/a",
component: Login
}
]
}, },
{ {
path: "/publisher/login", path: '/publisher/dashboard/new-app',
component: Login component: AddNewApp
} }
] ]
} }
]; ]
ReactDOM.render( <BrowserRouter> ReactDOM.render( <App routes={routes}/>, document.getElementById('root'));
{/* kick it all off with the root route */}
{renderRoutes(routes)}
</BrowserRouter>, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls. // unregister() to register() below. Note this comes with some pitfalls.

@ -1,53 +1,45 @@
import React from "react"; import React from "react";
import { Layout, Menu, Breadcrumb } from 'antd'; import { Layout, Menu, Icon } from 'antd';
const { Header, Content, Footer } = Layout; const { Header, Content, Footer } = Layout;
import styles from './Dashboard.less'; import styles from './Dashboard.less';
import Logo from "../../../public/images/logo.svg"; import Logo from "../../../public/images/logo.svg";
import Login from "../Login"; import {Link, NavLink} from "react-router-dom";
import {renderRoutes} from "react-router-config"; import RouteWithSubRoutes from "../../components/RouteWithSubRoutes"
import {NavLink} from "react-router-dom";
class Dashboard extends React.Component { class Dashboard extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
route : props.route routes : props.routes
} }
console.log(props);
} }
render() { render() {
return ( return (
<Layout className="layout"> <Layout className="layout">
<Header> <Header>
<div style={{backgroundImage: "url(" + { Logo} + ")"}} className={styles.logo}/> <div className={styles.logo}>
<img src={Logo}/>
</div>
<Menu <Menu
theme="light" theme="light"
mode="horizontal" mode="horizontal"
defaultSelectedKeys={['2']} defaultSelectedKeys={['2']}
style={{ lineHeight: '64px' }} style={{ lineHeight: '64px' }}
> >
<Menu.Item key="1">nav 1</Menu.Item> <Menu.Item key="1"><Link to="apps"><Icon type="appstore" />Apps</Link></Menu.Item>
<Menu.Item key="2">nav 2</Menu.Item> <Menu.Item key="2"><Link to="apps"><Icon type="line-chart" />Apps</Link></Menu.Item>
<Menu.Item key="3">nav 3</Menu.Item> <Menu.Item key="3"><Link to="new-app"><Icon type="upload" />Add New App</Link></Menu.Item>
</Menu> </Menu>
</Header> </Header>
<Content style={{ padding: '0 50px' }}> <Content style={{ padding: '0 0' }}>
<Breadcrumb style={{ margin: '16px 0' }}> {this.state.routes.map((route) => (
<Breadcrumb.Item>Home</Breadcrumb.Item> <RouteWithSubRoutes key={route.path} {...route} />
<Breadcrumb.Item>List</Breadcrumb.Item> ))}
<Breadcrumb.Item>App</Breadcrumb.Item>
</Breadcrumb>
<NavLink exact to="/publisher/a" className="nav-link" >
Items
</NavLink>
{/* child routes won't render without this */}
{renderRoutes(this.state.route.routes, { someProp: "these extra props are optional" })}
<div style={{ background: '#fff', padding: 24, minHeight: 280 }}>Content</div>
</Content> </Content>
<Footer style={{ textAlign: 'center' }}> <Footer style={{ textAlign: 'center' }}>
©2019 entgra.io ©2019 entgra.io

@ -1,7 +1,15 @@
.logo { .logo {
width: 120px; width: 120px;
height: 31px; height: 31px;
background: rgba(0,0,0,.2); margin: 16px 0 16px 20px;
margin: 16px 24px 16px 0;
float: left; float: left;
img{
height: 35px;
}
}
input{
min-height: 0;
} }

@ -0,0 +1,117 @@
import React from "react";
import "antd/dist/antd.css";
import {PageHeader, Typography, Card, Steps, Button, message, Row, Col} from "antd";
import Step1 from "./Step1"
import Step2 from "./Step2"
import Step3 from "./Step3"
const Paragraph = Typography;
const routes = [
{
path: 'index',
breadcrumbName: 'publisher',
},
{
path: 'first',
breadcrumbName: 'dashboard',
},
{
path: 'second',
breadcrumbName: 'add new app',
},
];
const Step = Steps.Step;
const steps = [{
title: 'First',
content: Step1
}, {
title: 'Second',
content: Step2,
}, {
title: 'Last',
content: Step3,
}];
class AddNewApp extends React.Component {
constructor(props) {
super(props);
this.state = {
current: 0,
};
}
next() {
const current = this.state.current + 1;
this.setState({current});
}
prev() {
const current = this.state.current - 1;
this.setState({current});
}
render() {
const {current} = this.state;
const Content = steps[current].content;
return (
<div>
<PageHeader
title="Add New App"
breadcrumb={{routes}}
>
<div className="wrap">
<div className="content">
<Paragraph>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempo.
</Paragraph>
</div>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<Row>
<Col span={16} offset={4}>
<Card>
<div>
<Steps current={current}>
{steps.map(item => <Step key={item.title} title={item.title}/>)}
</Steps>
<Content/>
<div className="steps-action">
{
current < steps.length - 1
&& <Button type="primary" onClick={() => this.next()}>Next</Button>
}
{
current === steps.length - 1
&& <Button type="primary"
onClick={() => message.success('Processing complete!')}>Done</Button>
}
{
current > 0
&& (
<Button style={{marginLeft: 8}} onClick={() => this.prev()}>
Previous
</Button>
)
}
</div>
</div>
</Card>
</Col>
</Row>
</div>
</div>
);
}
}
export default AddNewApp;

@ -0,0 +1,153 @@
import React from "react";
import {Form, Input, Button, Select, Divider, Tag, Tooltip, Icon, Checkbox, Row, Col} from "antd";
import styles from './Style.less';
const { Option } = Select;
const { TextArea } = Input;
const InputGroup = Input.Group;
const formItemLayout = {
labelCol: {
span: 8,
},
wrapperCol: {
span: 16,
},
};
class EditableTagGroup extends React.Component {
state = {
tags: [],
inputVisible: false,
inputValue: '',
};
handleClose = (removedTag) => {
const tags = this.state.tags.filter(tag => tag !== removedTag);
console.log(tags);
this.setState({ tags });
}
showInput = () => {
this.setState({ inputVisible: true }, () => this.input.focus());
}
handleInputChange = (e) => {
this.setState({ inputValue: e.target.value });
}
handleInputConfirm = () => {
const { inputValue } = this.state;
let { tags } = this.state;
if (inputValue && tags.indexOf(inputValue) === -1) {
tags = [...tags, inputValue];
}
console.log(tags);
this.setState({
tags,
inputVisible: false,
inputValue: '',
});
}
saveInputRef = input => this.input = input
render() {
const { tags, inputVisible, inputValue } = this.state;
return (
<div>
{tags.map((tag, index) => {
const isLongTag = tag.length > 20;
const tagElem = (
<Tag key={tag} closable={index !== 0} onClose={() => this.handleClose(tag)}>
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
</Tag>
);
return isLongTag ? <Tooltip title={tag} key={tag}>{tagElem}</Tooltip> : tagElem;
})}
{inputVisible && (
<Input
ref={this.saveInputRef}
type="text"
size="small"
style={{ width: 78 }}
value={inputValue}
onChange={this.handleInputChange}
onBlur={this.handleInputConfirm}
onPressEnter={this.handleInputConfirm}
/>
)}
{!inputVisible && (
<Tag
onClick={this.showInput}
style={{ background: '#fff', borderStyle: 'dashed' }}
>
<Icon type="plus" /> New Tag
</Tag>
)}
</div>
);
}
}
class Step1 extends React.Component {
render() {
console.log("hhhoohh");
return (
<div>
<Form layout="horizontal" className={styles.stepForm} hideRequiredMark>
<Form.Item {...formItemLayout} label="Platform">
<Select placeholder="ex: android">
<Option value="Android">Android</Option>
<Option value="iOS">iOS</Option>
</Select>
</Form.Item>
<Form.Item {...formItemLayout} label="Type">
<Select value="Enterprise">
<Option value="Enterprise" selected>Enterprise</Option>
</Select>
</Form.Item>
<Form.Item {...formItemLayout} label="Name">
<Input placeholder="App Name" />
</Form.Item>
<Form.Item {...formItemLayout} label="Description">
<TextArea placeholder="Enter the description" rows={4} />
</Form.Item>
<Form.Item {...formItemLayout} label="Category">
<Select placeholder="Select a category">
<Option value="travel">Travel</Option>
<Option value="entertainment">Entertainment</Option>
</Select>
</Form.Item>
<Form.Item {...formItemLayout} label="Tags">
<EditableTagGroup/>
</Form.Item>
<Form.Item {...formItemLayout} label="Price">
<Input prefix="$" placeholder="00.00" />
</Form.Item>
<Form.Item {...formItemLayout} label="Share with all tenents?">
<Checkbox > </Checkbox>
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Daa">
<InputGroup>
<Row gutter={8}>
<Col span={5}>
<Input placeholder="Key" />
</Col>
<Col span={10}>
<Input placeholder="value" />
</Col>
<Col span={4}>
<Button type="dashed" shape="circle" icon="plus" />
</Col>
</Row>
</InputGroup>
</Form.Item>
</Form>
</div>
);
}
}
export default Step1;

@ -0,0 +1,12 @@
import React from "react"
class Step2 extends React.Component {
render() {
console.log("hhhoohh");
return (
<p>tttoooeeee</p>
);
}
}
export default Step2;

@ -0,0 +1,12 @@
import React from "react"
class Step3 extends React.Component {
render() {
console.log("hhhoohh");
return (
<p>tttoooeeee</p>
);
}
}
export default Step3;

@ -0,0 +1,215 @@
import React from "react";
import "antd/dist/antd.css";
import {Table, Divider, Tag, Card, PageHeader, Typography, Avatar,Input, Button, Icon, Row, Col} from "antd";
import Highlighter from 'react-highlight-words';
const Paragraph = Typography;
const Search = Input.Search;
const routes = [
{
path: 'index',
breadcrumbName: 'Publisher',
},
{
path: 'first',
breadcrumbName: 'Dashboard',
},
{
path: 'second',
breadcrumbName: 'Apps',
},
];
const data = [{
key: '1',
icon: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
name: 'John Brown',
platform: 'android',
type: 'Enterprise',
status: 'published',
version: '13.0.0.1',
updated_at: '27-03-2019 08:27'
},{
key: '2',
icon: 'http://aztechbeat.com/wp-content/uploads/2014/04/confide-app-icon.png',
name: 'Lorem Ipsum',
platform: 'ios',
type: 'Enterprise',
status: 'published',
version: '2.3.1.2',
updated_at: '27-03-2019 09:45'
},{
key: '3',
icon: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRx2Xx1-hnH16EGZHUlT06nOcfGODPoboA2TXKaBVtODto4lJtK',
name: 'Lorem Ipsum',
platform: 'ios',
type: 'Enterprise',
status: 'removed',
version: '4.1.1.0',
updated_at: '27-03-2019 09:46'
}];
class Apps extends React.Component {
routes;
state = {
searchText: '',
};
constructor(props) {
super(props);
this.routes = props.routes;
}
getColumnSearchProps = (dataIndex) => ({
filterDropdown: ({
setSelectedKeys, selectedKeys, confirm, clearFilters,
}) => (
<div style={{ padding: 8 }}>
<Input
ref={node => { this.searchInput = node; }}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm)}
icon="search"
size="small"
style={{ width: 90, marginRight: 8 }}
>
Search
</Button>
<Button
onClick={() => this.handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
</div>
),
filterIcon: filtered => <Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) => record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: (text) => (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
),
})
handleSearch = (selectedKeys, confirm) => {
confirm();
this.setState({ searchText: selectedKeys[0] });
}
handleReset = (clearFilters) => {
clearFilters();
this.setState({ searchText: '' });
}
render() {
const columns = [{
title: '',
dataIndex: 'icon',
key: 'icon',
render: text => <Avatar size="large" src={text}/>,
}, {
title: 'Name',
dataIndex: 'name',
key: 'name',
render: text => <a href="javascript:;">{text}</a>,
...this.getColumnSearchProps('name'),
}, {
title: 'Platform',
dataIndex: 'platform',
key: 'platform',
}, {
title: 'Type',
dataIndex: 'type',
key: 'type',
}, {
title: 'Status',
key: 'status',
dataIndex: 'status',
render: tag => {
let color;
switch (tag) {
case 'published':
color = 'green';
break;
case 'removed':
color = 'red'
break;
case 'default':
color = 'blue'
}
return <Tag color={color} key={tag}>{tag.toUpperCase()}</Tag>;
},
}, {
title: 'Published Version',
dataIndex: 'version',
key: 'version',
}, {
title: 'Last Updated',
dataIndex: 'updated_at',
key: 'updated_at',
},{
title: 'Action',
key: 'action',
render: () => (
<span>
<a href="javascript:;">Edit</a>
<Divider type="vertical" />
<a href="javascript:;">Manage</a>
</span>
),
}];
return (
<div>
<PageHeader
breadcrumb={{routes}}
/>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
<Card>
<Row style={{padding:10}}>
<Col span={6} offset={18}>
<Search
placeholder="search"
onSearch={value => console.log(value)}
style={{ width: 200}}
/>
<Button style={{margin:5}}>Advanced Search</Button>
</Col>
</Row>
<Table columns={columns} dataSource={data}/>
</Card>
</div>
</div>
);
}
}
export default Apps;

@ -21,6 +21,9 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = { const config = {
devtool: "source-map", devtool: "source-map",
output: {
publicPath: '/publisher/' // <---- this
},
watch: false, watch: false,
resolve: { resolve: {
alias: { alias: {

@ -80,9 +80,13 @@ public class PermissionUtils {
} }
public static boolean putPermission(Permission permission) throws PermissionManagementException { public static boolean putPermission(Permission permission) throws PermissionManagementException {
return putPermission(permission.getPath());
}
public static boolean putPermission(String permissionPath) throws PermissionManagementException {
boolean status; boolean status;
try { try {
StringTokenizer tokenizer = new StringTokenizer(permission.getPath(), "/"); StringTokenizer tokenizer = new StringTokenizer(permissionPath, "/");
String lastToken = "", currentToken, tempPath; String lastToken = "", currentToken, tempPath;
while (tokenizer.hasMoreTokens()) { while (tokenizer.hasMoreTokens()) {
currentToken = tokenizer.nextToken(); currentToken = tokenizer.nextToken();
@ -95,7 +99,7 @@ public class PermissionUtils {
status = true; status = true;
} catch (RegistryException e) { } catch (RegistryException e) {
throw new PermissionManagementException("Error occurred while persisting permission : " + throw new PermissionManagementException("Error occurred while persisting permission : " +
permission.getName(), e); permissionPath, e);
} }
return status; return status;
} }

@ -29,7 +29,7 @@
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl</ClassName> <ClassName>org.wso2.carbon.device.application.mgt.core.impl.ReviewManagerImpl</ClassName>
</Extension> </Extension>
<Extension name="LifecycleStateManager"> <Extension name="LifecycleStateManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManger</ClassName> <ClassName>org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager</ClassName>
</Extension> </Extension>
<Extension name="SubscriptionManager"> <Extension name="SubscriptionManager">
<ClassName>org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl</ClassName> <ClassName>org.wso2.carbon.device.application.mgt.core.impl.SubscriptionManagerImpl</ClassName>
@ -56,46 +56,78 @@
If there is a requirement to introduce a new state to the lifecycle, please refer above If there is a requirement to introduce a new state to the lifecycle, please refer above
diagram and add relevant state to the below configuration appropriately. diagram and add relevant state to the below configuration appropriately.
--> -->
<!-- a lifecyclestate can have following properties
<LifecycleState name="In-Review">
<IsAppInstallable>false</IsAppInstallable>
<IsAppUpdatable>true</IsAppUpdatable>
<IsInitialState>false</IsInitialState>
<IsEndState>false</IsEndState>
<Permission>
/device-mgt/applications/life-cycle/in-review
</Permission>
<ProceedingStates>
<State>Rejected</State>
<State>Approved</State>
</ProceedingStates>
</LifecycleState>
-->
<LifecycleStates> <LifecycleStates>
<LifecycleState name="Created"> <LifecycleState name="Created">
<IsAppUpdatable>true</IsAppUpdatable>
<IsInitialState>true</IsInitialState>
<Permission>/device-mgt/applications/life-cycle/create</Permission>
<ProceedingStates> <ProceedingStates>
<State>In-Review</State> <State>In-Review</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="In-Review"> <LifecycleState name="In-Review">
<Permission>/device-mgt/applications/life-cycle/in-review</Permission>
<ProceedingStates> <ProceedingStates>
<State>Rejected</State> <State>Rejected</State>
<State>Approved</State> <State>Approved</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Approved"> <LifecycleState name="Approved">
<Permission>/device-mgt/applications/life-cycle/approve</Permission>
<ProceedingStates> <ProceedingStates>
<State>Published</State> <State>Published</State>
<State>Created</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Rejected"> <LifecycleState name="Rejected">
<Permission>/device-mgt/applications/life-cycle/reject</Permission>
<ProceedingStates> <ProceedingStates>
<State>In-Review</State> <State>Created</State>
<State>Removed</State> <State>Removed</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Published"> <LifecycleState name="Published">
<IsAppInstallable>true</IsAppInstallable>
<Permission>/device-mgt/applications/life-cycle/publish</Permission>
<ProceedingStates> <ProceedingStates>
<State>Unpublished</State> <State>Unpublished</State>
<State>Deprecated</State> <State>Deprecated</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Unpublished"> <LifecycleState name="Unpublished">
<Permission>/device-mgt/applications/life-cycle/unpublish</Permission>
<ProceedingStates> <ProceedingStates>
<State>Published</State>
<State>In-Review</State>
<State>Removed</State> <State>Removed</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Deprecated"> <LifecycleState name="Deprecated">
<Permission>/device-mgt/applications/life-cycle/deprecate</Permission>
<ProceedingStates> <ProceedingStates>
<State>Removed</State> <State>Removed</State>
<State>In-Review</State>
</ProceedingStates> </ProceedingStates>
</LifecycleState> </LifecycleState>
<LifecycleState name="Removed"> <LifecycleState name="Removed">
<IsEndState>true</IsEndState>
<Permission>/device-mgt/applications/life-cycle/remove</Permission>
</LifecycleState> </LifecycleState>
</LifecycleStates> </LifecycleStates>

Loading…
Cancel
Save