Merge pull request #814 from Nirothipan/fileTransfer

File transfer Feature
merge-requests/1/head
Charitha Goonetilleke 7 years ago committed by GitHub
commit 1ce74f47c9

@ -0,0 +1,76 @@
/*
* 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.
*/
package org.wso2.carbon.mdm.services.android.bean;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.mdm.services.android.bean.AndroidOperation;
import java.io.Serializable;
/**
* This class represents the information of file transfer operation payload.
*/
@ApiModel(value = "FileTransfer",
description = "This class carries all information related to file transfer operation.")
public class FileTransfer extends AndroidOperation implements Serializable {
@ApiModelProperty(name = "fileURL", value = "File URL", required = true)
private String fileURL;
@ApiModelProperty(name = "userName", value = "User Name", required = true)
private String userName;
@ApiModelProperty(name = "ftpPassword", value = "FTP password", required = true)
private String ftpPassword;
@ApiModelProperty(name = "fileLocation", value = "fileLocation", required = true)
private String fileLocation;
public String getFileURL() {
return fileURL;
}
public void setFileURL(String fileURL) {
this.fileURL = fileURL;
}
public String getFtpPassword() {
return ftpPassword;
}
public void setFtpPassword(String ftpPassword) {
this.ftpPassword = ftpPassword;
}
public String getFileLocation() {
return fileLocation;
}
public void setFileLocation(String fileLocation) {
this.fileLocation = fileLocation;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}

@ -0,0 +1,66 @@
/*
* 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.
*/
package org.wso2.carbon.mdm.services.android.bean.wrapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.mdm.services.android.bean.FileTransfer;
import java.util.List;
/**
* This class is used to wrap the File Transfer bean with devices.
*/
@ApiModel(value = "FileTransferBeanWrapper",
description = "FileTransfer related Information.")
public class FileTransferBeanWrapper {
@ApiModelProperty(name = "deviceIDs", value = "Device id list of the operation to be executed.", required = true)
private List<String> deviceIDs;
@ApiModelProperty(name = "upload", value = "Upload / Download w.r.t device.",
notes = "upload = true , If file is to be uploaded to the device.", required = true)
private boolean upload;
@ApiModelProperty(name = "operation", value = "Information of the File Transfer Operation.", required = true)
private FileTransfer operation;
public List<String> getDeviceIDs() {
return deviceIDs;
}
public void setDeviceIDs(List<String> deviceIDs) {
this.deviceIDs = deviceIDs;
}
public FileTransfer getOperation() {
return operation;
}
public void setOperation(FileTransfer operation) {
this.operation = operation;
}
public boolean isUpload() {
return upload;
}
public void setUpload(boolean upload) {
this.upload = upload;
}
}

@ -216,11 +216,78 @@ import java.util.List;
description = "Setting a Web Clip on Android Devices", description = "Setting a Web Clip on Android Devices",
key = "perm:android:set-webclip", key = "perm:android:set-webclip",
permissions = {"/device-mgt/devices/owning-device/operations/android/webclip"} permissions = {"/device-mgt/devices/owning-device/operations/android/webclip"}
),
@Scope(
name = "File Transfer",
description = "Transferring a file to android devices",
key = "perm:android:file-transfer",
permissions = {"/device-mgt/devices/owning-device/operations/android/file-transfer"}
) )
} }
) )
public interface DeviceManagementAdminService { public interface DeviceManagementAdminService {
@POST
@Path("/file-transfer")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Transferring file to the device.",
notes = "Using this API you have the option to transfer a file from SFTP/FTP server or using an " +
"HTTP link to the device or retrieve file from the device to FTP/SFTP server .",
response = Activity.class,
tags = "Android Device Management Administrative Service",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = AndroidConstants.SCOPE, value = "perm:android:file-transfer")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "File transferred.",
response = Activity.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "URL of the activity instance that refers to the scheduled operation."),
@ResponseHeader(
name = "Content-Type",
description = "Content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource was last modified. \n" +
"Used by caches, or in conditional requests.")}),
@ApiResponse(
code = 303,
message = "See Other. \n The source can be retrieved from the URL specified in the location header.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The Source URL of the document.")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error."),
@ApiResponse(
code = 415,
message = "Unsupported media type. \n The format of the requested entity was not supported.\n"),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n " +
"Server error occurred while file transfer operation.")
})
Response fileTransfer(
@ApiParam(
name = "fileTransfer",
value = "Provide the ID of the Android device. Multiple device IDs can be added by using " +
"comma separated values.",
required = true) FileTransferBeanWrapper fileTransferBeanWrapper);
@POST @POST
@Path("/lock-devices") @Path("/lock-devices")
@ApiOperation( @ApiOperation(
@ -343,7 +410,7 @@ public interface DeviceManagementAdminService {
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ", value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@ -405,7 +472,7 @@ public interface DeviceManagementAdminService {
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ", value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/clear-password") @Path("/clear-password")
@ -463,7 +530,7 @@ public interface DeviceManagementAdminService {
Response removePassword( Response removePassword(
@ApiParam(name = "deviceIDs", @ApiParam(name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ", value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ",
required = true) List<String> deviceIDs); required = true) List<String> deviceIDs);
@POST @POST
@Path("/control-camera") @Path("/control-camera")
@ -478,7 +545,7 @@ public interface DeviceManagementAdminService {
@Extension(properties = { @Extension(properties = {
@ExtensionProperty(name = AndroidConstants.SCOPE, value = "perm:android:control-camera") @ExtensionProperty(name = AndroidConstants.SCOPE, value = "perm:android:control-camera")
}) })
} ) })
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse( @ApiResponse(
code = 201, code = 201,
@ -525,7 +592,7 @@ public interface DeviceManagementAdminService {
"camera on the device to function by defining false as the value and the ID of the Android device. " + "camera on the device to function by defining false as the value and the ID of the Android device. " +
"Multiple device IDs can be added by using comma separated values. ", "Multiple device IDs can be added by using comma separated values. ",
required = true) required = true)
CameraBeanWrapper cameraBeanWrapper); CameraBeanWrapper cameraBeanWrapper);
@POST @POST
@Path("/info") @Path("/info")
@ -588,7 +655,7 @@ public interface DeviceManagementAdminService {
name = "deviceIds", name = "deviceIds",
value = "Provide the device ID of the Android device. Multiple device IDs can be added by using comma separated values.", value = "Provide the device ID of the Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/logcat") @Path("/logcat")
@ -623,11 +690,11 @@ public interface DeviceManagementAdminService {
@ResponseHeader( @ResponseHeader(
name = "ETag", name = "ETag",
description = "Entity Tag of the response resource.\n" + description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."), "Used by caches, or in conditional requests."),
@ResponseHeader( @ResponseHeader(
name = "Last-Modified", name = "Last-Modified",
description = "Date and time the resource was last modified.\n" + description = "Date and time the resource was last modified.\n" +
"Used by caches, or in conditional requests.")}), "Used by caches, or in conditional requests.")}),
@ApiResponse( @ApiResponse(
code = 303, code = 303,
message = "See Other. \n The source can be retrieved from the URL specified in the location header.", message = "See Other. \n The source can be retrieved from the URL specified in the location header.",
@ -644,7 +711,7 @@ public interface DeviceManagementAdminService {
@ApiResponse( @ApiResponse(
code = 500, code = 500,
message = "Internal Server Error. \n " + message = "Internal Server Error. \n " +
"Server error occurred while adding a new device logcat operation.") "Server error occurred while adding a new device logcat operation.")
}) })
Response getDeviceLogcat( Response getDeviceLogcat(
@ApiParam( @ApiParam(
@ -712,7 +779,7 @@ public interface DeviceManagementAdminService {
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ", value = "Provide the ID of the Android device. Multiple device IDs can be added by using comma separated values. ",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/wipe") @Path("/wipe")
@ -773,7 +840,7 @@ public interface DeviceManagementAdminService {
value = "Provide the the passcode, which is the passcode that the Android agent prompts the device owner to set at the time of device enrollment, " + value = "Provide the the passcode, which is the passcode that the Android agent prompts the device owner to set at the time of device enrollment, " +
"to enable the factory reset operation, and the ID of the Android device. Multiple device IDs can be added by using comma separated values. ", "to enable the factory reset operation, and the ID of the Android device. Multiple device IDs can be added by using comma separated values. ",
required = true) required = true)
WipeDataBeanWrapper wipeDataBeanWrapper); WipeDataBeanWrapper wipeDataBeanWrapper);
@POST @POST
@Path("/applications") @Path("/applications")
@ -835,9 +902,9 @@ public interface DeviceManagementAdminService {
Response getApplications( Response getApplications(
@ApiParam( @ApiParam(
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values." , value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values.",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/ring") @Path("/ring")
@ -897,7 +964,7 @@ public interface DeviceManagementAdminService {
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values.", value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values.",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/reboot") @Path("/reboot")
@ -957,7 +1024,7 @@ public interface DeviceManagementAdminService {
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values. ", value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values. ",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/mute") @Path("/mute")
@ -1017,7 +1084,7 @@ public interface DeviceManagementAdminService {
name = "deviceIDs", name = "deviceIDs",
value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values. ", value = "Provide the ID of the Android device. Multiple device IDs can be added using comma separated values. ",
required = true) required = true)
List<String> deviceIDs); List<String> deviceIDs);
@POST @POST
@Path("/install-application") @Path("/install-application")
@ -1081,7 +1148,7 @@ public interface DeviceManagementAdminService {
" URL and name of the application, the date and time for the scheduled installation, and the ID of the " + " URL and name of the application, the date and time for the scheduled installation, and the ID of the " +
"Android device. Multiple device IDs can be added by using comma separated values.", "Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
ApplicationInstallationBeanWrapper applicationInstallationBeanWrapper); ApplicationInstallationBeanWrapper applicationInstallationBeanWrapper);
@POST @POST
@Path("/update-application") @Path("/update-application")
@ -1146,7 +1213,7 @@ public interface DeviceManagementAdminService {
"URL and name of the application, the date and time for the scheduled installation, and the ID of the" + "URL and name of the application, the date and time for the scheduled installation, and the ID of the" +
"Android device. Multiple device IDs can be added by using comma separated values.", "Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
ApplicationUpdateBeanWrapper applicationUpdateBeanWrapper); ApplicationUpdateBeanWrapper applicationUpdateBeanWrapper);
@POST @POST
@Path("/uninstall-application") @Path("/uninstall-application")
@ -1208,7 +1275,7 @@ public interface DeviceManagementAdminService {
"URL and name of the application, the date and time for the scheduled installation, and the ID of the" + "URL and name of the application, the date and time for the scheduled installation, and the ID of the" +
"Android device. Multiple device IDs can be added by using comma separated values.", "Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
ApplicationUninstallationBeanWrapper applicationUninstallationBeanWrapper); ApplicationUninstallationBeanWrapper applicationUninstallationBeanWrapper);
@POST @POST
@Path("/blacklist-applications") @Path("/blacklist-applications")
@ -1337,7 +1404,7 @@ public interface DeviceManagementAdminService {
"(example: http//abc.com, http://abc.com/ota), " + "(example: http//abc.com, http://abc.com/ota), " +
"and the ID of the Android device. Multiple device IDs can be added by using comma separated values.", "and the ID of the Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
UpgradeFirmwareBeanWrapper upgradeFirmwareBeanWrapper); UpgradeFirmwareBeanWrapper upgradeFirmwareBeanWrapper);
@POST @POST
@Path("/configure-vpn") @Path("/configure-vpn")
@ -1398,7 +1465,7 @@ public interface DeviceManagementAdminService {
name = "vpnBean", name = "vpnBean",
value = "VPN configuration and DeviceIds", value = "VPN configuration and DeviceIds",
required = true) required = true)
VpnBeanWrapper vpnBeanWrapper); VpnBeanWrapper vpnBeanWrapper);
@POST @POST
@Path("/send-notification") @Path("/send-notification")
@ -1459,7 +1526,7 @@ public interface DeviceManagementAdminService {
value = "The properties required to send a notification. Provide the message you wish to send and the ID of the " + value = "The properties required to send a notification. Provide the message you wish to send and the ID of the " +
"Android device. Multiple device IDs can be added by using comma separated values.", "Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
NotificationBeanWrapper notificationBeanWrapper); NotificationBeanWrapper notificationBeanWrapper);
@POST @POST
@Path("/configure-wifi") @Path("/configure-wifi")
@ -1521,7 +1588,7 @@ public interface DeviceManagementAdminService {
"the ssid or the name of the Wi-Fi network that you wish to configure and the ID of the Android device." + "the ssid or the name of the Wi-Fi network that you wish to configure and the ID of the Android device." +
" Multiple device IDs can be added by using comma separated values.", " Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
WifiBeanWrapper wifiBeanWrapper); WifiBeanWrapper wifiBeanWrapper);
@POST @POST
@Path("/encrypt-storage") @Path("/encrypt-storage")
@ -1583,7 +1650,7 @@ public interface DeviceManagementAdminService {
"true as the value or do not encrypt the storage on the device by assigning false as the value and " + "true as the value or do not encrypt the storage on the device by assigning false as the value and " +
"provide the ID of the Android device. Multiple device IDs can be added by using comma separated values.", "provide the ID of the Android device. Multiple device IDs can be added by using comma separated values.",
required = true) required = true)
EncryptionBeanWrapper encryptionBeanWrapper); EncryptionBeanWrapper encryptionBeanWrapper);
@POST @POST
@Path("/change-lock-code") @Path("/change-lock-code")
@ -1645,7 +1712,7 @@ public interface DeviceManagementAdminService {
"the ID of the Android device. Multiple device IDs can be added by using comma separated values. " + "the ID of the Android device. Multiple device IDs can be added by using comma separated values. " +
"If a passcode policy has been set in EMM, the lock code should comply to the passcode policy.\t", "If a passcode policy has been set in EMM, the lock code should comply to the passcode policy.\t",
required = true) required = true)
LockCodeBeanWrapper lockCodeBeanWrapper); LockCodeBeanWrapper lockCodeBeanWrapper);
@POST @POST
@Path("/set-password-policy") @Path("/set-password-policy")
@ -1705,7 +1772,7 @@ public interface DeviceManagementAdminService {
name = "passwordPolicy", name = "passwordPolicy",
value = "The properties required to set a password policy.", value = "The properties required to set a password policy.",
required = true) required = true)
PasswordPolicyBeanWrapper passwordPolicyBeanWrapper); PasswordPolicyBeanWrapper passwordPolicyBeanWrapper);
@POST @POST
@Path("/set-webclip") @Path("/set-webclip")
@ -1765,7 +1832,7 @@ public interface DeviceManagementAdminService {
name = "webClip", name = "webClip",
value = "The properties to set the web clip.", value = "The properties to set the web clip.",
required = true) required = true)
WebClipBeanWrapper webClipBeanWrapper); WebClipBeanWrapper webClipBeanWrapper);
} }

@ -36,6 +36,7 @@ import org.wso2.carbon.mdm.services.android.bean.Camera;
import org.wso2.carbon.mdm.services.android.bean.DeviceEncryption; import org.wso2.carbon.mdm.services.android.bean.DeviceEncryption;
import org.wso2.carbon.mdm.services.android.bean.DeviceLock; import org.wso2.carbon.mdm.services.android.bean.DeviceLock;
import org.wso2.carbon.mdm.services.android.bean.ErrorResponse; import org.wso2.carbon.mdm.services.android.bean.ErrorResponse;
import org.wso2.carbon.mdm.services.android.bean.FileTransfer;
import org.wso2.carbon.mdm.services.android.bean.LockCode; import org.wso2.carbon.mdm.services.android.bean.LockCode;
import org.wso2.carbon.mdm.services.android.bean.Notification; import org.wso2.carbon.mdm.services.android.bean.Notification;
import org.wso2.carbon.mdm.services.android.bean.PasscodePolicy; import org.wso2.carbon.mdm.services.android.bean.PasscodePolicy;
@ -51,6 +52,7 @@ import org.wso2.carbon.mdm.services.android.bean.wrapper.BlacklistApplicationsBe
import org.wso2.carbon.mdm.services.android.bean.wrapper.CameraBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.CameraBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.DeviceLockBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.DeviceLockBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.EncryptionBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.EncryptionBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.FileTransferBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.LockCodeBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.LockCodeBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.NotificationBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.NotificationBeanWrapper;
import org.wso2.carbon.mdm.services.android.bean.wrapper.PasswordPolicyBeanWrapper; import org.wso2.carbon.mdm.services.android.bean.wrapper.PasswordPolicyBeanWrapper;
@ -89,6 +91,46 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
private static final Log log = LogFactory.getLog(DeviceManagementAdminServiceImpl.class); private static final Log log = LogFactory.getLog(DeviceManagementAdminServiceImpl.class);
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
@POST
@Path("/file-transfer")
@Override
public Response fileTransfer(FileTransferBeanWrapper fileTransferBeanWrapper) {
try {
if (fileTransferBeanWrapper == null || fileTransferBeanWrapper.getOperation() == null
|| fileTransferBeanWrapper.getDeviceIDs() == null) {
String errorMessage = "The payload of the file transfer operation is incorrect.";
log.error(errorMessage);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
}
if (log.isDebugEnabled()) {
log.debug("Invoking Android file transfer operation for " + fileTransferBeanWrapper.getDeviceIDs());
}
FileTransfer file = fileTransferBeanWrapper.getOperation();
ProfileOperation operation = new ProfileOperation();
if (fileTransferBeanWrapper.isUpload()) {
operation.setCode(AndroidConstants.OperationCodes.FILE_DOWNLOAD);
} else {
operation.setCode(AndroidConstants.OperationCodes.FILE_UPLOAD);
}
operation.setType(Operation.Type.PROFILE);
operation.setEnabled(true);
operation.setPayLoad(file.toJSON());
Activity activity = AndroidDeviceUtils.getOperationResponse(fileTransferBeanWrapper.getDeviceIDs(), operation);
return Response.status(Response.Status.CREATED).entity(activity).build();
} catch (InvalidDeviceException e) {
String errorMessage = "Invalid Device Identifiers ( " + fileTransferBeanWrapper.getDeviceIDs() + " ) found.";
log.error(errorMessage, e);
throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
} catch (OperationManagementException e) {
String errorMessage = "Issue in retrieving operation management service instance for file transfer operation";
log.error(errorMessage, e);
throw new UnexpectedServerErrorException(
new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build());
}
}
@POST @POST
@Path("/lock-devices") @Path("/lock-devices")
@Override @Override
@ -113,10 +155,10 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
Activity activity = AndroidDeviceUtils.getOperationResponse(deviceLockBeanWrapper.getDeviceIDs(), operation); Activity activity = AndroidDeviceUtils.getOperationResponse(deviceLockBeanWrapper.getDeviceIDs(), operation);
return Response.status(Response.Status.CREATED).entity(activity).build(); return Response.status(Response.Status.CREATED).entity(activity).build();
} catch (InvalidDeviceException e) { } catch (InvalidDeviceException e) {
String errorMessage = "Invalid Device Identifiers found."; String errorMessage = "Invalid Device Identifiers found.";
log.error(errorMessage, e); log.error(errorMessage, e);
throw new BadRequestException( throw new BadRequestException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build()); new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage).build());
} catch (OperationManagementException e) { } catch (OperationManagementException e) {
String errorMessage = "Issue in retrieving operation management service instance"; String errorMessage = "Issue in retrieving operation management service instance";
log.error(errorMessage, e); log.error(errorMessage, e);
@ -475,7 +517,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
try { try {
if (applicationInstallationBeanWrapper == null || applicationInstallationBeanWrapper.getOperation() == if (applicationInstallationBeanWrapper == null || applicationInstallationBeanWrapper.getOperation() ==
null) { null) {
String errorMessage = "The payload of the application installing operation is incorrect"; String errorMessage = "The payload of the application installing operation is incorrect";
log.error(errorMessage); log.error(errorMessage);
throw new BadRequestException( throw new BadRequestException(
@ -920,7 +962,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
try { try {
URL url = new URL(apkUrl); URL url = new URL(apkUrl);
URLConnection conn = url.openConnection(); URLConnection conn = url.openConnection();
if(((HttpURLConnection) conn).getResponseCode() != HttpURLConnection.HTTP_OK) { if (((HttpURLConnection) conn).getResponseCode() != HttpURLConnection.HTTP_OK) {
String errorMessage = "URL is not pointed to a downloadable file."; String errorMessage = "URL is not pointed to a downloadable file.";
log.error(errorMessage); log.error(errorMessage);
throw new BadRequestException( throw new BadRequestException(
@ -942,8 +984,8 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
private static void validateApplicationType(String type) { private static void validateApplicationType(String type) {
if (type != null) { if (type != null) {
if (!"enterprise".equalsIgnoreCase(type) if (!"enterprise".equalsIgnoreCase(type)
&& !"public".equalsIgnoreCase(type) && !"public".equalsIgnoreCase(type)
&& !"webapp".equalsIgnoreCase(type)) { && !"webapp".equalsIgnoreCase(type)) {
String errorMessage = "Invalid application type."; String errorMessage = "Invalid application type.";
log.error(errorMessage); log.error(errorMessage);
throw new BadRequestException( throw new BadRequestException(
@ -957,7 +999,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
} }
} }
private static void validateScheduleDate(String dateString){ private static void validateScheduleDate(String dateString) {
try { try {
if (dateString != null && !dateString.isEmpty()) { if (dateString != null && !dateString.isEmpty()) {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);

@ -74,6 +74,8 @@ public final class AndroidConstants {
} }
public static final String DEVICE_LOCK = "DEVICE_LOCK"; public static final String DEVICE_LOCK = "DEVICE_LOCK";
public static final String FILE_DOWNLOAD = "FILE_UPLOAD_TO_THE_DEVICE";
public static final String FILE_UPLOAD = "FILE_DOWNLOAD_FROM_THE_DEVICE";
public static final String DEVICE_UNLOCK = "DEVICE_UNLOCK"; public static final String DEVICE_UNLOCK = "DEVICE_UNLOCK";
public static final String DEVICE_LOCATION = "DEVICE_LOCATION"; public static final String DEVICE_LOCATION = "DEVICE_LOCATION";
public static final String WIFI = "WIFI"; public static final String WIFI = "WIFI";

@ -71,6 +71,10 @@
<i class="icon fw fw-error"></i><span></span> <i class="icon fw fw-error"></i><span></span>
</div> </div>
<div id="operation-warn-msg" class="info alert-info hidden" role="alert">
<i class="icon fw fw-info"></i><span></span>
</div>
<div id="operation-form"> <div id="operation-form">
<form action="{{params.0.uri}}" method="{{params.0.method}}" <form action="{{params.0.uri}}" method="{{params.0.method}}"
style="padding-bottom: 20px;" style="padding-bottom: 20px;"
@ -94,6 +98,24 @@
<br/> <br/>
{{/each}} {{/each}}
{{#each uiParams}} {{#each uiParams}}
{{#equal this.type "select"}}
<div class="form-group">
<select class="form-control" id="{{this.id}}">
<option>{{this.valueOne}}</option>
<option>{{this.valueTwo}}</option>
<option>{{this.valueThree}}</option>
</select>
</div>
{{/equal}}
{{#equal this.type "radio"}}
<input type="radio" id="{{this.id}}"
name="{{this.name}}"
value="{{this.value}}"
class="radio"
checked="checked"
data-param-type="form"/>
{{this.value}}
{{/equal}}
{{#equal this.type "checkbox"}} {{#equal this.type "checkbox"}}
<input type="{{this.type}}" id="{{this.id}}" <input type="{{this.type}}" id="{{this.id}}"
class="checkbox" class="checkbox"
@ -102,12 +124,25 @@
{{this.label}} {{this.label}}
<br/> <br/>
{{/equal}} {{/equal}}
{{#equal this.type "password"}}
<input type="{{this.type}}" id="{{this.id}}"
placeholder="{{this.label}}" class="form-control"
data-param-type="form" value=""/>
<br/>
{{/equal}}
{{#equal this.type "text"}} {{#equal this.type "text"}}
<input type="{{this.type}}" id="{{this.id}}" <input type="{{this.type}}" id="{{this.id}}"
placeholder="{{this.label}}" class="form-control" placeholder="{{this.label}}" class="form-control"
data-param-type="form" value=""/> data-param-type="form" value=""/>
<br/> <br/>
{{/equal}} {{/equal}}
{{#equal this.type "info"}}
<div class="form-group" id="{{this.id}}">
<span class="help-block">
+ {{this.value}}
</span>
</div>
{{/equal}}
{{/each}} {{/each}}
<button id="btnSend" type="button" onclick="submitForm('form-{{operation}}')" <button id="btnSend" type="button" onclick="submitForm('form-{{operation}}')"
class="btn btn-default">Send class="btn btn-default">Send

@ -24,6 +24,9 @@ function operationSelect(selection) {
$(modalPopupContent).addClass("operation-data"); $(modalPopupContent).addClass("operation-data");
$(modalPopupContent).html($(" .operation[data-operation-code=" + selection + "]").html()); $(modalPopupContent).html($(" .operation[data-operation-code=" + selection + "]").html());
$(modalPopupContent).data("operation-code", selection); $(modalPopupContent).data("operation-code", selection);
if (selection === "FILE_TRANSFER") {
fileTransferSelection();
}
showPopup(); showPopup();
} }
@ -32,6 +35,81 @@ var resetLoader = function () {
$('#lbl-execution').addClass("hidden"); $('#lbl-execution').addClass("hidden");
}; };
/**
* This function changes/hide/show field respective to the selection.
*/
function fileTransferSelection() {
var userName = document.getElementById('userName');
var password = document.getElementById('ftpPassword');
var infoTxt = document.getElementById('defaultFileLocation');
$(userName).hide();
$(password).hide();
$(infoTxt).hide();
fillUserName();
checkAuth();
changeLabels();
}
/**
* This changes the text box label when the operation is toggled between To device and From device
* and shows an info label for FILE UPLOAD regarding saving location.
*/
function changeLabels() {
var upload = document.getElementById('upload');
var download = document.getElementById('download');
var infoTxt = document.getElementById('defaultFileLocation');
console.log("info text " + infoTxt.value);
jQuery(upload).change(function () {
document.getElementById('fileURL').placeholder = "File URL";
document.getElementById('fileLocation').placeholder = "Location to save file in device";
$(infoTxt).show();
});
jQuery(download).change(function () {
document.getElementById('fileURL').placeholder = "URL to upload file from device";
document.getElementById('fileLocation').placeholder = "File location in the device";
$(infoTxt).hide();
});
}
/**
* This function show/hide username and password text boxes when authentication is toggled.
*/
function checkAuth() {
var auth = document.getElementById('authentication');
var userName = document.getElementById('userName');
var password = document.getElementById('ftpPassword');
jQuery(auth).click(function () {
if (this.checked) {
$(userName).show();
$(password).show();
} else {
$(userName).hide();
$(password).hide();
}
});
}
/**
* This function extracts the user name from the file url and fills it in the user name field.
*/
function fillUserName() {
var inputBox = document.getElementById('fileURL');
var regexp = ':\/\/[^\/]*@';
var pattern = new RegExp(regexp);
jQuery(inputBox).on('input', function () {
var fileUrl = inputBox.value;
var res = pattern.test(fileUrl);
if (res) {
var name = fileUrl.match(regexp).toString();
document.getElementById('userName').value = name.substring(3, name.length - 1);
} else {
document.getElementById('userName').value = "";
document.getElementById('userName').placeholder = "User Name"
}
}
);
}
function submitForm(formId) { function submitForm(formId) {
$("#btnSend").addClass("hidden"); $("#btnSend").addClass("hidden");
$("#lbl-execution").removeClass("hidden"); $("#lbl-execution").removeClass("hidden");
@ -53,10 +131,12 @@ function submitForm(formId) {
} else if (input.data("param-type") == "form") { } else if (input.data("param-type") == "form") {
var prefix = (uriencodedFormStr == "") ? "" : "&"; var prefix = (uriencodedFormStr == "") ? "" : "&";
uriencodedFormStr += prefix + input.attr("id") + "=" + input.val(); uriencodedFormStr += prefix + input.attr("id") + "=" + input.val();
if (input.attr("type") == "text") { if (input.attr("type") == "text" || input.attr("type") == "password") {
payload[input.attr("id")] = input.val(); payload[input.attr("id")] = input.val();
} else if (input.attr("type") == "checkbox") { } else if (input.attr("type") == "checkbox") {
payload[input.attr("id")] = input.is(":checked"); payload[input.attr("id")] = input.is(":checked");
} else if (input.attr("type") == "radio") {
payload[input.attr("id")] = input.is(":checked");
} }
} }
}); });
@ -76,7 +156,7 @@ function submitForm(formId) {
var defaultStatusClasses = "fw fw-stack-1x"; var defaultStatusClasses = "fw fw-stack-1x";
var content = $("#operation-response-template").find(".content"); var content = $("#operation-response-template").find(".content");
var title = content.find("#title"); var title = content.find("#title");
title.attr("class","center-block text-center"); title.attr("class", "center-block text-center");
var statusIcon = content.find("#status-icon"); var statusIcon = content.find("#status-icon");
var description = content.find("#description"); var description = content.find("#description");
description.html(""); description.html("");
@ -179,6 +259,9 @@ function validatePayload(operationCode, payload) {
returnVal = "Message Body Can't be empty !"; returnVal = "Message Body Can't be empty !";
} }
break; break;
case "FILE_TRANSFER":
returnVal = validateFileTransferParameters(payload);
break;
default: default:
break; break;
@ -186,6 +269,33 @@ function validatePayload(operationCode, payload) {
return returnVal; return returnVal;
} }
/**
* This function validates all the parameters that are entered related to the file transfer operation.
* @param payload
* @returns {string}
*/
function validateFileTransferParameters(payload) {
var returnVal = "OK";
var auth = document.getElementById('authentication');
var protocol = $(document.getElementById('protocol')).find("option:selected").text();
if (payload.upload && !payload.fileURL) {
returnVal = "Please enter File URL";
} else if (!payload.upload && !payload.fileURL) {
returnVal = "Please enter the URL to upload file from device";
} else if (protocol === "HTTP" && !(payload.fileURL).startsWith("http:")) {
returnVal = "Please enter HTTP URL"
} else if (protocol === "FTP" && !(payload.fileURL).startsWith("ftp:")) {
returnVal = "Please enter FTP URL"
} else if (protocol === "SFTP" && !(payload.fileURL).startsWith("sftp:")) {
returnVal = "Please enter SFTP URL"
} else if (!payload.upload && !payload.fileLocation) {
returnVal = "Please specify the file location in device";
} else if (auth.checked && !payload.userName) {
returnVal = "Please enter the user name if authentication required"
}
return returnVal;
}
var generatePayload = function (operationCode, operationData, deviceList) { var generatePayload = function (operationCode, operationData, deviceList) {
var payload; var payload;
var operationType; var operationType;
@ -239,6 +349,18 @@ var generatePayload = function (operationCode, operationData, deviceList) {
} }
}; };
break; break;
case androidOperationConstants["FILE_TRANSFER"]:
operationType = operationTypeConstants["PROFILE"];
payload = {
"operation": {
"fileURL": operationData["fileURL"],
"userName": operationData["userName"],
"ftpPassword": operationData["ftpPassword"],
"fileLocation": operationData["fileLocation"]
},
"upload": operationData["upload"]
};
break;
case androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"]: case androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"]:
operationType = operationTypeConstants["PROFILE"]; operationType = operationTypeConstants["PROFILE"];
payload = { payload = {
@ -433,5 +555,6 @@ var androidOperationConstants = {
"SET_STATUS_BAR_DISABLED": "SET_STATUS_BAR_DISABLED", "SET_STATUS_BAR_DISABLED": "SET_STATUS_BAR_DISABLED",
"APPLICATION_OPERATION_CODE": "APP-RESTRICTION", "APPLICATION_OPERATION_CODE": "APP-RESTRICTION",
"SYSTEM_UPDATE_POLICY_CODE": "SYSTEM_UPDATE_POLICY", "SYSTEM_UPDATE_POLICY_CODE": "SYSTEM_UPDATE_POLICY",
"KIOSK_APPS_CODE": "KIOSK_APPS" "KIOSK_APPS_CODE": "KIOSK_APPS",
}; "FILE_TRANSFER": "FILE_TRANSFER"
};

@ -6,6 +6,7 @@
"analyticsEnabled": "false", "analyticsEnabled": "false",
"groupingEnabled": "false", "groupingEnabled": "false",
"scopes" : [ "scopes" : [
"perm:android:file-transfer",
"perm:android:enroll", "perm:android:enroll",
"perm:android:wipe", "perm:android:wipe",
"perm:android:ring", "perm:android:ring",
@ -135,6 +136,72 @@
"icon": "fw-block", "icon": "fw-block",
"permission": "/device-mgt/devices/owning-device/operations/android/enterprise-wipe" "permission": "/device-mgt/devices/owning-device/operations/android/enterprise-wipe"
}, },
"FILE_TRANSFER": {
"icon": "fw-save",
"formParams": [
{
"type": "radio",
"name": "directionSelection",
"id": "upload",
"optional": false,
"value": "To device"
},
{
"type": "radio",
"name": "directionSelection",
"id": "download",
"optional": false,
"value": "From device"
},
{
"type": "select",
"name": "protocolSelection",
"id": "protocol",
"optional": false,
"valueOne": "HTTP",
"valueTwo": "FTP",
"valueThree": "SFTP",
"label": "Protocol"
},
{
"type": "text",
"id": "fileURL",
"optional": false,
"label": "URL to upload file from device"
},
{
"type": "text",
"id": "fileLocation",
"optional": false,
"label": "File location in the device"
},
{
"type": "info",
"id": "defaultFileLocation",
"optional": false,
"value": "File will be saved in Default download directory if not specified."
},
{
"type": "checkbox",
"id": "authentication",
"optional": true,
"label": "Authentication required"
},
{
"type": "text",
"id": "userName",
"optional": false,
"label": "User Name"
},
{
"type": "password",
"id": "ftpPassword",
"optional": false,
"label": "Password (Ignore if not needed)"
}
],
"permission": "/device-mgt/devices/owning-device/operations/android/file-transfer"
},
"WIPE_DATA": { "WIPE_DATA": {
"icon": "fw-delete", "icon": "fw-delete",
"formParams": [ "formParams": [

@ -141,6 +141,12 @@
<Operation context="/api/device-mgt/android/v1.0/admin/devices/change-lock-code" method="POST" type="application/json"> <Operation context="/api/device-mgt/android/v1.0/admin/devices/change-lock-code" method="POST" type="application/json">
</Operation> </Operation>
</Feature> </Feature>
<Feature code="FILE_TRANSFER">
<Name>File Transfer</Name>
<Description>Transfer file to the device</Description>
<Operation context="/api/device-mgt/android/v1.0/admin/devices/file-transfer" method="POST" type="application/json">
</Operation>
</Feature>
<Feature code="ENTERPRISE_WIPE"> <Feature code="ENTERPRISE_WIPE">
<Name>Enterprise Wipe</Name> <Name>Enterprise Wipe</Name>
<Description>Remove enterprise applications</Description> <Description>Remove enterprise applications</Description>
@ -380,4 +386,4 @@
<IdleTimeToMarkInactive>900</IdleTimeToMarkInactive> <IdleTimeToMarkInactive>900</IdleTimeToMarkInactive>
<IdleTimeToMarkUnreachable>600</IdleTimeToMarkUnreachable> <IdleTimeToMarkUnreachable>600</IdleTimeToMarkUnreachable>
</DeviceStatusTaskConfig> </DeviceStatusTaskConfig>
</DeviceTypeConfiguration> </DeviceTypeConfiguration>

Loading…
Cancel
Save