Merge remote-tracking branch 'wso2/application-mgt' into wso2-application-mgt

feature/appm-store/pbac
sinthuja 7 years ago
commit bc074ccf59

2
.gitignore vendored

@ -24,3 +24,5 @@ target
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/node_modules/
components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/build/

@ -232,7 +232,6 @@ public interface ApplicationManagementAPI {
required = true)
@Valid Application application);
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ -649,4 +648,98 @@ public interface ApplicationManagementAPI {
name = "version",
value = "Version of the application")
@QueryParam("version") String version);
@GET
@Path("/image-artifacts/{uuid}")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Consumes(MediaType.APPLICATION_JSON)
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "DELETE",
value = "Delete the releases of a particular applicaion",
notes = "This will delete the releases or specific release of an application",
tags = "Application Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "perm:application:get")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully deleted the Application release."),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error occurred while deleting the release of a"
+ "particular application.",
response = ErrorResponse.class)
})
Response getApplicationImageArtifacts(
@ApiParam(
name = "UUID",
value = "Unique identifier of the Application",
required = true)
@PathParam("uuid") String applicationUUID,
@ApiParam(
name = "name",
value = "Name of the artifact to be retrieved",
required = true)
@QueryParam("name") String name,
@ApiParam(
name = "count",
value = "Count of the screen-shot artifact to be retrieved",
required = false)
@QueryParam("count") int count);
@PUT
@Consumes("application/json")
@Path("/{uuid}/{version}/{channel}")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "PUT",
value = "Make the particular application release as default or not",
notes = "Make the particular application release as default or not",
tags = "Application Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "perm:application-mgt:login")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully retrieved the lifecycle states.",
response = List.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Error occurred while getting the life-cycle states.",
response = ErrorResponse.class)
})
Response updateDefaultVersion(
@ApiParam(
name = "UUID",
value = "Unique identifier of the Application",
required = true)
@PathParam("uuid") String applicationUUID,
@ApiParam(
name = "Version",
value = "Version of the Application Release",
required = true)
@PathParam("version") String version,
@ApiParam(
name = "Release Channel",
value = "Release Channel",
required = true)
@PathParam("channel") String channel,
@ApiParam(
name = "isDefault",
value = "Whether to make it default or not",
required = false)
@QueryParam("isDefault") boolean isDefault);
}

@ -425,7 +425,51 @@ public class ApplicationManagementAPIImpl implements ApplicationManagementAPI {
+ applicationUUID).build();
}
} catch (ApplicationManagementException e) {
log.error("Error while deleting application release with the applicaion UUID " + applicationUUID, e);
log.error("Error while deleting application release with the application UUID " + applicationUUID, e);
return APIUtil.getResponse(e, Response.Status.INTERNAL_SERVER_ERROR);
}
}
@Override
@GET
@Path("/image-artifacts/{uuid}")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getApplicationImageArtifacts(@PathParam("uuid") String applicationUUID,
@QueryParam("name") String name, @QueryParam("count") int count) {
if (name == null || name.isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST).entity("Name should not be null. Name is mandatory to"
+ " retrieve the particular image artifact of the release").build();
}
ApplicationStorageManager applicationStorageManager = APIUtil.getApplicationStorageManager();
try {
InputStream imageArtifact = applicationStorageManager.getImageArtifact(applicationUUID, name, count);
FileStreamingOutput fileStreamingOutput = new FileStreamingOutput(imageArtifact);
Response.ResponseBuilder response = Response.status(Response.Status.OK).entity(fileStreamingOutput);
response.header("Content-Disposition", "attachment; filename=\"" + name + "\"");
return response.build();
} catch (ApplicationStorageManagementException e) {
log.error("Application Storage Management Exception while getting the image artifact " + name + " of "
+ "the application with UUID " + applicationUUID, e);
return APIUtil.getResponse(e, Response.Status.INTERNAL_SERVER_ERROR);
}
}
@Override
@PUT
@Consumes("application/json")
@Path("/{uuid}/{version}/{channel}")
public Response updateDefaultVersion(@PathParam("uuid") String applicationUUID, @PathParam("version") String
version, @PathParam("channel") String channel, @QueryParam("isDefault") boolean isDefault) {
ApplicationReleaseManager applicationReleaseManager = APIUtil.getApplicationReleaseManager();
try {
applicationReleaseManager.changeDefaultRelease(applicationUUID, version, isDefault, channel);
return Response.status(Response.Status.OK)
.entity("Successfully changed the default version for the " + "release channel " + channel
+ " for the application UUID " + applicationUUID).build();
} catch (ApplicationManagementException e) {
log.error("Application Release Management Exception while changing the default release for the release "
+ "channel " + channel + " for the application with UUID " + applicationUUID + " for the version "
+ version);
return APIUtil.getResponse(e, Response.Status.INTERNAL_SERVER_ERROR);
}
}

@ -43,14 +43,8 @@ public class Application {
private String description;
private String iconName;
private String bannerName;
private String videoName;
private List<String> screenshots;
private List<String> tags;
private Platform platform;
@ -73,6 +67,8 @@ public class Application {
private Visibility visibility;
private int screenShotCount;
private User user;
public int getId() {
@ -155,22 +151,6 @@ public class Application {
this.description = description;
}
public String getIconName() {
return iconName;
}
public void setIconName(String iconName) {
this.iconName = iconName;
}
public String getBannerName() {
return bannerName;
}
public void setBannerName(String bannerName) {
this.bannerName = bannerName;
}
public String getVideoName() {
return videoName;
}
@ -179,14 +159,6 @@ public class Application {
this.videoName = videoName;
}
public List<String> getScreenshots() {
return screenshots;
}
public void setScreenshots(List<String> screenshots) {
this.screenshots = screenshots;
}
public List<String> getTags() {
return tags;
}
@ -251,6 +223,14 @@ public class Application {
this.user = user;
}
public void setScreenShotCount (int screenShotCount) {
this.screenShotCount = screenShotCount;
}
public int getScreenShotCount() {
return screenShotCount;
}
@Override
public String toString() {
return "UUID : " + uuid + "\tIdentifier : " + identifier + "\tName : " + name + "\tShort Description : "

@ -46,6 +46,8 @@ public class Filter {
private String sortBy;
private String userName;
public int getLimit() {
return limit;
}
@ -102,6 +104,14 @@ public class Filter {
this.sortBy = sortBy;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public boolean hasCondition() {
if (filterProperties != null || searchQuery != null || filter != null) {
return true;
@ -109,5 +119,4 @@ public class Filter {
return false;
}
}

@ -25,7 +25,7 @@ import java.util.List;
/**
* ApplicationReleaseManager is responsible for handling all the operations related with
* {@link org.wso2.carbon.device.application.mgt.common.ApplicationRelease} which involving addition, updation ,
* {@link org.wso2.carbon.device.application.mgt.common.ApplicationRelease} which involving addition, updating ,
* deletion and viewing.
*
*/
@ -59,11 +59,15 @@ public interface ApplicationReleaseManager {
public List<ApplicationRelease> getReleases(String applicationUuid) throws ApplicationManagementException;
/**
* To make a release as the default one for an application.
*
* @param id ID of the ApplicationRelease, that need to be made default.
* To make a particular application release as the default / not default-one
* @param uuid UUID of the application
* @param version Version of the application
* @param isDefault is default or not.
* @param releaseChannel Release channel to make the
* @throws ApplicationManagementException Application Management Exception.
*/
public void makeDefaultRelease(int id) throws ApplicationManagementException;
public void changeDefaultRelease(String uuid, String version, boolean isDefault, String releaseChannel)
throws ApplicationManagementException;
/**
* To update with a new release for an Application.

@ -83,4 +83,16 @@ public interface ApplicationStorageManager {
*/
public void deleteAllApplicationReleaseArtifacts(String applicationUUID) throws
ApplicationStorageManagementException;
/**
* To get particular image artifact of the application.
*
* @param applicationUUID UUID of the application, to retrieve the image artifact.
* @param name Name of the artifact - icon/banner/screenshot
* @param count Position of a parameter to get the image artifact.
* @return the relevant image artifact.
* @throws ApplicationStorageManagementException Application Storage Management Exception.
*/
public InputStream getImageArtifact(String applicationUUID, String name, int count) throws
ApplicationStorageManagementException;
}

@ -35,15 +35,15 @@ public interface ApplicationDAO {
Application createApplication(Application application) throws ApplicationManagementDAOException;
ApplicationList getApplications(Filter filter) throws ApplicationManagementDAOException;
ApplicationList getApplications(Filter filter, int tenantId) throws ApplicationManagementDAOException;
Application getApplication(String uuid) throws ApplicationManagementDAOException;
Application getApplication(String uuid, int tenantId, String userName) throws ApplicationManagementDAOException;
int getApplicationId(String uuid) throws ApplicationManagementDAOException;
int getApplicationId(String uuid, int tenantId) throws ApplicationManagementDAOException;
Application editApplication(Application application, int tenantId) throws ApplicationManagementDAOException;
void deleteApplication(String uuid) throws ApplicationManagementDAOException;
void deleteApplication(String uuid, int tenantId) throws ApplicationManagementDAOException;
int getApplicationCount(Filter filter) throws ApplicationManagementDAOException;
@ -57,10 +57,13 @@ public interface ApplicationDAO {
void addRelease(ApplicationRelease release) throws ApplicationManagementDAOException;
void changeLifecycle(String applicationUUID, String lifecycleIdentifier, String username) throws
void changeLifecycle(String applicationUUID, String lifecycleIdentifier, String username, int tenantId) throws
ApplicationManagementDAOException;
List<LifecycleStateTransition> getNextLifeCycleStates(String applicationUUID, int tenantId) throws
ApplicationManagementDAOException;
void updateScreenShotCount(String applicationUUID, int tenantId, int count) throws
ApplicationManagementDAOException;
}

@ -45,7 +45,8 @@ public interface ApplicationReleaseDAO {
* @return ApplicationRelease for the particular version of the given application
* @throws ApplicationManagementDAOException Application Management DAO Exception.
*/
ApplicationRelease getRelease(String applicationUuid, String versionName) throws ApplicationManagementDAOException;
ApplicationRelease getRelease(String applicationUuid, String versionName, int tenantId) throws
ApplicationManagementDAOException;
/**
* To get all the releases of a particular application.
@ -54,7 +55,8 @@ public interface ApplicationReleaseDAO {
* @return list of the application releases
* @throws ApplicationManagementDAOException Application Management DAO Exception.
*/
List<ApplicationRelease> getApplicationReleases(String applicationUUID) throws ApplicationManagementDAOException;
List<ApplicationRelease> getApplicationReleases(String applicationUUID, int tenantId) throws
ApplicationManagementDAOException;
/**
* To update an Application release.
@ -80,4 +82,16 @@ public interface ApplicationReleaseDAO {
* @throws ApplicationManagementDAOException Application Management DAO Exception.
*/
void deleteReleaseProperties(int id) throws ApplicationManagementDAOException;
/**
* To change the default version of a particular release channel.
* @param uuid UUID of the application
* @param version Version of the application
* @param isDefault true if the request is to make the application as default one unless false
* @throws ApplicationManagementDAOException Application Management DAO Exception.
*/
void changeReleaseDefault(String uuid, String version, boolean isDefault, String releaseChannel, int tenantId)
throws ApplicationManagementDAOException;
}

@ -60,6 +60,7 @@ public class DAOFactory {
switch (databaseEngine) {
case Constants.DataBaseTypes.DB_TYPE_H2:
case Constants.DataBaseTypes.DB_TYPE_MYSQL:
case Constants.DataBaseTypes.DB_TYPE_POSTGRESQL:
return new GenericApplicationDAOImpl();
default:
throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
@ -90,6 +91,7 @@ public class DAOFactory {
switch (databaseEngine) {
case Constants.DataBaseTypes.DB_TYPE_H2:
case Constants.DataBaseTypes.DB_TYPE_MYSQL:
case Constants.DataBaseTypes.DB_TYPE_POSTGRESQL:
return new GenericLifecycleStateImpl();
default:
throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
@ -107,6 +109,7 @@ public class DAOFactory {
switch (databaseEngine) {
case Constants.DataBaseTypes.DB_TYPE_H2:
case Constants.DataBaseTypes.DB_TYPE_MYSQL:
case Constants.DataBaseTypes.DB_TYPE_POSTGRESQL:
return new GenericApplicationReleaseDAOImpl();
default:
throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);

@ -27,7 +27,6 @@ import org.wso2.carbon.device.application.mgt.common.Lifecycle;
import org.wso2.carbon.device.application.mgt.common.LifecycleState;
import org.wso2.carbon.device.application.mgt.common.Platform;
import org.wso2.carbon.device.application.mgt.common.User;
import org.wso2.carbon.device.application.mgt.core.util.JSONUtil;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -63,10 +62,8 @@ public class Util {
application.setIdentifier(rs.getString("IDENTIFIER"));
application.setShortDescription(rs.getString("SHORT_DESCRIPTION"));
application.setDescription(rs.getString("DESCRIPTION"));
application.setIconName(rs.getString("ICON_NAME"));
application.setBannerName(rs.getString("BANNER_NAME"));
application.setScreenShotCount(rs.getInt("SCREEN_SHOT_COUNT"));
application.setVideoName(rs.getString("VIDEO_NAME"));
application.setScreenshots(JSONUtil.jsonArrayStringToList(rs.getString("SCREENSHOTS")));
application.setCreatedAt(rs.getDate("CREATED_AT"));
application.setModifiedAt(rs.getDate("MODIFIED_AT"));
application.setUser(new User(rs.getString("CREATED_BY"), rs.getInt("TENANT_ID")));

@ -33,7 +33,6 @@ import org.wso2.carbon.device.application.mgt.core.dao.common.Util;
import org.wso2.carbon.device.application.mgt.core.dao.impl.AbstractDAOImpl;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil;
import org.wso2.carbon.device.application.mgt.core.util.JSONUtil;
import java.sql.Connection;
import java.sql.Date;
@ -65,34 +64,32 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
ResultSet rs = null;
String sql = "";
boolean isBatchExecutionSupported = ConnectionManagerUtil.isBatchQuerySupported();
int index = 0;
try {
conn = this.getDBConnection();
sql += "INSERT INTO APPM_APPLICATION (UUID, IDENTIFIER, NAME, SHORT_DESCRIPTION, DESCRIPTION, ICON_NAME, "
+ "BANNER_NAME, VIDEO_NAME, SCREENSHOTS, CREATED_BY, CREATED_AT, MODIFIED_AT, "
sql += "INSERT INTO APPM_APPLICATION (UUID, IDENTIFIER, NAME, SHORT_DESCRIPTION, DESCRIPTION, "
+ "VIDEO_NAME, SCREEN_SHOT_COUNT, CREATED_BY, CREATED_AT, MODIFIED_AT, "
+ "APPLICATION_CATEGORY_ID, PLATFORM_ID, TENANT_ID, LIFECYCLE_STATE_ID, "
+ "LIFECYCLE_STATE_MODIFIED_AT, LIFECYCLE_STATE_MODIFIED_BY) VALUES "
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
stmt.setString(1, application.getUuid());
stmt.setString(2, application.getIdentifier());
stmt.setString(3, application.getName());
stmt.setString(4, application.getShortDescription());
stmt.setString(5, application.getDescription());
stmt.setString(6, application.getIconName());
stmt.setString(7, application.getBannerName());
stmt.setString(8, application.getVideoName());
stmt.setString(9, JSONUtil.listToJsonArrayString(application.getScreenshots()));
stmt.setString(10, application.getUser().getUserName());
stmt.setDate(11, new Date(application.getCreatedAt().getTime()));
stmt.setDate(12, new Date(application.getModifiedAt().getTime()));
stmt.setInt(13, application.getCategory().getId());
stmt.setInt(14, application.getPlatform().getId());
stmt.setInt(15, application.getUser().getTenantId());
stmt.setInt(16, application.getCurrentLifecycle().getLifecycleState().getId());
stmt.setDate(17, new Date(application.getCurrentLifecycle().getLifecycleStateModifiedAt().getTime()));
stmt.setString(18, application.getCurrentLifecycle().getGetLifecycleStateModifiedBy());
stmt.setString(++index, application.getUuid());
stmt.setString(++index, application.getIdentifier());
stmt.setString(++index, application.getName());
stmt.setString(++index, application.getShortDescription());
stmt.setString(++index, application.getDescription());
stmt.setString(++index, application.getVideoName());
stmt.setInt(++index, application.getScreenShotCount());
stmt.setString(++index, application.getUser().getUserName());
stmt.setDate(++index, new Date(application.getCreatedAt().getTime()));
stmt.setDate(++index, new Date(application.getModifiedAt().getTime()));
stmt.setInt(++index, application.getCategory().getId());
stmt.setInt(++index, application.getPlatform().getId());
stmt.setInt(++index, application.getUser().getTenantId());
stmt.setInt(++index, application.getCurrentLifecycle().getLifecycleState().getId());
stmt.setDate(++index, new Date(application.getCurrentLifecycle().getLifecycleStateModifiedAt().getTime()));
stmt.setString(++index, application.getCurrentLifecycle().getGetLifecycleStateModifiedBy());
stmt.executeUpdate();
rs = stmt.getGeneratedKeys();
@ -112,7 +109,7 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
@Override
public ApplicationList getApplications(Filter filter) throws ApplicationManagementDAOException {
public ApplicationList getApplications(Filter filter, int tenantId) throws ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug("Getting application data from the database");
log.debug(String.format("Filter: limit=%s, offset=%", filter.getLimit(), filter.getOffset()));
@ -125,6 +122,7 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
ApplicationList applicationList = new ApplicationList();
List<Application> applications = new ArrayList<>();
Pagination pagination = new Pagination();
int index = 0;
if (filter == null) {
throw new ApplicationManagementDAOException("Filter need to be instantiated");
@ -140,20 +138,29 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
+ "LS.DESCRIPTION AS LS_DESCRIPTION FROM APPM_APPLICATION AS APP INNER JOIN APPM_PLATFORM AS "
+ "APL ON APP.PLATFORM_ID = APL.ID INNER JOIN APPM_APPLICATION_CATEGORY AS CAT ON "
+ "APP.APPLICATION_CATEGORY_ID = CAT.ID INNER JOIN APPM_LIFECYCLE_STATE AS "
+ "LS ON APP.LIFECYCLE_STATE_ID = LS.ID ";
+ "LS ON APP.LIFECYCLE_STATE_ID = LS.ID WHERE APP.TENANT_ID = ? ";
String userName = filter.getUserName();
if (!userName.equals("ALL")) {
sql += " AND APP.CREATED_BY = ? ";
}
if (filter.getSearchQuery() != null && !filter.getSearchQuery().isEmpty()) {
sql += "WHERE APP.NAME LIKE ? ";
sql += "AND APP.NAME LIKE ? ";
}
sql += "LIMIT ?,?;";
sql += "LIMIT ? OFFSET ?;";
stmt = conn.prepareStatement(sql);
int index = 0;
stmt.setInt(++index, tenantId);
if (!userName.equals("ALL")) {
stmt.setString(++index, userName);
}
if (filter.getSearchQuery() != null && !filter.getSearchQuery().isEmpty()) {
stmt.setString(++index, "%" + filter.getSearchQuery() + "%");
}
stmt.setInt(++index, filter.getOffset());
stmt.setInt(++index, filter.getLimit());
stmt.setInt(++index, filter.getOffset());
rs = stmt.executeQuery();
@ -183,11 +190,14 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
applicationList.setApplications(applications);
applicationList.setPagination(pagination);
} catch (SQLException e) {
throw new ApplicationManagementDAOException("Error occurred while getting application List", e);
throw new ApplicationManagementDAOException("Error occurred while getting application list for the tenant"
+ " " + tenantId + ". While executing " + sql, e);
} catch (JSONException e) {
throw new ApplicationManagementDAOException("Error occurred while parsing JSON", e);
throw new ApplicationManagementDAOException("Error occurred while parsing JSON, while getting application"
+ " list for the tenant " + tenantId, e);
} catch (DBConnectionException e) {
throw new ApplicationManagementDAOException("Error occurred while obtaining the DB connection.", e);
throw new ApplicationManagementDAOException("Error occurred while obtaining the DB connection while "
+ "getting application list for the tenant " + tenantId, e);
} finally {
Util.cleanupResources(stmt, rs);
}
@ -243,11 +253,12 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
}
@Override
public Application getApplication(String uuid) throws ApplicationManagementDAOException {
public Application getApplication(String uuid, int tenantId, String userName) throws
ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug("Getting application with the UUID(" + uuid + ") from the database");
}
Connection conn = null;
Connection conn;
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = "";
@ -260,10 +271,17 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
+ "LS.DESCRIPTION AS LS_DESCRIPTION FROM APPM_APPLICATION AS APP INNER JOIN APPM_PLATFORM AS "
+ "APL ON APP.PLATFORM_ID = APL.ID INNER JOIN APPM_APPLICATION_CATEGORY AS CAT ON "
+ "APP.APPLICATION_CATEGORY_ID = CAT.ID INNER JOIN APPM_LIFECYCLE_STATE AS "
+ "LS ON APP.LIFECYCLE_STATE_ID = LS.ID WHERE UUID = ?";
+ "LS ON APP.LIFECYCLE_STATE_ID = LS.ID WHERE UUID = ? AND APP.TENANT_ID = ? ";
stmt = conn.prepareStatement(sql);
stmt.setString(1, uuid);
stmt.setInt(2, tenantId);
if (!userName.equals("ALL")) {
sql += "AND APP.CREATED_BY = ?";
stmt.setString(3, userName);
}
rs = stmt.executeQuery();
if (log.isDebugEnabled()) {
@ -301,8 +319,8 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
}
@Override
public void changeLifecycle(String applicationUUID, String lifecycleIdentifier, String userName) throws
ApplicationManagementDAOException {
public void changeLifecycle(String applicationUUID, String lifecycleIdentifier, String userName, int tenantId)
throws ApplicationManagementDAOException {
if (log.isDebugEnabled()) {
log.debug("Change Life cycle status change " + lifecycleIdentifier + "request received to the DAO "
+ "level for the application with " + "the UUID '" + applicationUUID + "' from the user "
@ -314,12 +332,14 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
conn = this.getDBConnection();
String sql = "UPDATE APPM_APPLICATION SET "
+ "LIFECYCLE_STATE_ID = (SELECT ID FROM APPM_LIFECYCLE_STATE WHERE IDENTIFIER = ?), "
+ "LIFECYCLE_STATE_MODIFIED_BY = ?, LIFECYCLE_STATE_MODIFIED_AT = ? WHERE UUID = ?";
+ "LIFECYCLE_STATE_MODIFIED_BY = ?, LIFECYCLE_STATE_MODIFIED_AT = ? WHERE UUID = ? AND TENANT_ID "
+ "= ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, lifecycleIdentifier);
stmt.setString(2, userName);
stmt.setDate(3, new Date(System.currentTimeMillis()));
stmt.setString(4, applicationUUID);
stmt.setInt(5, tenantId);
stmt.executeUpdate();
} catch (DBConnectionException e) {
throw new ApplicationManagementDAOException("Error occurred while obtaining the DB connection.", e);
@ -341,13 +361,14 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
String sql = "SELECT STATE.NAME, TRANSITION.DESCRIPTION, TRANSITION.PERMISSION FROM ( SELECT * FROM "
+ "APPM_LIFECYCLE_STATE ) STATE RIGHT JOIN (SELECT * FROM APPM_LIFECYCLE_STATE_TRANSITION WHERE "
+ "INITIAL_STATE = (SELECT LIFECYCLE_STATE_ID FROM APPM_APPLICATION WHERE UUID = ?)) "
+ "INITIAL_STATE = (SELECT LIFECYCLE_STATE_ID FROM APPM_APPLICATION WHERE UUID = ? AND TENANT_ID = ?)) "
+ "TRANSITION ON TRANSITION.NEXT_STATE = STATE.ID";
try {
connection = this.getDBConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, applicationUUID);
preparedStatement.setInt(2, tenantId);
resultSet = preparedStatement.executeQuery();
List<LifecycleStateTransition> lifecycleStateTransitions = new ArrayList<>();
@ -370,6 +391,31 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
}
}
@Override
public void updateScreenShotCount(String applicationUUID, int tenantId, int count)
throws ApplicationManagementDAOException {
Connection connection;
PreparedStatement statement = null;
String sql = "UPDATE APPM_APPLICATION SET SCREEN_SHOT_COUNT = ? where UUID = ? and TENANT_ID = ?";
try {
connection = this.getDBConnection();
statement = connection.prepareStatement(sql);
statement.setInt(1, count);
statement.setString(2, applicationUUID);
statement.setInt(3, tenantId);
statement.executeUpdate();
} catch (DBConnectionException e) {
throw new ApplicationManagementDAOException("Database connection while trying to update the screen-shot "
+ "count for the application with UUID " + applicationUUID + " for the tenant " + tenantId);
} catch (SQLException e) {
throw new ApplicationManagementDAOException("SQL exception while executing the query '" + sql + "' .", e);
} finally {
Util.cleanupResources(statement, null);
}
}
@Override
public Application editApplication(Application application, int tenantId) throws ApplicationManagementDAOException {
Connection conn;
@ -379,35 +425,33 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
try {
conn = this.getDBConnection();
int index = 0;
sql += "UPDATE APPM_APPLICATION SET NAME = IFNULL (?, NAME), SHORT_DESCRIPTION = IFNULL "
+ "(?, SHORT_DESCRIPTION), DESCRIPTION = IFNULL (?, DESCRIPTION), ICON_NAME = IFNULL (?, ICON_NAME)"
+ ", BANNER_NAME = IFNULL (?, BANNER_NAME), VIDEO_NAME = IFNULL (?, VIDEO_NAME), "
+ "SCREENSHOTS = IFNULL (?, SCREENSHOTS), MODIFIED_AT = IFNULL (?, MODIFIED_AT), ";
sql += "UPDATE APPM_APPLICATION SET NAME = COALESCE (?, NAME), SHORT_DESCRIPTION = COALESCE "
+ "(?, SHORT_DESCRIPTION), DESCRIPTION = COALESCE (?, DESCRIPTION), SCREEN_SHOT_COUNT = "
+ "COALESCE (?, SCREEN_SHOT_COUNT), VIDEO_NAME = COALESCE (?, VIDEO_NAME), MODIFIED_AT = COALESCE "
+ "(?, MODIFIED_AT), ";
if (application.getPayment() != null) {
sql += " IS_FREE = IFNULL (?, IS_FREE), ";
sql += " IS_FREE = COALESCE (?, IS_FREE), ";
if (application.getPayment().getPaymentCurrency() != null) {
sql += "PAYMENT_CURRENCY = IFNULL (?, PAYMENT_CURRENCY), ";
sql += "PAYMENT_CURRENCY = COALESCE (?, PAYMENT_CURRENCY), ";
}
sql += "PAYMENT_PRICE = IFNULL (?, PAYMENT_PRICE), ";
sql += "PAYMENT_PRICE = COALESCE (?, PAYMENT_PRICE), ";
}
if (application.getCategory() != null && application.getCategory().getId() != 0) {
sql += "APPLICATION_CATEGORY_ID = IFNULL (?, APPLICATION_CATEGORY_ID), ";
sql += "APPLICATION_CATEGORY_ID = COALESCE (?, APPLICATION_CATEGORY_ID), ";
}
if (application.getPlatform() != null && application.getPlatform().getId() != 0) {
sql += "PLATFORM_ID = IFNULL (?, PLATFORM_ID), ";
sql += "PLATFORM_ID = COALESCE (?, PLATFORM_ID), ";
}
sql += "TENANT_ID = IFNULL (?, TENANT_ID) WHERE UUID = ?";
sql += "TENANT_ID = COALESCE (?, TENANT_ID) WHERE UUID = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(++index, application.getName());
stmt.setString(++index, application.getShortDescription());
stmt.setString(++index, application.getDescription());
stmt.setString(++index, application.getIconName());
stmt.setString(++index, application.getBannerName());
stmt.setInt(++index, application.getScreenShotCount());
stmt.setString(++index, application.getVideoName());
stmt.setString(++index, JSONUtil.listToJsonArrayString(application.getScreenshots()));
stmt.setDate(++index, new Date(application.getModifiedAt().getTime()));
if (application.getPayment() != null) {
stmt.setBoolean(++index, application.getPayment().isFreeApp());
@ -427,7 +471,7 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
stmt.setString(++index, application.getUuid());
stmt.executeUpdate();
application.setId(getApplicationId(application.getUuid()));
application.setId(getApplicationId(application.getUuid(), tenantId));
sql = "DELETE FROM APPM_APPLICATION_TAG WHERE APPLICATION_ID = ?";
stmt = conn.prepareStatement(sql);
@ -499,14 +543,15 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
}
@Override
public void deleteApplication(String uuid) throws ApplicationManagementDAOException {
public void deleteApplication(String uuid, int tenantId) throws ApplicationManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
try {
conn = this.getDBConnection();
String sql = "DELETE FROM APPM_APPLICATION WHERE UUID = ?";
String sql = "DELETE FROM APPM_APPLICATION WHERE UUID = ? AND TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, uuid);
stmt.setInt(2, tenantId);
stmt.executeUpdate();
} catch (DBConnectionException e) {
@ -561,7 +606,7 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
}
@Override
public int getApplicationId(String uuid) throws ApplicationManagementDAOException {
public int getApplicationId(String uuid, int tenantId) throws ApplicationManagementDAOException {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
@ -569,9 +614,10 @@ public class GenericApplicationDAOImpl extends AbstractDAOImpl implements Applic
int id = 0;
try {
conn = this.getDBConnection();
sql = "SELECT ID FROM APPM_APPLICATION WHERE UUID = ?";
sql = "SELECT ID FROM APPM_APPLICATION WHERE UUID = ? AND TENANT_ID = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, uuid);
stmt.setInt(2, tenantId);
rs = stmt.executeQuery();
if (rs.next()) {
id = rs.getInt(1);

@ -27,7 +27,12 @@ import org.wso2.carbon.device.application.mgt.core.dao.impl.AbstractDAOImpl;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil;
import java.sql.*;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -44,6 +49,10 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
Connection connection;
PreparedStatement statement = null;
ResultSet resultSet = null;
if (applicationRelease.isDefault()) {
}
String sql = "insert into APPM_APPLICATION_RELEASE(VERSION_NAME, RESOURCE, RELEASE_CHANNEL ,"
+ "RELEASE_DETAILS, CREATED_AT, APPM_APPLICATION_ID, IS_DEFAULT) values (?, ?, ?, ?, ?, ?, ?)";
int index = 0;
@ -79,13 +88,13 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
}
@Override
public ApplicationRelease getRelease(String applicationUuid, String versionName)
public ApplicationRelease getRelease(String applicationUuid, String versionName, int tenantId)
throws ApplicationManagementDAOException {
Connection connection;
PreparedStatement statement = null;
ResultSet resultSet = null;
String sql = "SELECT * FROM APPM_APPLICATION_RELEASE WHERE VERSION_NAME = ? AND APPM_APPLICATION_ID = "
+ "(SELECT ID FROM APPM_APPLICATION WHERE UUID = ?)";
+ "(SELECT ID FROM APPM_APPLICATION WHERE UUID = ? and TENANT_ID = ?)";
ApplicationRelease applicationRelease = null;
ResultSet rsProperties = null;
@ -94,6 +103,7 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
statement = connection.prepareStatement(sql);
statement.setString(1, versionName);
statement.setString(2, applicationUuid);
statement.setInt(3, tenantId);
resultSet = statement.executeQuery();
if (resultSet.next()) {
@ -132,13 +142,13 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
}
@Override
public List<ApplicationRelease> getApplicationReleases(String applicationUUID)
public List<ApplicationRelease> getApplicationReleases(String applicationUUID, int tenantId)
throws ApplicationManagementDAOException {
Connection connection;
PreparedStatement statement = null;
ResultSet resultSet = null;
String sql = "SELECT * FROM APPM_APPLICATION_RELEASE WHERE APPM_APPLICATION_ID = (SELECT ID FROM "
+ "APPM_APPLICATION WHERE UUID = ?)";
+ "APPM_APPLICATION WHERE UUID = ? AND TENANT_ID = ?)";
List<ApplicationRelease> applicationReleases = new ArrayList<>();
ResultSet rsProperties = null;
@ -146,6 +156,7 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
connection = this.getDBConnection();
statement = connection.prepareStatement(sql);
statement.setString(1, applicationUUID);
statement.setInt(2, tenantId);
resultSet = statement.executeQuery();
while (resultSet.next()) {
@ -264,6 +275,40 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
}
}
@Override
public void changeReleaseDefault(String uuid, String version, boolean isDefault, String releaseChannel,
int tenantId) throws ApplicationManagementDAOException {
Connection connection;
PreparedStatement statement = null;
String sql = "UPDATE APPM_APPLICATION_RELEASE SET IS_DEFAULT = ? AND RELEASE_CHANNEL = ? WHERE "
+ "APPM_APPLICATION_ID = (SELECT ID from APPM_APPLICATION WHERE UUID = ? AND TENANT_ID = ?) "
+ "AND VERSION_NAME = ?";
try {
if (isDefault) {
removeDefaultReleases(uuid, releaseChannel, tenantId);
}
connection = this.getDBConnection();
statement = connection.prepareStatement(sql);
statement.setBoolean(1, isDefault);
statement.setString(2, releaseChannel.toUpperCase());
statement.setString(3, uuid);
statement.setInt(4, tenantId);
statement.setString(5, version);
statement.executeUpdate();
} catch (DBConnectionException e) {
throw new ApplicationManagementDAOException(
"Database Connection exception while try to change the " + "default release of the release channel "
+ releaseChannel + " for the application " + uuid, e);
} catch (SQLException e) {
throw new ApplicationManagementDAOException(
"SQL Exception while trying to change the default release of " + "the release channel "
+ releaseChannel + " for the application " + uuid, e);
} finally {
Util.cleanupResources(statement, null);
}
}
/**
* To insert the application release properties.
* @param connection Database Connection
@ -294,4 +339,30 @@ public class GenericApplicationReleaseDAOImpl extends AbstractDAOImpl implements
}
}
}
/**
* To make all the releases of particular release channel as non-default ones.
*
* @param uuid UUID of the Application.
* @param releaseChannel ReleaseChannel for which we need to make all the releases as non-default ones.
* @param tenantId ID of the tenant.
* @throws DBConnectionException Database Connection Exception.
* @throws SQLException SQL Exception.
*/
private void removeDefaultReleases(String uuid, String releaseChannel, int tenantId)
throws DBConnectionException, SQLException {
PreparedStatement statement = null;
try {
Connection connection = this.getDBConnection();
String sql = "UPDATE APPM_APPLICATION_RELEASE SET IS_DEFAULT = FALSE WHERE APPM_APPLICATION_ID = (SELECT "
+ "ID from APPM_APPLICATION WHERE UUID = ? AND TENANT_ID = ?) AND RELEASE_CHANNEL = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, uuid);
statement.setInt(2, tenantId);
statement.setString(3, releaseChannel.toUpperCase());
statement.executeUpdate();
} finally {
Util.cleanupResources(statement, null);
}
}
}

@ -46,7 +46,6 @@ import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -158,10 +157,10 @@ public class ApplicationManagerImpl implements ApplicationManager {
try {
ApplicationDAO applicationDAO = DAOFactory.getApplicationDAO();
ConnectionManagerUtil.beginDBTransaction();
int appId = applicationDAO.getApplicationId(uuid);
int appId = applicationDAO.getApplicationId(uuid, tenantId);
applicationDAO.deleteTags(appId);
applicationDAO.deleteProperties(appId);
applicationDAO.deleteApplication(uuid);
applicationDAO.deleteApplication(uuid, tenantId);
ConnectionManagerUtil.commitDBTransaction();
} catch (ApplicationManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
@ -174,15 +173,26 @@ public class ApplicationManagerImpl implements ApplicationManager {
@Override
public ApplicationList getApplications(Filter filter) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
try {
if (isAuthorized(userName, tenantId, CarbonConstants.UI_ADMIN_PERMISSION_COLLECTION)) {
userName = "ALL";
}
} catch (UserStoreException e) {
throw new ApplicationManagementException("User-store exception while checking whether the user " +
userName + " of tenant " + tenantId + " has the publisher permission");
}
filter.setUserName(userName);
try {
ConnectionManagerUtil.openDBConnection();
ApplicationDAO applicationDAO = DAOFactory.getApplicationDAO();
return applicationDAO.getApplications(filter);
return applicationDAO.getApplications(filter, tenantId);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
@Override
@ -190,6 +200,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
ApplicationManagementException {
boolean isAvailableNextState = false;
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
List<LifecycleStateTransition> nextLifeCycles = getLifeCycleStates(applicationUuid);
for (LifecycleStateTransition lifecycleStateTransition : nextLifeCycles) {
@ -210,7 +221,7 @@ public class ApplicationManagerImpl implements ApplicationManager {
try {
ConnectionManagerUtil.beginDBTransaction();
ApplicationDAO applicationDAO = DAOFactory.getApplicationDAO();
applicationDAO.changeLifecycle(applicationUuid, lifecycleIdentifier, userName);
applicationDAO.changeLifecycle(applicationUuid, lifecycleIdentifier, userName, tenantId);
ConnectionManagerUtil.commitDBTransaction();
} catch (ApplicationManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
@ -278,20 +289,25 @@ public class ApplicationManagerImpl implements ApplicationManager {
@Override
public Application getApplication(String uuid) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
try {
if (isAuthorized(userName, tenantId, CarbonConstants.UI_ADMIN_PERMISSION_COLLECTION)) {
userName = "ALL";
}
} catch (UserStoreException e) {
throw new ApplicationManagementException(
"User-store exception while getting application with the UUID " + uuid);
}
try {
ConnectionManagerUtil.openDBConnection();
return DAOFactory.getApplicationDAO().getApplication(uuid);
return DAOFactory.getApplicationDAO().getApplication(uuid, tenantId, userName);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
public void uploadArtifacts(String applicationUUID, InputStream iconFileStream, InputStream bannerFileStream,
List<InputStream> screenShotStreams)
throws ApplicationManagementException {
}
/**
* To check whether current user is application owner or admin.
*
@ -310,7 +326,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
}
try {
ConnectionManagerUtil.openDBConnection();
Application application = DAOFactory.getApplicationDAO().getApplication(applicationUUID);
Application application = DAOFactory.getApplicationDAO()
.getApplication(applicationUUID, tenantId, userName);
return application.getUser().getUserName().equals(userName)
&& application.getUser().getTenantId() == tenantId;
} finally {

@ -20,6 +20,7 @@ package org.wso2.carbon.device.application.mgt.core.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.application.mgt.common.Application;
import org.wso2.carbon.device.application.mgt.common.ApplicationRelease;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
@ -64,6 +65,7 @@ public class ApplicationReleaseManagerImpl implements ApplicationReleaseManager
@Override
public ApplicationRelease getRelease(String applicationUuid, String version) throws
ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
Application application = validateApplication(applicationUuid);
if (log.isDebugEnabled()) {
log.debug("Application release retrieval request is received for the application " +
@ -71,7 +73,7 @@ public class ApplicationReleaseManagerImpl implements ApplicationReleaseManager
}
try {
ConnectionManagerUtil.openDBConnection();
return DAOFactory.getApplicationReleaseDAO().getRelease(applicationUuid, version);
return DAOFactory.getApplicationReleaseDAO().getRelease(applicationUuid, version, tenantId);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
@ -79,6 +81,7 @@ public class ApplicationReleaseManagerImpl implements ApplicationReleaseManager
@Override
public List<ApplicationRelease> getReleases(String applicationUuid) throws ApplicationManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
Application application = validateApplication(applicationUuid);
if (log.isDebugEnabled()) {
log.debug("Request is received to retrieve all the releases related with the application " +
@ -86,15 +89,33 @@ public class ApplicationReleaseManagerImpl implements ApplicationReleaseManager
}
try {
ConnectionManagerUtil.openDBConnection();
return DAOFactory.getApplicationReleaseDAO().getApplicationReleases(applicationUuid);
return DAOFactory.getApplicationReleaseDAO().getApplicationReleases(applicationUuid, tenantId);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
@Override
public void makeDefaultRelease(int id) throws ApplicationManagementException {
public void changeDefaultRelease(String uuid, String version, boolean isDefault, String releaseChannel) throws
ApplicationManagementException {
Application application = validateApplication(uuid);
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
if (log.isDebugEnabled()) {
log.debug("Request received to change the default release for the release channel " + releaseChannel
+ "for the application " + application.toString());
}
try {
ConnectionManagerUtil.beginDBTransaction();
DAOFactory.getApplicationReleaseDAO()
.changeReleaseDefault(uuid, version, isDefault, releaseChannel, tenantId);
ConnectionManagerUtil.commitDBTransaction();
} catch (ApplicationManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
throw e;
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
@Override

@ -21,12 +21,18 @@ package org.wso2.carbon.device.application.mgt.core.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.application.mgt.common.Application;
import org.wso2.carbon.device.application.mgt.common.ApplicationRelease;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationStorageManagementException;
import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException;
import org.wso2.carbon.device.application.mgt.common.exception.TransactionManagementException;
import org.wso2.carbon.device.application.mgt.common.services.ApplicationStorageManager;
import org.wso2.carbon.device.application.mgt.core.dao.common.DAOFactory;
import org.wso2.carbon.device.application.mgt.core.exception.ApplicationManagementDAOException;
import org.wso2.carbon.device.application.mgt.core.internal.DataHolder;
import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil;
import org.wso2.carbon.device.application.mgt.core.util.Constants;
import java.io.File;
@ -36,6 +42,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
/**
@ -47,18 +54,8 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
@Override
public void uploadImageArtifacts(String applicationUUID, InputStream iconFileStream, InputStream bannerFileStream,
List<InputStream> screenShotStreams) throws ApplicationStorageManagementException {
Application application;
try {
application = DataHolder.getInstance().getApplicationManager().getApplication(applicationUUID);
} catch (ApplicationManagementException e) {
throw new ApplicationStorageManagementException(
"Exception while retrieving the application details for " + "the application with UUID "
+ applicationUUID);
}
if (application == null) {
throw new ApplicationStorageManagementException("Application with UUID " + applicationUUID + " does not "
+ "exist. Cannot upload the artifacts to non-existing application.");
}
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
Application application = validateApplication(applicationUUID);
String artifactDirectoryPath = Constants.artifactPath + application.getId();
if (log.isDebugEnabled()) {
log.debug("Artifact Directory Path for saving the artifacts related with application " + applicationUUID
@ -66,10 +63,8 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
createArtifactDirectory(artifactDirectoryPath);
if (iconFileStream != null) {
String iconName = application.getIconName();
iconName = (iconName == null) ? "icon" : iconName;
try {
saveFile(iconFileStream, artifactDirectoryPath + File.separator + iconName);
saveFile(iconFileStream, artifactDirectoryPath + File.separator + Constants.IMAGE_ARTIFACTS[0]);
} catch (IOException e) {
throw new ApplicationStorageManagementException(
"IO Exception while saving the icon file in the server for " + "the application "
@ -77,10 +72,8 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
}
if (bannerFileStream != null) {
String bannerName = application.getBannerName();
bannerName = (bannerName == null) ? "banner" : bannerName;
try {
saveFile(bannerFileStream, artifactDirectoryPath + File.separator + bannerName);
saveFile(bannerFileStream, artifactDirectoryPath + File.separator + Constants.IMAGE_ARTIFACTS[1]);
} catch (IOException e) {
throw new ApplicationStorageManagementException(
"IO Exception while saving the banner file in the server for" + " the application "
@ -88,18 +81,11 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
}
if (screenShotStreams != null) {
int count = 1;
int count = application.getScreenShotCount() + 1;
String screenshotName;
List<String> screenShotNames = application.getScreenshots();
boolean isScreenShotNameExist = (screenShotNames == null || screenShotNames.isEmpty());
int screenShotNameLength = isScreenShotNameExist ? screenShotNames.size() : 0;
for (InputStream screenshotStream : screenShotStreams) {
try {
if (isScreenShotNameExist && count <= screenShotNameLength) {
screenshotName = screenShotNames.get(count);
} else {
screenshotName = "screenshot_" + count;
}
screenshotName = Constants.IMAGE_ARTIFACTS[2] + count;
saveFile(screenshotStream, artifactDirectoryPath + File.separator + screenshotName);
count++;
} catch (IOException e) {
@ -108,24 +94,35 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
e);
}
}
try {
ConnectionManagerUtil.beginDBTransaction();
DAOFactory.getApplicationDAO().updateScreenShotCount(applicationUUID, tenantId, count - 1);
ConnectionManagerUtil.commitDBTransaction();
} catch (TransactionManagementException e) {
ConnectionManagerUtil.rollbackDBTransaction();
throw new ApplicationStorageManagementException("Transaction Management exception while trying to "
+ "update the screen-shot count of the application " + applicationUUID + " for the tenant "
+ tenantId, e);
} catch (DBConnectionException e) {
ConnectionManagerUtil.rollbackDBTransaction();
throw new ApplicationStorageManagementException("Database connection management exception while "
+ "trying to update the screen-shot count for the application " + applicationUUID + " for the"
+ " tenant " + tenantId, e);
} catch (ApplicationManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
throw new ApplicationStorageManagementException("Application Management DAO exception while trying to"
+ " update the screen-shot count for the application " + applicationUUID + " for the tenant "
+ tenantId, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
}
@Override
public void uploadReleaseArtifacts(String applicationUUID, String versionName, InputStream binaryFile)
throws ApplicationStorageManagementException {
Application application;
try {
application = DataHolder.getInstance().getApplicationManager().getApplication(applicationUUID);
} catch (ApplicationManagementException e) {
throw new ApplicationStorageManagementException(
"Exception while retrieving the application details for " + "the application with UUID "
+ applicationUUID);
}
if (application == null) {
throw new ApplicationStorageManagementException("Application with UUID " + applicationUUID + " does not "
+ "exist. Cannot upload release artifacts for not existing application.");
}
Application application = validateApplication(applicationUUID);
String artifactDirectoryPath = Constants.artifactPath + application.getId();
if (log.isDebugEnabled()) {
log.debug("Artifact Directory Path for saving the application release related artifacts related with "
@ -148,18 +145,7 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
@Override
public InputStream getReleasedArtifacts(String applicationUUID, String versionName)
throws ApplicationStorageManagementException {
Application application;
try {
application = DataHolder.getInstance().getApplicationManager().getApplication(applicationUUID);
} catch (ApplicationManagementException e) {
throw new ApplicationStorageManagementException(
"Exception while retrieving the application details for " + "the application with UUID "
+ applicationUUID);
}
if (application == null) {
throw new ApplicationStorageManagementException("Application with UUID " + applicationUUID + " does not "
+ "exist. Cannot retrieve release artifacts for not existing application.");
}
Application application = validateApplication(applicationUUID);
String artifactPath = Constants.artifactPath + application.getId() + File.separator + versionName;
if (log.isDebugEnabled()) {
@ -182,18 +168,7 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
@Override
public void deleteApplicationArtifacts(String applicationUUID) throws ApplicationStorageManagementException {
Application application;
try {
application = DataHolder.getInstance().getApplicationManager().getApplication(applicationUUID);
} catch (ApplicationManagementException e) {
throw new ApplicationStorageManagementException(
"Exception while retrieving the application details for " + "the application with UUID "
+ applicationUUID);
}
if (application == null) {
throw new ApplicationStorageManagementException("Application with UUID " + applicationUUID + " does not "
+ "exist. Cannot delete the artifacts of a non-existing application.");
}
Application application = validateApplication(applicationUUID);
String artifactDirectoryPath = Constants.artifactPath + application.getId();
File artifactDirectory = new File(artifactDirectoryPath);
@ -205,18 +180,7 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
@Override
public void deleteApplicationReleaseArtifacts(String applicationUUID, String version)
throws ApplicationStorageManagementException {
Application application;
try {
application = DataHolder.getInstance().getApplicationManager().getApplication(applicationUUID);
} catch (ApplicationManagementException e) {
throw new ApplicationStorageManagementException(
"Exception while retrieving the application details for " + "the application with UUID "
+ applicationUUID);
}
if (application == null) {
throw new ApplicationStorageManagementException("Application with UUID " + applicationUUID + " does not "
+ "exist. Cannot delete the artifacts of a non-existing application.");
}
Application application = validateApplication(applicationUUID);
String artifactPath = Constants.artifactPath + application.getId() + File.separator + version;
File artifact = new File(artifactPath);
@ -225,8 +189,10 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
}
@Override public void deleteAllApplicationReleaseArtifacts(String applicationUUID)
throws ApplicationStorageManagementException {
@Override
public void deleteAllApplicationReleaseArtifacts(String applicationUUID) throws
ApplicationStorageManagementException {
Application application = validateApplication(applicationUUID);
try {
List<ApplicationRelease> applicationReleases = DataHolder.getInstance().getReleaseManager()
.getReleases(applicationUUID);
@ -240,6 +206,31 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
}
@Override
public InputStream getImageArtifact(String applicationUUID, String name, int count) throws
ApplicationStorageManagementException {
Application application = validateApplication(applicationUUID);
validateImageArtifactNames(name);
String imageArtifactPath = Constants.artifactPath + application.getId() + File.separator + name.toLowerCase();
if (name.equalsIgnoreCase(Constants.IMAGE_ARTIFACTS[2])) {
imageArtifactPath += count;
}
File imageFile = new File(imageArtifactPath);
if (!imageFile.exists()) {
throw new ApplicationStorageManagementException(
"Image artifact " + name + " does not exist for the " + "application with UUID " + applicationUUID);
} else {
try {
return new FileInputStream(imageArtifactPath);
} catch (FileNotFoundException e) {
throw new ApplicationStorageManagementException(
"File not found exception while trying to get the image artifact " + name + " for the "
+ "application " + applicationUUID, e);
}
}
}
/**
* To save a file in a given location.
*
@ -294,4 +285,44 @@ public class ApplicationStorageManagerImpl implements ApplicationStorageManager
}
artifactDirectory.delete();
}
/**
* To validate the image artifact names.
* @param name Name of the image artifact.
* @throws ApplicationStorageManagementException Application Storage Management Exception
*/
private void validateImageArtifactNames(String name) throws ApplicationStorageManagementException {
if (name == null || name.isEmpty()) {
throw new ApplicationStorageManagementException("Image artifact name cannot be null or empty. It is a "
+ "required parameter");
}
if (!Arrays.asList(Constants.IMAGE_ARTIFACTS).contains(name.toLowerCase())) {
throw new ApplicationStorageManagementException("Provide artifact name is not valid. Please provide the "
+ "name among " + Arrays.toString(Constants.IMAGE_ARTIFACTS));
}
}
/**
* To validate the Application before storing and retrieving the artifacts of a particular application.
*
* @param uuid UUID of the Application
* @return {@link Application} if it is validated
* @throws ApplicationStorageManagementException Application Storage Management Exception will be thrown if a
* valid application related with the specific UUID
* could not be found.
*/
private Application validateApplication(String uuid) throws ApplicationStorageManagementException {
Application application = null;
try {
application = DataHolder.getInstance().getApplicationManager().getApplication(uuid);
} catch (ApplicationManagementException e) {
throw new ApplicationStorageManagementException(
"Exception while retrieving the application details for the application with UUID "
+ uuid);
}
if (application == null) {
throw new ApplicationStorageManagementException("Application with UUID " + uuid + " does not exist.");
}
return application;
}
}

@ -58,4 +58,9 @@ public class Constants {
* Path to save the Application related artifacts.
*/
public static String artifactPath = "";
/**
* Name of the image artifacts that are saved in the file system.
*/
public static final String[] IMAGE_ARTIFACTS = {"icon", "banner", "screenshot"};
}

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>application-mgt</artifactId>
<version>3.0.46-SNAPSHOT</version>
</parent>
<artifactId>org.wso2.carbon.device.application.mgt.publisher.ui</artifactId>
<version>3.0.46-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.wso2.maven</groupId>
<artifactId>carbon-p2-plugin</artifactId>
<version>${carbon.p2.plugin.version}</version>
<executions>
<execution>
<id>4-p2-feature-generation</id>
<phase>package</phase>
<goals>
<goal>p2-feature-gen</goal>
</goals>
<configuration>
<id>org.wso2.carbon.device.application.mgt</id>
<propertiesFile>../../etc/feature.properties</propertiesFile>
<adviceFile>
<properties>
<propertyDef>org.wso2.carbon.p2.category.type:server
</propertyDef>
<propertyDef>org.eclipse.equinox.p2.type.group:false
</propertyDef>
</properties>
</adviceFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<id>npm install (initialize)</id>
<goals>
<goal>exec</goal>
</goals>
<phase>initialize</phase>
<configuration>
<workingDirectory>${basedir}/src/main/resources/publisher</workingDirectory>
<executable>${npm.executable}</executable>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm run build (compile)</id>
<goals>
<goal>exec</goal>
</goals>
<phase>compile</phase>
<configuration>
<workingDirectory>${basedir}/src/main/resources/publisher</workingDirectory>
<executable>${npm.executable}</executable>
<arguments>
<argument>run</argument>
<argument>${npm.build.command}</argument>
</arguments>
</configuration>
</execution>
</executions>
<configuration>
<workingDirectory>${npm.working.dir}</workingDirectory>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>platform-windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<properties>
<!-- Override the executable names for Windows -->
<npm.executable>npm.cmd</npm.executable>
</properties>
</profile>
</profiles>
<properties>
<maven.test.skip>false</maven.test.skip>
<npm.executable>npm</npm.executable>
<npm.build.command>build_prod</npm.build.command>
<npm.working.dir>./src/main/</npm.working.dir>
</properties>
</project>

@ -0,0 +1,56 @@
{
"name": "publisher",
"version": "1.0.0",
"description": "WSO2 IoT Server App Publisher",
"main": "App.js",
"repository": {
"type": "git",
"url": "git://github.com/wso2/carbon-devicemgt"
},
"license": "Apache License 2.0",
"dependencies": {
"axios": "^0.16.2",
"flux": "^3.1.3",
"history": "^4.6.3",
"latest-version": "^3.1.0",
"material-ui": "^0.19.0",
"material-ui-datatables": "^0.18.2",
"prop-types": "^15.5.10",
"qs": "^6.5.0",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-dropzone": "^4.1.0",
"react-images-uploader": "^1.1.0",
"react-material-ui-form-validator": "^0.5.0",
"react-modal": "^2.2.2",
"react-router": "^4.1.2",
"react-router-dom": "^4.1.2",
"react-scripts": "1.0.10",
"react-sliding-pane": "^1.2.3",
"react-tap-event-plugin": "^2.0.1"
},
"devDependencies": {
"babel-core": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"chai": "^4.0.2",
"babel-preset-react": "^6.24.1",
"babel-register": "^6.24.1",
"css-loader": "^0.28.2",
"less": "^2.7.2",
"less-loader": "^4.0.4",
"mocha": "^3.4.1",
"mock-local-storage": "^1.0.2",
"style-loader": "^0.18.1",
"webpack": "^2.5.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build --history-api-fallback",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"build_prod": "NODE_ENV=production webpack -p --progress --colors --config webpack.config.js",
"build_dev": "NODE_ENV=development webpack -d --config webpack.config.js --watch "
}
}

@ -0,0 +1,57 @@
<!doctype html>
<!--
~ Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. 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.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/publisher/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/publisher/images/favicon.png">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>WSO2 IoT App Publisher</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

@ -0,0 +1,15 @@
{
"short_name": "App Publisher",
"name": "WSO2 IoT App Publisher",
"icons": [
{
"src": "images/favicon.png",
"sizes": "16x16",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

@ -0,0 +1,97 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import './App.css'
import React, {Component} from 'react';
import createHistory from 'history/createHashHistory';
import {HashRouter as Router, Redirect, Route, Switch} from 'react-router-dom'
import {BaseLayout, ApplicationCreate, Login, NotFound, PublisherOverview, PlatformCreate} from './components'
const history = createHistory({basename: '/publisher'});
/**
* This component defines the layout and the routes for the app.
* All the content will be loaded inside the Base component.
* The base component includes the Core layout and the routers according to which the content will be displayed.
*
* The Router and Route components.
* The Router and Route is used for navigation.
* We specify the component which needs to be rendered for an URL.
* Ex: When navigate to publisher/overview, the overview component will be rendered inside the main layout.
* */
class Base extends Component {
constructor() {
super();
this.state = {
user: "admin"
}
}
render() {
if (this.state.user) {
return (
<div className="container">
<BaseLayout>
<Switch>
<Redirect exact path={"/"} to={"/overview"}/>
<Route exact path={"/overview"} component={PublisherOverview}/>
<Route exact path={"/assets/apps/create"} component={ApplicationCreate}/>
<Route exact path={"/assets/platforms/create"} component={PlatformCreate}/>
<Route exact path={"/assets/apps"} />
<Route exact path={"/assets/apps/:app"} />
<Route exact path={"/assets/apps/edit/:app"} />
<Route exact path={"/assets/platforms/:platform"}/>
<Route exact path={"/assets/platforms/edit/:platform"}/>
<Route exact path={"/assets/reviews"}/>
<Route exact path={"/assets/reviews/:review"}/>
<Route component={NotFound}/>
</Switch>
</BaseLayout>
</div>
)
}
return (<Redirect to={"/login"}/>)
}
}
/**
* This component is referred by the index.js to initiate the application.
* */
class Publisher extends Component {
render() {
return (
<div className="App">
<Router basename="publisher" history={history}>
<Switch>
<Route path="/login" component={Login}/>
<Route path="/logout" component={Login}/>
<Route component={Base}/>
</Switch>
</Router>
</div>
);
}
}
Publisher.propTypes = {
user: Object
};
export default Publisher;

@ -0,0 +1,26 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});

@ -0,0 +1,17 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/

@ -0,0 +1,17 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/

@ -0,0 +1,17 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/

@ -0,0 +1,17 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/

@ -0,0 +1,21 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
/**
* Defines the list of App Manager APIs.
* */

@ -0,0 +1,17 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/

@ -0,0 +1,22 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import {Dispatcher} from 'flux';
export default new Dispatcher();

@ -0,0 +1,231 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
import Dialog from 'material-ui/Dialog';
import {withRouter} from 'react-router-dom';
import {Step1, Step2, Step3} from './Forms';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardTitle} from 'material-ui/Card';
import {Step, StepLabel, Stepper,} from 'material-ui/Stepper';
/**
* The App Create Component.
*
* Application creation is handled through a Wizard. (We use Material UI Stepper.)
*
* In each step, data will be set to the state separately.
* When the wizard is completed, data will be arranged and sent to the api.
* */
class ApplicationCreate extends Component {
constructor() {
super();
this.setStepData.bind(this);
this.removeStepData.bind(this);
this.handleSubmit.bind(this);
this.handleCancel.bind(this);
this.handleYes.bind(this);
this.handleNo.bind(this);
this.state = {
finished: false,
stepIndex: 0,
stepData: [],
isDialogOpen: false
};
}
/**
* Handles next button click event.
* */
handleNext = () => {
const {stepIndex} = this.state;
this.setState({
stepIndex: stepIndex + 1,
finished: stepIndex >= 2,
});
};
/**
* Handles form submit.
* */
handleSubmit = () => {
console.log(this.state.stepData);
};
/**
* Handles cancel button click event.
* This will show a confirmation dialog to cancel the application creation process.
* */
handleCancel = () => {
this.setState({isDialogOpen: true});
};
/**
* Handled [ < Prev ] button click.
* This clears the data in the current step and returns to the previous step.
* */
handlePrev = () => {
const {stepIndex} = this.state;
if (stepIndex > 0) {
this.removeStepData();
this.setState({stepIndex: stepIndex - 1});
}
};
/**
* Saves form data in each step in to the state.
* */
setStepData = (step, data) => {
console.log(step, data, this.state.stepData);
let tmpStepData = this.state.stepData;
tmpStepData.push({step: step, data: data});
this.setState({stepData: tmpStepData})
};
/**
* Remove the last data point
* */
removeStepData = () => {
let tempData = this.state.stepData;
tempData.pop();
this.setState({stepData: tempData});
};
/**
* Handles the Yes button in app creation cancellation dialog.
* Clears all the form data and reset the wizard.
* */
handleYes = () => {
this.setState({finished: false, stepIndex: 0, stepData: [], isDialogOpen: false});
};
/**
* Handles No button in app creation cancellation dialog.
* Returns to the same step.
* */
handleNo = () => {
this.setState({isDialogOpen: false});
};
/**
* Defines all the Steps in the stepper. (Wizard)
*
* Extension Point: If any extra steps needed, follow the instructions below.
* 1. Create the required form ./Forms directory.
* 2. Add defined case statements.
* 3. Define the Step in render function.
*
* */
getStepContent(stepIndex) {
switch (stepIndex) {
case 0:
return <Step1 handleNext={this.handleNext}
setData={this.setStepData}
removeData={this.removeStepData}/>;
case 1:
return <Step2 handleNext={this.handleNext}
handlePrev={this.handlePrev}
setData={this.setStepData}
removeData={this.removeStepData}/>;
case 2:
return <Step3 handleFinish={this.handleNext}
handlePrev={this.handlePrev}
setData={this.setStepData}
removeData={this.removeStepData}/>;
default:
return 'You\'re a long way from home sonny jim!';
}
}
render() {
const {finished, stepIndex} = this.state;
const contentStyle = {margin: '0 16px'};
/**
* Defines the dialog box actions. [Yes][No]
* */
const actions = [
<FlatButton
label="Yes"
primary={true}
onClick={this.handleYes}
/>,
<FlatButton
label="No"
secondary={true}
onClick={this.handleNo}
/>,
];
return (
<div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}>
<Card>
<CardTitle title="Create Application"/>
{/**
* The stepper goes here.
*/}
<CardActions>
<div style={{width: '100%', margin: 'auto'}}>
<Stepper activeStep={stepIndex}>
<Step>
<StepLabel>Select Application Platform</StepLabel>
</Step>
<Step>
<StepLabel>Enter Application Details</StepLabel>
</Step>
<Step>
<StepLabel>Release</StepLabel>
</Step>
</Stepper>
<div style={contentStyle}>
{finished ? (
<div>
<p>Create App?</p>
<form>
<RaisedButton primary={true} label="Create" onClick={this.handleSubmit}/>
<FlatButton label="Cancel" onClick={this.handleCancel}/>
</form>
</div>
) : (
<div>
{this.getStepContent(stepIndex)}
</div>
)}
</div>
</div>
</CardActions>
</Card>
<Dialog
actions={actions}
modal={false}
open={this.state.isDialogOpen}
onRequestClose={this.handleNo}
>
Do you really want to cancel?
</Dialog>
</div>);
}
}
export default withRouter(ApplicationCreate);

@ -0,0 +1,30 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';
/**
* Application List Component.
* */
class ApplicationListing extends Component{
}
export default withRouter(ApplicationListing);

@ -0,0 +1,30 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';
/**
* Application view component.
* Shows the details of the application.
* */
class ApplicationView extends Component{
}
export default withRouter(ApplicationView);

@ -0,0 +1,140 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton';
/**
* The first step of the application creation wizard.
* This contains following components:
* * Application Title
* * Store Type
* * Application Platform
*
* Parent Component: Create
* Props:
* 1. handleNext: {type: function, Invokes handleNext function of parent component}
* 2. setData : {type: function, Sets current form data to the state of the parent component}
* 3. removeData: {type: function, Invokes the removeStepData function click of parent}
* */
class Step1 extends Component {
constructor() {
super();
this.state = {
finished: false,
stepIndex: 0,
store: 1,
platform: 1,
stepData: []
};
}
/**
* Invokes the handleNext function in Create component.
* */
handleNext = () => {
this.props.handleNext();
};
/**
* Persist the current form data to the state.
* */
setStepData() {
this.props.setData("step1", {step: "Dfds"});
this.handleNext.bind(this);
}
/**
* Handles Next button click.
* Validates the form.
* Sets the data to the state.
* Invokes the handleNext method of Create component.
* */
handleClick() {
this.setStepData();
this.handleNext();
}
/**
* Triggers when changing the Platform selection.
* */
onChangePlatform = (event, index, value) => {
this.setState({platform: value});
};
/**
* Triggers when changing the Store selection.
* */
onChangeStore = (event, index, value) => {
this.setState({store: value});
};
render() {
const contentStyle = {margin: '0 16px'};
return (
<div>
<div style={contentStyle}>
<div>
<div>
<TextField
hintText="Enter a title for your application."
floatingLabelText="Title*"
floatingLabelFixed={true}
/><br/>
<SelectField
floatingLabelText="Store Type*"
value={this.state.store}
floatingLabelFixed={true}
onChange={this.onChangeStore.bind(this)}
>
<MenuItem value={1} primaryText="Enterprise"/>
<MenuItem value={2} primaryText="Public"/>
</SelectField> <br/>
<SelectField
floatingLabelText="Platform*"
value={this.state.platform}
floatingLabelFixed={true}
onChange={this.onChangePlatform.bind(this)}
>
<MenuItem value={1} primaryText="Android"/>
<MenuItem value={2} primaryText="iOS"/>
<MenuItem value={3} primaryText="Web"/>
</SelectField>
</div>
<br/>
<br/>
<div style={{marginTop: 12}}>
<RaisedButton
label="Next >"
primary={true}
onClick={this.handleClick.bind(this)}
/>
</div>
</div>
</div>
</div>
);
}
}
export default Step1;

@ -0,0 +1,209 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import Chip from 'material-ui/Chip';
import React, {Component} from 'react';
import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton';
/**
* The Second step of application create wizard.
* This contains following components.
* * App Title
* * Short Description
* * Application Description
* * Application Visibility
* * Application Tags : {Used Material UI Chip component}
* * Application Category.
* * Platform Specific properties.
* * Screenshots
* * Banner
* * Icon
*
* Parent Component: Create
* Props:
* * handleNext : {type: function, Invokes handleNext function in Parent.}
* * handlePrev : {type: function, Invokes handlePrev function in Parent}
* * setData : {type: function, Invokes setStepData function in Parent}
* * removeData : {type: Invokes removeStepData function in Parent}
* */
class Step2 extends Component {
constructor() {
super();
this.state = {
tags: [],
defValue: "",
category: 1
};
this.styles = {
chip: {
margin: 4,
},
wrapper: {
display: 'flex',
flexWrap: 'wrap',
},
};
}
/**
* Create a tag on Enter key press and set it to the state.
* Clears the tags text field.
* Chip gets two parameters: Key and value.
* */
addTags(event) {
let tags = this.state.tags;
if (event.charCode === 13) {
event.preventDefault();
tags.push({key: Math.floor(Math.random() * 1000), value: event.target.value});
this.setState({tags, defValue: ""}, console.log(this.state.tags));
}
}
/**
*
* */
handleTagChange(event) {
let defaultValue = this.state.defValue;
defaultValue = event.target.value;
this.setState({defValue: defaultValue})
}
/**
* Invokes the handleNext function in Create component.
* */
handleNext() {
this.props.handleNext();
}
/**
* Invokes the handlePrev function in Create component.
* */
handlePrev() {
this.props.handlePrev();
}
/**
* Handles Chip delete function.
* Removes the tag from state.tags
* */
handleRequestDelete = (key) => {
this.chipData = this.state.tags;
const chipToDelete = this.chipData.map((chip) => chip.key).indexOf(key);
this.chipData.splice(chipToDelete, 1);
this.setState({tags: this.chipData});
};
/**
* Creates Chip array from state.tags.
* */
renderChip(data) {
console.log(data);
return (
<Chip
key={data.key}
onRequestDelete={() => this.handleRequestDelete(data.key)}
style={this.styles.chip}
>
{data.value}
</Chip>
);
}
render() {
const contentStyle = {margin: '0 16px'};
return (
<div style={contentStyle}>
<div>
<div>
<TextField
hintText="Enter a title for your application."
floatingLabelText="Title*"
floatingLabelFixed={true}
/><br/>
<TextField
hintText="Enter a short description for your application."
floatingLabelText="Short Description*"
floatingLabelFixed={true}
multiLine={true}
rows={2}
/><br/>
<TextField
hintText="Enter the description."
floatingLabelText="Description*"
floatingLabelFixed={true}
multiLine={true}
rows={4}
/><br/>
<TextField
hintText="Select the application visibility"
floatingLabelText="Visibility*"
floatingLabelFixed={true}
/><br/>
<TextField
hintText="Enter application tags.."
floatingLabelText="Tags*"
floatingLabelFixed={true}
value={this.state.defValue}
onChange={this.handleTagChange.bind(this)}
onKeyPress={this.addTags.bind(this)}
/><br/>
<div style={this.styles.wrapper}>
{this.state.tags.map(this.renderChip, this)}
</div>
<br/>
<SelectField
floatingLabelText="Category*"
value={this.state.category}
floatingLabelFixed={true}
>
<MenuItem value={1} primaryText="Business"/>
</SelectField> <br/>
{/*Platform Specific Properties.*/}
<div style={{border: '1px'}}>
fdfdfd
</div>
</div>
<br />
<br />
<div style={{marginTop: 12}}>
<FlatButton
label="< Back"
disabled={false}
onClick={this.handlePrev.bind(this)}
style={{marginRight: 12}}
/>
<RaisedButton
label="Next >"
primary={true}
onClick={this.handleNext.bind(this)}
/>
</div>
</div>
</div>
);
}
}
export default Step2;

@ -0,0 +1,131 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
import Toggle from 'material-ui/Toggle';
import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton';
/**
* The Third step of application create wizard. {Application Release Step}
* This step is not compulsory.
*
* When click finish, user will prompt to confirm the application creation.
* User can go ahead and create the app or cancel.
*
* This contains following components:
* * Toggle to select application release. Un-hides the Application Release form.
*
* Application Release Form.
* * Release Channel
* * Application Version
* * Upload component for application.
*
* Parent Component: Create
* Props:
* * handleFinish : {type: function, Invokes handleNext function in Parent.}
* * handlePrev : {type: function, Invokes handlePrev function in Parent}
* * setData : {type: function, Invokes setStepData function in Parent}
* * removeData : {type: Invokes removeStepData function in Parent}
* */
class Step3 extends Component {
constructor() {
super();
this.state = {
showForm: false,
releaseChannel: 1
}
}
/**
* Handles finish button click.
* This invokes handleNext function in parent component.
* */
handleFinish() {
this.props.handleFinish();
}
/**
* Invokes Prev button click.
* */
handlePrev() {
this.props.handlePrev();
}
/**
* Handles release application selection.
* */
handleToggle() {
let hide = this.state.showForm;
this.setState({showForm: !hide});
}
render() {
const contentStyle = {margin: '0 16px'};
return (
<div style={contentStyle}>
<div>
<Toggle
label="Release the Application"
labelPosition="right"
onToggle={this.handleToggle.bind(this)}
defaultToggled={this.state.showForm}
/>
{/*If toggle is true, the release form will be shown.*/}
{!this.state.showForm ? <div/> : <div>
<SelectField
floatingLabelText="Select Release Channel*"
value={this.state.releaseChannel}
floatingLabelFixed={true}
>
<MenuItem value={1} primaryText="Alpha"/>
<MenuItem value={2} primaryText="Beta"/>
<MenuItem value={3} primaryText="GA"/>
</SelectField> <br/>
<TextField
hintText="1.0.0"
floatingLabelText="Version*"
floatingLabelFixed={true}
/><br/>
</div>}
<div style={{marginTop: 12}}>
<FlatButton
label="< Back"
disabled={false}
onClick={this.handlePrev.bind(this)}
style={{marginRight: 12}}
/>
<RaisedButton
label="Finish"
primary={true}
onClick={this.handleFinish.bind(this)}
/>
</div>
</div>
</div>
);
}
}
export default Step3;

@ -0,0 +1,23 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import Step1 from './Step1';
import Step2 from './Step2';
import Step3 from './Step3';
export {Step1, Step2, Step3};

@ -0,0 +1,164 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import Badge from 'material-ui/Badge';
import React, {Component} from 'react';
import AppBar from 'material-ui/AppBar';
import Drawer from 'material-ui/Drawer';
import {withRouter} from 'react-router-dom';
import IconButton from 'material-ui/IconButton';
import {List, ListItem} from 'material-ui/List';
import Apps from 'material-ui/svg-icons/navigation/apps';
import Add from 'material-ui/svg-icons/content/add-circle';
import Feedback from 'material-ui/svg-icons/action/feedback';
import Dashboard from 'material-ui/svg-icons/action/dashboard';
import DevicesOther from 'material-ui/svg-icons/hardware/devices-other';
import NotificationsIcon from 'material-ui/svg-icons/social/notifications';
import ActionAccountCircle from 'material-ui/svg-icons/action/account-circle';
/**
* Base Layout:
* App bar
* Left Navigation
* Middle content.
* */
class BaseLayout extends Component {
constructor() {
super();
this.state = {
notifications: 0,
user: 'Admin'
}
}
componentWillMount() {
}
handleApplicationClick() {
this.handleHistory('/assets/apps');
}
handleOverviewClick() {
this.handleHistory('/overview');
}
handleApplicationCreateClick() {
this.handleHistory('/assets/apps/create');
}
handlePlatformClick() {
this.handleHistory('/assets/platforms');
}
handlePlatformCreateClick() {
this.handleHistory('/assets/platforms/create');
}
handleReviewClick() {
this.handleHistory('/assets/reviews');
}
/**
* The method to update the history.
* to: The URL to route.
* */
handleHistory(to) {
this.props.history.push(to);
}
render() {
return (
<div>
<AppBar title="App Publisher"
iconElementRight={
<div>
<Badge
badgeContent={this.state.notifications}
secondary={true}
badgeStyle={{top: 12, right: 12}}
>
<IconButton tooltip="Notifications">
<NotificationsIcon/>
</IconButton>
</Badge>
<IconButton onClick={() => {
console.log("Clicked")
}}>
<ActionAccountCircle/>
</IconButton>
</div>
}
/>
<div>
<Drawer containerStyle={{height: 'calc(100% - 64px)', width: '15%', top: '10%'}} open={true}>
<List>
<ListItem primaryText="Overview"
onClick={this.handleOverviewClick.bind(this)}
leftIcon={<Dashboard/>}/>
<ListItem primaryText="Applications"
leftIcon={<Apps/>}
initiallyOpen={false}
primaryTogglesNestedList={true}
onClick={this.handleApplicationClick.bind(this)}
nestedItems={[
<ListItem
key={1}
primaryText="Create"
onClick={this.handleApplicationCreateClick.bind(this)}
leftIcon={<Add/>}
/>]}
/>
<ListItem primaryText="Platforms"
leftIcon={<DevicesOther/>}
initiallyOpen={false}
primaryTogglesNestedList={true}
onClick={this.handlePlatformClick.bind(this)}
nestedItems={[
<ListItem
key={1}
primaryText="Create"
onClick={this.handlePlatformCreateClick.bind(this)}
leftIcon={<Add/>}
/>]}
/>
<ListItem primaryText="Reviews"
onClick={this.handleReviewClick.bind(this)}
leftIcon={<Feedback/>}/>
</List>
</Drawer>
</div>
<div style=
{
{
height: 'calc(100% - 64px)',
marginLeft: '16%',
width: 'calc(100%-15%)',
top: 64,
left: "-100px"
}
}>
{this.props.children}
</div>
</div>);
}
}
export default withRouter(BaseLayout);

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Error page.
* */
class Error extends Component {
constructor() {
super();
}
render() {
return (
<div>
404 not found
</div>
);
}
}
export default Error;

@ -0,0 +1,47 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
*
* ***NEW***
* The Publisher overview component.
* This component could be used to view app analytics.
* i.e number of overall downloads, ratings ect.
* */
class PublisherOverview extends Component {
constructor() {
super();
}
componentWillMount() {
}
render() {
return (
<div>
Overview
</div>
);
}
}
export default PublisherOverview;

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Platform Create component
* */
class PlatformCreate extends Component {
constructor() {
super();
}
render() {
return (
<div>
Create Platform
</div>
);
}
}
export default PlatformCreate;

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Platform Listing component.
* */
class PlatformListing extends Component {
constructor() {
super();
}
render() {
return (
<div>
Platform View
</div>
);
}
}
export default PlatformListing;

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Platform view component.
* */
class PlatformView extends Component {
constructor() {
super();
}
render() {
return (
<div>
Platform View
</div>
);
}
}
export default PlatformView;

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Review Listing.
* */
class ReviewListing extends Component {
constructor() {
super();
}
render() {
return (
<div>
Reviews List
</div>
);
}
}
export default ReviewListing;

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Review details view.
* */
class ReviewView extends Component {
constructor() {
super();
}
render() {
return (
<div>
Review
</div>
);
}
}
export default ReviewView;

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import React, {Component} from 'react';
/**
* Error page.
* */
class DataTable extends Component {
constructor() {
super();
}
render() {
return (
<div>
Data Table
</div>
);
}
}
export default DataTable;

@ -0,0 +1,153 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import qs from 'qs';
import React, {Component} from 'react';
import Checkbox from 'material-ui/Checkbox';
import {Redirect, Switch} from 'react-router-dom';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardTitle} from 'material-ui/Card';
import {TextValidator, ValidatorForm} from 'react-material-ui-form-validator';
//todo: remove the {TextValidator, ValidatorForm} and implement it manually.
/**
* The Login Component.
*
* This component contains the Login form and methods to handle field change events.
* The user name and password will be set to the state and sent to the api.
*
* If the user is already logged in, it will redirect to the last point where the user was.
* */
class Login extends Component {
constructor() {
super();
this.state = {
isLoggedIn: true,
referrer: "/",
userName: "",
password: "",
rememberMe: true
}
}
componentDidMount() {
let queryString = this.props.location.search;
console.log(queryString);
queryString = queryString.replace(/^\?/, '');
/* With QS version up we can directly use {ignoreQueryPrefix: true} option */
let params = qs.parse(queryString);
if (params.referrer) {
this.setState({referrer: params.referrer});
}
}
handleLogin(event) {
event.preventDefault();
}
/**
* Handles the username field change event.
* */
onUserNameChange(event) {
this.setState(
{
userName: event.target.value
}
);
}
/**
* Handles the password field change event.
* */
onPasswordChange(event) {
this.setState(
{
password: event.target.value
}
);
}
/**
* Handles the remember me check.
* */
handleRememberMe() {
this.setState(
{
rememberMe: !this.state.rememberMe
}
);
}
render() {
if (!this.state.isLoggedIn) {
return (
<div>
{/*TODO: Style the components.*/}
<Card>
<CardTitle title="WSO2 IoT App Publisher"/>
<CardActions>
<ValidatorForm
ref="form"
onSubmit={this.handleLogin.bind(this)}
onError={errors => console.log(errors)}>
<TextValidator
floatingLabelText="User Name"
floatingLabelFixed={true}
onChange={this.onUserNameChange.bind(this)}
name="userName"
validators={['required']}
errorMessages={['User Name is required']}
value={this.state.userName}
/>
<br/>
<TextValidator
floatingLabelText="Password"
floatingLabelFixed={true}
onChange={this.onPasswordChange.bind(this)}
name="password"
type="password"
value={this.state.password}
validators={['required']}
errorMessages={['Password is required']}
/>
<br/>
<Checkbox label="Remember me."
onCheck={this.handleRememberMe.bind(this)}
checked={this.state.rememberMe}/>
<br/>
<RaisedButton type="submit" label="Login"/>
</ValidatorForm>
</CardActions>
</Card>
</div>);
} else {
return (
<Switch>
<Redirect to={this.state.referrer}/>
</Switch>
);
}
}
}
export default Login;

@ -0,0 +1,30 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import Login from './User/Login/Login';
import NotFound from './Error/NotFound';
import BaseLayout from './Base/BaseLayout';
import PlatformCreate from './Platform/PlatformCreate';
import PublisherOverview from './Overview/PublisherOverview';
import ApplicationCreate from './Application/ApplicationCreate';
/**
* Contains all UI components related to Application, Login and Platform
*/
export {Login, BaseLayout, ApplicationCreate, NotFound, PublisherOverview, PlatformCreate};

@ -0,0 +1,30 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import './index.css';
import React from 'react';
import Publisher from './App';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
/**
* This is the base js file of the app. All the content will be rendered in the root element.
* */
ReactDOM.render(<MuiThemeProvider><Publisher/></MuiThemeProvider>, document.getElementById('root'));
registerServiceWorker();

@ -0,0 +1,126 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/publisher/service-worker.js`;
if (!isLocalhost) {
// Is not local host. Just register service worker
registerValidSW(swUrl);
} else {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
}
});
}
}
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

@ -0,0 +1,19 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
export class ApplicationStore {};

@ -0,0 +1,18 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
export class PlatformStore{};

@ -0,0 +1,19 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
export class ReviewStore{};

@ -0,0 +1,24 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
import ReviewStore from './ReviewStore';
import PlatformStore from './PlatformStore';
import ApplicationStore from './ApplicationStore';
export {ApplicationStore, PlatformStore, ReviewStore};

@ -0,0 +1,68 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
var path = require('path');
const config = {
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'public/dist'),
filename: '[name].js'
},
devtool: "source-map",
plugins: [],
watch: false,
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015', 'react'],
plugins: ['transform-class-properties']
}
}
]
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
}
]
}
};
if (process.env.NODE_ENV === "development") {
config.watch = true;
}
module.exports = config;

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>application-mgt</artifactId>
<version>3.0.46-SNAPSHOT</version>
</parent>
<artifactId>org.wso2.carbon.device.application.mgt.store.ui</artifactId>
<version>3.0.46-SNAPSHOT</version>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.wso2.maven</groupId>
<artifactId>carbon-p2-plugin</artifactId>
<version>${carbon.p2.plugin.version}</version>
<executions>
<execution>
<id>4-p2-feature-generation</id>
<phase>package</phase>
<goals>
<goal>p2-feature-gen</goal>
</goals>
<configuration>
<id>org.wso2.carbon.device.application.mgt.store</id>
<propertiesFile>../../etc/feature.properties</propertiesFile>
<adviceFile>
<properties>
<propertyDef>org.wso2.carbon.p2.category.type:server
</propertyDef>
<propertyDef>org.eclipse.equinox.p2.type.group:false
</propertyDef>
</properties>
</adviceFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<id>npm install (initialize)</id>
<goals>
<goal>exec</goal>
</goals>
<phase>initialize</phase>
<configuration>
<workingDirectory>${basedir}/src/main/resources/store</workingDirectory>
<executable>${npm.executable}</executable>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm run build (compile)</id>
<goals>
<goal>exec</goal>
</goals>
<phase>compile</phase>
<configuration>
<workingDirectory>${basedir}/src/main/resources/publisher</workingDirectory>
<executable>${npm.executable}</executable>
<arguments>
<argument>run</argument>
<argument>${npm.build.command}</argument>
</arguments>
</configuration>
</execution>
</executions>
<configuration>
<workingDirectory>${npm.working.dir}</workingDirectory>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>platform-windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<properties>
<!-- Override the executable names for Windows -->
<npm.executable>npm.cmd</npm.executable>
</properties>
</profile>
</profiles>
<properties>
<maven.test.skip>false</maven.test.skip>
<npm.executable>npm</npm.executable>
<npm.build.command>build_prod</npm.build.command>
<npm.working.dir>./src/main/</npm.working.dir>
</properties>
</project>

@ -37,7 +37,7 @@
<module>org.wso2.carbon.device.application.mgt.core</module>
<module>org.wso2.carbon.device.application.mgt.common</module>
<module>org.wso2.carbon.device.application.mgt.api</module>
<module>org.wso2.carbon.device.application.mgt.ui</module>
<module>org.wso2.carbon.device.application.mgt.publisher.ui</module>
</modules>
<build>

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>application-mgt-feature</artifactId>
<version>3.0.46-SNAPSHOT</version>
</parent>
<artifactId>org.wso2.carbon.device.application.mgt.publisher.ui.feature</artifactId>
<version>3.0.46-SNAPSHOT</version>
</project>

@ -61,7 +61,6 @@
</Extensions>
<Artifacts>
<ImageLocation>${carbon.home}/repository/resources/mobileapps/images/</ImageLocation>
<BinaryLocation>${carbon.home}/repository/resources/mobileapps/binary/</BinaryLocation>
<BinaryLocation>repository/resources/mobileapps/</BinaryLocation>
</Artifacts>
</ApplicationManagementConfiguration>

@ -125,10 +125,8 @@ CREATE TABLE IF NOT EXISTS `APPM_APPLICATION` (
`NAME` VARCHAR(100) NOT NULL,
`SHORT_DESCRIPTION` VARCHAR(255) NULL,
`DESCRIPTION` TEXT NULL,
`ICON_NAME` VARCHAR(100) NULL,
`BANNER_NAME` VARCHAR(100) NULL,
`SCREEN_SHOT_COUNT` INT DEFAULT 0,
`VIDEO_NAME` VARCHAR(100) NULL,
`SCREENSHOTS` TEXT NULL,
`CREATED_BY` VARCHAR(255) NULL,
`CREATED_AT` DATETIME NOT NULL,
`MODIFIED_AT` DATETIME NULL,
@ -183,7 +181,7 @@ CREATE TABLE IF NOT EXISTS APPM_APPLICATION_RELEASE (
ID INT NOT NULL AUTO_INCREMENT,
VERSION_NAME VARCHAR(100) NOT NULL,
RESOURCE TEXT NULL,
RELEASE_CHANNEL VARCHAR(50) NULL,
RELEASE_CHANNEL VARCHAR(50) DEFAULT 'ALPHA',
RELEASE_DETAILS TEXT NULL,
CREATED_AT DATETIME NOT NULL,
APPM_APPLICATION_ID INT NOT NULL,

@ -126,10 +126,8 @@ CREATE TABLE IF NOT EXISTS `APPM_APPLICATION` (
`NAME` VARCHAR(100) NOT NULL,
`SHORT_DESCRIPTION` VARCHAR(255) NULL,
`DESCRIPTION` TEXT NULL,
`ICON_NAME` VARCHAR(100) NULL,
`BANNER_NAME` VARCHAR(100) NULL,
`VIDEO_NAME` VARCHAR(100) NULL,
`SCREENSHOTS` TEXT NULL,
`SCREEN_SHOT_COUNT` INT DEFAULT 0,
`CREATED_BY` VARCHAR(255) NULL,
`CREATED_AT` DATETIME NOT NULL,
`MODIFIED_AT` DATETIME NULL,
@ -191,7 +189,7 @@ CREATE TABLE IF NOT EXISTS `APPM_APPLICATION_RELEASE` (
`ID` INT NOT NULL AUTO_INCREMENT UNIQUE ,
`VERSION_NAME` VARCHAR(100) NOT NULL,
`RESOURCE` TEXT NULL,
`RELEASE_CHANNEL` VARCHAR(50) NULL,
`RELEASE_CHANNEL` VARCHAR(50) DEFAULT 'ALPHA',
`RELEASE_DETAILS` TEXT NULL,
`CREATED_AT` DATETIME NOT NULL,
`APPM_APPLICATION_ID` INT NOT NULL,
@ -307,8 +305,8 @@ CREATE TABLE IF NOT EXISTS `APPM_PLATFORM_TENANT_MAPPING` (
CONSTRAINT `fk_APPM_PLATFORM_TENANT_MAPPING_APPM_SUPPORTED_PLATFORM1`
FOREIGN KEY (`PLATFORM_ID`)
REFERENCES `APPM_PLATFORM` (`ID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ON DELETE CASCADE
ON UPDATE CASCADE )
ENGINE = InnoDB
COMMENT = 'This table contains the data related relationship between application platofrm and appication mappings';

@ -42,3 +42,205 @@ PRIMARY KEY (ID, TENANT_ID, PLATFORM_ID)
);
CREATE INDEX FK_PLATFROM_TENANT_MAPPING_PLATFORM ON APPM_PLATFORM_TENANT_MAPPING(PLATFORM_ID ASC);
DROP TABLE IF EXISTS APPM_APPLICATION_CATEGORY;
DROP SEQUENCE IF EXISTS APPM_APPLICATION_CATEGORY_PK_SEQ;
CREATE SEQUENCE APPM_APPLICATION_CATEGORY_PK_SEQ;
CREATE TABLE IF NOT EXISTS APPM_APPLICATION_CATEGORY (
ID INT DEFAULT NEXTVAL('APPM_APPLICATION_CATEGORY_PK_SEQ'),
NAME VARCHAR(100) NOT NULL,
DESCRIPTION TEXT NULL,
PUBLISHED BOOLEAN DEFAULT FALSE,
PRIMARY KEY (ID));
INSERT INTO APPM_APPLICATION_CATEGORY (NAME, DESCRIPTION, PUBLISHED) VALUES ('Enterprise', 'Enterprise level
applications which the artifacts need to be provided', TRUE);
INSERT INTO APPM_APPLICATION_CATEGORY (NAME, DESCRIPTION, PUBLISHED) VALUES ('Public', 'Public category in which the
application need to be downloaded from the public application store', TRUE);
DROP TABLE IF EXISTS APPM_LIFECYCLE_STATE;
DROP SEQUENCE IF EXISTS APPM_LIFECYCLE_STATE_PK_SEQ;
CREATE SEQUENCE APPM_LIFECYCLE_STATE_PK_SEQ;
-- -----------------------------------------------------
-- Table APPM_LIFECYCLE_STATE
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS APPM_LIFECYCLE_STATE (
ID INT DEFAULT NEXTVAL('APPM_LIFECYCLE_STATE_PK_SEQ'),
NAME VARCHAR(100) NOT NULL,
IDENTIFIER VARCHAR(100) NOT NULL,
DESCRIPTION TEXT NULL,
PRIMARY KEY (ID));
DROP INDEX IF EXISTS APPM_LIFECYCLE_STATE_IDENTIFIER_UNIQUE;
CREATE INDEX APPM_LIFECYCLE_STATE_IDENTIFIER_UNIQUE ON APPM_LIFECYCLE_STATE(IDENTIFIER ASC);
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION) VALUES ('CREATED', 'CREATED', 'Application creation
initial state');
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION)
VALUES ('IN REVIEW', 'IN REVIEW', 'Application is in in-review state');
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION)
VALUES ('APPROVED', 'APPROVED', 'State in which Application is approved after reviewing.');
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION)
VALUES ('REJECTED', 'REJECTED', 'State in which Application is rejected after reviewing.');
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION)
VALUES ('PUBLISHED', 'PUBLISHED', 'State in which Application is in published state.');
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION)
VALUES ('UNPUBLISHED', 'UNPUBLISHED', 'State in which Application is in un published state.');
INSERT INTO APPM_LIFECYCLE_STATE (NAME, IDENTIFIER, DESCRIPTION)
VALUES ('RETIRED', 'RETIRED', 'Retiring an application to indicate end of life state,');
DROP TABLE IF EXISTS APPM_LIFECYCLE_STATE_TRANSITION;
DROP SEQUENCE IF EXISTS APPM_LIFECYCLE_STATE_TRANSITION_PK_SEQ;
CREATE SEQUENCE APPM_LIFECYCLE_STATE_TRANSITION_PK_SEQ;
CREATE TABLE IF NOT EXISTS APPM_LIFECYCLE_STATE_TRANSITION
(
ID INT DEFAULT NEXTVAL('APPM_LIFECYCLE_STATE_TRANSITION_PK_SEQ'),
INITIAL_STATE INT,
NEXT_STATE INT,
PERMISSION VARCHAR(1024),
DESCRIPTION VARCHAR(2048),
PRIMARY KEY (INITIAL_STATE, NEXT_STATE),
FOREIGN KEY (INITIAL_STATE) REFERENCES APPM_LIFECYCLE_STATE(ID) ON DELETE CASCADE,
FOREIGN KEY (NEXT_STATE) REFERENCES APPM_LIFECYCLE_STATE(ID) ON DELETE CASCADE
);
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(1, 2, null, 'Submit for review');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(2, 1, null, 'Revoke from review');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(2, 3, '/permission/admin/manage/device-mgt/application/review', 'APPROVE');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(2, 4, '/permission/admin/manage/device-mgt/application/review', 'REJECT');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(3, 4, '/permission/admin/manage/device-mgt/application/review', 'REJECT');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(3, 5, null, 'PUBLISH');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(5, 6, null, 'UN PUBLISH');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(6, 5, null, 'PUBLISH');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(4, 1, null, 'Return to CREATE STATE');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(6, 1, null, 'Return to CREATE STATE');
INSERT INTO APPM_LIFECYCLE_STATE_TRANSITION(INITIAL_STATE, NEXT_STATE, PERMISSION, DESCRIPTION) VALUES
(6, 7, null, 'Retire');
DROP TABLE IF EXISTS APPM_APPLICATION;
DROP SEQUENCE IF EXISTS APPM_APPLICATION_PK_SEQ;
CREATE SEQUENCE APPM_APPLICATION_PK_SEQ;
CREATE TABLE IF NOT EXISTS APPM_APPLICATION (
ID INT DEFAULT NEXTVAL('APPM_APPLICATION_PK_SEQ') UNIQUE,
UUID VARCHAR(100) NOT NULL,
IDENTIFIER VARCHAR(255) NULL,
NAME VARCHAR(100) NOT NULL,
SHORT_DESCRIPTION VARCHAR(255) NULL,
DESCRIPTION TEXT NULL,
SCREEN_SHOT_COUNT INT DEFAULT 0,
VIDEO_NAME VARCHAR(100) NULL,
CREATED_BY VARCHAR(255) NULL,
CREATED_AT TIMESTAMP NOT NULL,
MODIFIED_AT TIMESTAMP NULL,
IS_FREE BOOLEAN DEFAULT TRUE,
PAYMENT_CURRENCY VARCHAR(45) NULL,
PAYMENT_PRICE DECIMAL(10,2) NULL,
APPLICATION_CATEGORY_ID INT NOT NULL,
LIFECYCLE_STATE_ID INT NOT NULL,
LIFECYCLE_STATE_MODIFIED_BY VARCHAR(255) NULL,
LIFECYCLE_STATE_MODIFIED_AT TIMESTAMP NULL,
TENANT_ID INT NOT NULL,
PLATFORM_ID INT NOT NULL,
PRIMARY KEY (ID, APPLICATION_CATEGORY_ID, LIFECYCLE_STATE_ID, PLATFORM_ID),
FOREIGN KEY (APPLICATION_CATEGORY_ID)
REFERENCES APPM_APPLICATION_CATEGORY (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_APPM_APPLICATION_APPM_LIFECYCLE_STATE1
FOREIGN KEY (LIFECYCLE_STATE_ID)
REFERENCES APPM_LIFECYCLE_STATE (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_APPM_APPLICATION_APPM_PLATFORM1
FOREIGN KEY (PLATFORM_ID)
REFERENCES APPM_PLATFORM (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
CREATE INDEX IF NOT EXISTS FK_APPLICATION_APPLICATION_CATEGORY ON APPM_APPLICATION(APPLICATION_CATEGORY_ID ASC);
CREATE INDEX IF NOT EXISTS UK_APPLICATION_UUID ON APPM_APPLICATION(UUID ASC);
DROP TABLE IF EXISTS APPM_APPLICATION_PROPERTY;
-- -----------------------------------------------------
-- Table APPM_APPLICATION_PROPERTY
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS APPM_APPLICATION_PROPERTY (
PROP_KEY VARCHAR(255) NOT NULL,
PROP_VAL TEXT NULL,
APPLICATION_ID INT NOT NULL,
PRIMARY KEY (PROP_KEY, APPLICATION_ID),
CONSTRAINT FK_APPLICATION_PROPERTY_APPLICATION
FOREIGN KEY (APPLICATION_ID)
REFERENCES APPM_APPLICATION (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
CREATE INDEX FK_APPLICATION_PROPERTY_APPLICATION ON APPM_APPLICATION_PROPERTY(APPLICATION_ID ASC);
CREATE TABLE IF NOT EXISTS APPM_APPLICATION_TAG (
NAME VARCHAR(45) NOT NULL,
APPLICATION_ID INT NOT NULL,
PRIMARY KEY (APPLICATION_ID, NAME),
CONSTRAINT fk_APPM_APPLICATION_TAG_APPM_APPLICATION1
FOREIGN KEY (APPLICATION_ID)
REFERENCES APPM_APPLICATION (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
CREATE INDEX IF NOT EXISTS FK_APPLICATION_TAG_APPLICATION ON APPM_APPLICATION_TAG(APPLICATION_ID ASC);
DROP TABLE IF EXISTS APPM_APPLICATION_RELEASE;
DROP SEQUENCE IF EXISTS APPM_APPLICATION_RELEASE_PK_SEQ;
CREATE SEQUENCE APPM_APPLICATION_RELEASE_PK_SEQ;
-- -----------------------------------------------------
-- Table APPM_APPLICATION_RELEASE
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS APPM_APPLICATION_RELEASE (
ID INT DEFAULT NEXTVAL('APPM_APPLICATION_RELEASE_PK_SEQ') UNIQUE,
VERSION_NAME VARCHAR(100) NOT NULL,
RESOURCE TEXT NULL,
RELEASE_CHANNEL VARCHAR(50) DEFAULT 'ALPHA',
RELEASE_DETAILS TEXT NULL,
CREATED_AT TIMESTAMP NOT NULL,
APPM_APPLICATION_ID INT NOT NULL,
IS_DEFAULT BOOLEAN DEFAULT FALSE,
PRIMARY KEY (APPM_APPLICATION_ID, VERSION_NAME),
CONSTRAINT FK_APPLICATION_VERSION_APPLICATION
FOREIGN KEY (APPM_APPLICATION_ID)
REFERENCES APPM_APPLICATION (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
CREATE INDEX FK_APPLICATION_VERSION_APPLICATION ON APPM_APPLICATION_RELEASE(APPM_APPLICATION_ID ASC);
DROP TABLE IF EXISTS APPM_RELEASE_PROPERTY;
-- -----------------------------------------------------
-- Table APPM_RELEASE_PROPERTY
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS APPM_RELEASE_PROPERTY (
PROP_KEY VARCHAR(255) NOT NULL,
PROP_VALUE TEXT NULL,
APPLICATION_RELEASE_ID INT NOT NULL,
PRIMARY KEY (PROP_KEY, APPLICATION_RELEASE_ID),
CONSTRAINT FK_RELEASE_PROPERTY_APPLICATION_RELEASE
FOREIGN KEY (APPLICATION_RELEASE_ID)
REFERENCES APPM_APPLICATION_RELEASE (ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
CREATE INDEX FK_RELEASE_PROPERTY_APPLICATION_RELEASE ON APPM_RELEASE_PROPERTY(APPLICATION_RELEASE_ID ASC);

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~
~ WSO2 Inc. 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>application-mgt-feature</artifactId>
<version>3.0.46-SNAPSHOT</version>
</parent>
<artifactId>org.wso2.carbon.device.application.mgt.store.ui.feature</artifactId>
<version>3.0.46-SNAPSHOT</version>
</project>

@ -35,9 +35,10 @@
<modules>
<module>org.wso2.carbon.device.application.mgt.api.feature</module>
<module>org.wso2.carbon.device.application.mgt.ui.feature</module>
<!--<module>org.wso2.carbon.device.application.mgt.ui.feature</module>-->
<module>org.wso2.carbon.device.application.mgt.feature</module>
<!--<module>org.wso2.carbon.device.application.mgt.extensions.feature</module>-->
<module>org.wso2.carbon.device.application.mgt.server.feature</module>
<module>org.wso2.carbon.device.application.mgt.publisher.ui.feature</module>
</modules>
</project>
Loading…
Cancel
Save