mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Add Devices filtering by a Custom Property feature to API and dao layer (#208)
## Purpose * Related ticket https://roadmap.entgra.net/issues/10262 ## Description This modifed API accept any custom property key value pair as a encoded JSON String for filtering devices /devicescustomProperty=%7B%22FIRMWARE_APP_VERSION%22%3A%22122%22%2C%22FIRMWARE_VERSION%22%3A%22123%22%7D ## Add Custom property to mdm-ui-config.xml ``` <DeviceInfoConfigurations> <DeviceInfoItem> <DefinedValue>FIRMWARE_VERSION</DefinedValue> <DisplayValue>label_firmware_version</DisplayValue> <Type>deviceDetailsMap</Type> </DeviceInfoItem> <DeviceInfoItem> <DefinedValue>FIRMWARE_APP_VERSION</DefinedValue> <DisplayValue>label_app_version</DisplayValue> <Type>deviceDetailsMap</Type> </DeviceInfoItem> <DeviceInfoItem> <DefinedValue>FIRMWARE_SYSTEM_VERSION</DefinedValue> <DisplayValue>label_firmware_system_version</DisplayValue> <Type>deviceDetailsMap</Type> </DeviceInfoItem> </DeviceInfoConfigurations> ``` DefinedValue = Key_value in DM_DEVECE_INFO table DisplayValue = UI display text for filtering Type = Dont change Co-authored-by: pramilaniroshan <pramila@entgra.io> Reviewed-on: https://repository.entgra.net/community/device-mgt-core/pulls/208 Co-authored-by: Pramila Niroshan <pramila@entgra.io> Co-committed-by: Pramila Niroshan <pramila@entgra.io>
This commit is contained in:
parent
ea6744288a
commit
fccae9b8c0
@ -65,6 +65,7 @@ import javax.ws.rs.core.MediaType;
|
|||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device related REST-API. This can be used to manipulated device related details.
|
* Device related REST-API. This can be used to manipulated device related details.
|
||||||
@ -283,6 +284,12 @@ public interface DeviceManagementService {
|
|||||||
required = false)
|
required = false)
|
||||||
@QueryParam("serialNumber")
|
@QueryParam("serialNumber")
|
||||||
String serialNumber,
|
String serialNumber,
|
||||||
|
@ApiParam(
|
||||||
|
name = "customProperty",
|
||||||
|
value = "CustomProperty from device as a JSON encoded string.",
|
||||||
|
required = false)
|
||||||
|
@QueryParam("customProperty")
|
||||||
|
String customProperty,
|
||||||
@ApiParam(
|
@ApiParam(
|
||||||
name = "status",
|
name = "status",
|
||||||
value = "Provide the device status details, such as active or inactive.",
|
value = "Provide the device status details, such as active or inactive.",
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl;
|
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import io.entgra.device.mgt.core.application.mgt.common.ApplicationInstallResponse;
|
import io.entgra.device.mgt.core.application.mgt.common.ApplicationInstallResponse;
|
||||||
import io.entgra.device.mgt.core.application.mgt.common.SubscriptionType;
|
import io.entgra.device.mgt.core.application.mgt.common.SubscriptionType;
|
||||||
@ -29,7 +30,6 @@ import org.apache.commons.httpclient.HttpStatus;
|
|||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.json.JSONObject;
|
|
||||||
import io.entgra.device.mgt.core.apimgt.keymgt.extension.DCRResponse;
|
import io.entgra.device.mgt.core.apimgt.keymgt.extension.DCRResponse;
|
||||||
import io.entgra.device.mgt.core.apimgt.keymgt.extension.TokenRequest;
|
import io.entgra.device.mgt.core.apimgt.keymgt.extension.TokenRequest;
|
||||||
import io.entgra.device.mgt.core.apimgt.keymgt.extension.TokenResponse;
|
import io.entgra.device.mgt.core.apimgt.keymgt.extension.TokenResponse;
|
||||||
@ -64,7 +64,6 @@ import io.entgra.device.mgt.core.device.mgt.common.type.mgt.DeviceStatus;
|
|||||||
import io.entgra.device.mgt.core.device.mgt.core.app.mgt.ApplicationManagementProviderService;
|
import io.entgra.device.mgt.core.device.mgt.core.app.mgt.ApplicationManagementProviderService;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceConfigurationManager;
|
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceConfigurationManager;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceManagementConfig;
|
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceManagementConfig;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.dao.TrackerManagementDAOException;
|
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.DeviceDetailsMgtException;
|
import io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.DeviceDetailsMgtException;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.DeviceInformationManager;
|
import io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.DeviceInformationManager;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.dto.DeviceType;
|
import io.entgra.device.mgt.core.device.mgt.core.dto.DeviceType;
|
||||||
@ -75,10 +74,7 @@ import io.entgra.device.mgt.core.device.mgt.core.search.mgt.SearchManagerService
|
|||||||
import io.entgra.device.mgt.core.device.mgt.core.search.mgt.SearchMgtException;
|
import io.entgra.device.mgt.core.device.mgt.core.search.mgt.SearchMgtException;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.service.DeviceManagementProviderService;
|
import io.entgra.device.mgt.core.device.mgt.core.service.DeviceManagementProviderService;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.service.GroupManagementProviderService;
|
import io.entgra.device.mgt.core.device.mgt.core.service.GroupManagementProviderService;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.traccar.api.service.DeviceAPIClientService;
|
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.traccar.common.TraccarHandlerConstants;
|
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.util.DeviceManagerUtil;
|
import io.entgra.device.mgt.core.device.mgt.core.util.DeviceManagerUtil;
|
||||||
import io.entgra.device.mgt.core.device.mgt.core.util.HttpReportingUtil;
|
|
||||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.*;
|
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.*;
|
||||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api.DeviceManagementService;
|
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api.DeviceManagementService;
|
||||||
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util.InputValidationException;
|
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util.InputValidationException;
|
||||||
@ -98,6 +94,7 @@ import javax.validation.Valid;
|
|||||||
import javax.validation.constraints.Size;
|
import javax.validation.constraints.Size;
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.io.IOException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -105,6 +102,7 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Path("/devices")
|
@Path("/devices")
|
||||||
public class DeviceManagementServiceImpl implements DeviceManagementService {
|
public class DeviceManagementServiceImpl implements DeviceManagementService {
|
||||||
@ -142,6 +140,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
|||||||
@QueryParam("role") String role,
|
@QueryParam("role") String role,
|
||||||
@QueryParam("ownership") String ownership,
|
@QueryParam("ownership") String ownership,
|
||||||
@QueryParam("serialNumber") String serialNumber,
|
@QueryParam("serialNumber") String serialNumber,
|
||||||
|
@QueryParam("customProperty") String customProperty,
|
||||||
@QueryParam("status") List<String> status,
|
@QueryParam("status") List<String> status,
|
||||||
@QueryParam("groupId") int groupId,
|
@QueryParam("groupId") int groupId,
|
||||||
@QueryParam("since") String since,
|
@QueryParam("since") String since,
|
||||||
@ -155,6 +154,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
|||||||
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
|
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
|
||||||
}
|
}
|
||||||
// RequestValidationUtil.validateSelectionCriteria(type, user, roleName, ownership, status);
|
// RequestValidationUtil.validateSelectionCriteria(type, user, roleName, ownership, status);
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
RequestValidationUtil.validatePaginationParameters(offset, limit);
|
RequestValidationUtil.validatePaginationParameters(offset, limit);
|
||||||
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
|
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
|
||||||
DeviceAccessAuthorizationService deviceAccessAuthorizationService =
|
DeviceAccessAuthorizationService deviceAccessAuthorizationService =
|
||||||
@ -166,6 +166,22 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
|||||||
if (name != null && !name.isEmpty()) {
|
if (name != null && !name.isEmpty()) {
|
||||||
request.setDeviceName(name);
|
request.setDeviceName(name);
|
||||||
}
|
}
|
||||||
|
if (customProperty != null && !customProperty.isEmpty()) {
|
||||||
|
try {
|
||||||
|
Map<String, String> customProperties = objectMapper.readValue(customProperty, Map.class);
|
||||||
|
// Extract and set custom properties
|
||||||
|
for (Map.Entry<String, String> entry : customProperties.entrySet()) {
|
||||||
|
String propertyName = entry.getKey();
|
||||||
|
String propertyValue = entry.getValue();
|
||||||
|
// Add custom property to the paginationRequest object
|
||||||
|
request.addCustomProperty(propertyName, propertyValue);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
String msg = "Error occurred while converting custom property string to a Java Map";
|
||||||
|
log.error(msg);
|
||||||
|
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (type != null && !type.isEmpty()) {
|
if (type != null && !type.isEmpty()) {
|
||||||
request.setDeviceType(type);
|
request.setDeviceType(type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -157,7 +157,7 @@ public class DeviceManagementServiceImplTest {
|
|||||||
.toReturn(this.deviceAccessAuthorizationService);
|
.toReturn(this.deviceAccessAuthorizationService);
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
null, null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
|
||||||
}
|
}
|
||||||
@ -177,22 +177,22 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
null,null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, null, DEFAULT_OWNERSHIP,
|
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, null, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
null, null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
|
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
null, null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
|
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, true,
|
null, null, DEFAULT_STATUS_LIST, 1, null, null, true,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
}
|
}
|
||||||
@ -306,7 +306,7 @@ public class DeviceManagementServiceImplTest {
|
|||||||
.toReturn(this.deviceManagementProviderService);
|
.toReturn(this.deviceManagementProviderService);
|
||||||
Mockito.when(deviceAccessAuthorizationService.isDeviceAdminUser()).thenReturn(true);
|
Mockito.when(deviceAccessAuthorizationService.isDeviceAdminUser()).thenReturn(true);
|
||||||
deviceManagementService.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null,
|
deviceManagementService.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null,
|
||||||
DEFAULT_ROLE, DEFAULT_OWNERSHIP, null, DEFAULT_STATUS_LIST, 1,
|
DEFAULT_ROLE, DEFAULT_OWNERSHIP, null,null, DEFAULT_STATUS_LIST, 1,
|
||||||
null, null, false, 10, 5);
|
null, null, false, 10, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,11 +326,11 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP
|
||||||
, null, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
|
, null, null, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, null, DEFAULT_USERNAME, DEFAULT_ROLE, DEFAULT_OWNERSHIP
|
.getDevices(null, TEST_DEVICE_TYPE, null, DEFAULT_USERNAME, DEFAULT_ROLE, DEFAULT_OWNERSHIP
|
||||||
, null, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
|
, null, null, DEFAULT_STATUS_LIST, 1, null, null, false, 10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +352,7 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, "newuser", null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, "newuser", null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, null, null, false,
|
null, null, DEFAULT_STATUS_LIST, 0, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode());
|
||||||
Mockito.reset(this.deviceAccessAuthorizationService);
|
Mockito.reset(this.deviceAccessAuthorizationService);
|
||||||
@ -374,17 +374,17 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, false,
|
null, null, DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, true,
|
null, null, DEFAULT_STATUS_LIST, 0, null, ifModifiedSince, true,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, null, "ErrorModifiedSince",
|
null, null, DEFAULT_STATUS_LIST, 0, null, "ErrorModifiedSince",
|
||||||
false, 10, 5);
|
false, 10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
|
||||||
}
|
}
|
||||||
@ -405,17 +405,17 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, since, null, false,
|
null, null,DEFAULT_STATUS_LIST, 0, since, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, since, null, true,
|
null, null,DEFAULT_STATUS_LIST, 0, since, null, true,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
|
||||||
response = this.deviceManagementService
|
response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 0, "ErrorSince", null, false,
|
null, null,DEFAULT_STATUS_LIST, 0, "ErrorSince", null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
|
||||||
}
|
}
|
||||||
@ -438,7 +438,7 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
null, null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
Mockito.reset(this.deviceManagementProviderService);
|
Mockito.reset(this.deviceManagementProviderService);
|
||||||
@ -461,7 +461,7 @@ public class DeviceManagementServiceImplTest {
|
|||||||
|
|
||||||
Response response = this.deviceManagementService
|
Response response = this.deviceManagementService
|
||||||
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
|
||||||
null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
null, null, DEFAULT_STATUS_LIST, 1, null, null, false,
|
||||||
10, 5);
|
10, 5);
|
||||||
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||||
Mockito.reset(this.deviceAccessAuthorizationService);
|
Mockito.reset(this.deviceAccessAuthorizationService);
|
||||||
|
|||||||
@ -41,6 +41,7 @@ public class PaginationRequest {
|
|||||||
private Date since;
|
private Date since;
|
||||||
private String filter;
|
private String filter;
|
||||||
private String serialNumber;
|
private String serialNumber;
|
||||||
|
private Map<String, String> customProperty = new HashMap<>();
|
||||||
private Map<String, Object> property = new HashMap<>();
|
private Map<String, Object> property = new HashMap<>();
|
||||||
private List<String> statusList = new ArrayList<>();
|
private List<String> statusList = new ArrayList<>();
|
||||||
private OperationLogFilters operationLogFilters = new OperationLogFilters();
|
private OperationLogFilters operationLogFilters = new OperationLogFilters();
|
||||||
@ -115,6 +116,18 @@ public class PaginationRequest {
|
|||||||
return ownership;
|
return ownership;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getCustomProperty() {
|
||||||
|
return customProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomProperty(Map<String, String> customProperty) {
|
||||||
|
this.customProperty = customProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCustomProperty(String key, String value) {
|
||||||
|
customProperty.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
public void setOwnership(String ownership) {
|
public void setOwnership(String ownership) {
|
||||||
this.ownership = ownership;
|
this.ownership = ownership;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
||||||
@ -92,14 +93,40 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
"d.DEVICE_IDENTIFICATION, " +
|
"d.DEVICE_IDENTIFICATION, " +
|
||||||
"t.NAME AS DEVICE_TYPE ";
|
"t.NAME AS DEVICE_TYPE ";
|
||||||
|
|
||||||
if (serial != null) {
|
//Filter by serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_INFO i " +
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
"WHERE DEVICE_TYPE_ID = t.ID " +
|
sql = sql +
|
||||||
"AND d.ID= i.DEVICE_ID " +
|
"FROM DM_DEVICE d " +
|
||||||
"AND i.KEY_FIELD = 'serial' " +
|
"INNER JOIN DM_DEVICE_TYPE t ON d.DEVICE_TYPE_ID = t.ID " +
|
||||||
"AND i.VALUE_FIELD LIKE ? " +
|
"WHERE ";
|
||||||
"AND d.TENANT_ID = ? ";
|
if (serial != null) {
|
||||||
isSerialProvided = true;
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
boolean firstCondition = true;
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
if (!firstCondition) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
firstCondition = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sql += "AND d.TENANT_ID = ? ";
|
||||||
} else {
|
} else {
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
||||||
}
|
}
|
||||||
@ -143,6 +170,11 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
if (isSerialProvided) {
|
if (isSerialProvided) {
|
||||||
stmt.setString(paramIdx++, "%" + serial + "%");
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
}
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, tenantId);
|
stmt.setInt(paramIdx++, tenantId);
|
||||||
if (isSinceProvided) {
|
if (isSinceProvided) {
|
||||||
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
|
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
|
||||||
@ -624,6 +656,8 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
boolean isStatusProvided = false;
|
boolean isStatusProvided = false;
|
||||||
Date since = request.getSince();
|
Date since = request.getSince();
|
||||||
boolean isSinceProvided = false;
|
boolean isSinceProvided = false;
|
||||||
|
String serial = request.getSerialNumber();
|
||||||
|
boolean isSerialProvided = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Connection conn = getConnection();
|
Connection conn = getConnection();
|
||||||
@ -692,6 +726,28 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
sql += buildStatusQuery(statusList);
|
sql += buildStatusQuery(statusList);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
//Filter Group with serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ?) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
sql = sql + " LIMIT ?,?";
|
sql = sql + " LIMIT ?,?";
|
||||||
|
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
@ -721,6 +777,14 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
stmt.setString(paramIdx++, status);
|
stmt.setString(paramIdx++, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isSerialProvided) {
|
||||||
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||||
stmt.setInt(paramIdx, request.getRowCount());
|
stmt.setInt(paramIdx, request.getRowCount());
|
||||||
|
|
||||||
@ -1250,6 +1314,17 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
query += buildStatusQuery(status);
|
query += buildStatusQuery(status);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
// Loop through custom properties and add conditions
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
query += " AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = DM_DEVICE.ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query = query + " LIMIT ?,?";
|
query = query + " LIMIT ?,?";
|
||||||
|
|
||||||
@ -1277,6 +1352,12 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
ps.setString(index++, deviceStatus);
|
ps.setString(index++, deviceStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set custom property values in the loop
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
ps.setString(index++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
ps.setInt(index++, offsetValue);
|
ps.setInt(index++, offsetValue);
|
||||||
ps.setInt(index, limitValue);
|
ps.setInt(index, limitValue);
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
||||||
@ -93,14 +94,40 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
"d.DEVICE_IDENTIFICATION, " +
|
"d.DEVICE_IDENTIFICATION, " +
|
||||||
"t.NAME AS DEVICE_TYPE ";
|
"t.NAME AS DEVICE_TYPE ";
|
||||||
|
|
||||||
if (serial != null) {
|
//Filter by serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_INFO i " +
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
"WHERE DEVICE_TYPE_ID = t.ID " +
|
sql = sql +
|
||||||
"AND d.ID= i.DEVICE_ID " +
|
"FROM DM_DEVICE d " +
|
||||||
"AND i.KEY_FIELD = 'serial' " +
|
"INNER JOIN DM_DEVICE_TYPE t ON d.DEVICE_TYPE_ID = t.ID " +
|
||||||
"AND i.VALUE_FIELD LIKE ? " +
|
"WHERE ";
|
||||||
"AND d.TENANT_ID = ? ";
|
if (serial != null) {
|
||||||
isSerialProvided = true;
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
boolean firstCondition = true;
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
if (!firstCondition) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
firstCondition = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sql += "AND d.TENANT_ID = ? ";
|
||||||
} else {
|
} else {
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
||||||
}
|
}
|
||||||
@ -144,6 +171,11 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
if (isSerialProvided) {
|
if (isSerialProvided) {
|
||||||
stmt.setString(paramIdx++, "%" + serial + "%");
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
}
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, tenantId);
|
stmt.setInt(paramIdx++, tenantId);
|
||||||
if (isSinceProvided) {
|
if (isSinceProvided) {
|
||||||
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
|
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
|
||||||
@ -454,6 +486,8 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
boolean isStatusProvided = false;
|
boolean isStatusProvided = false;
|
||||||
Date since = request.getSince();
|
Date since = request.getSince();
|
||||||
boolean isSinceProvided = false;
|
boolean isSinceProvided = false;
|
||||||
|
String serial = request.getSerialNumber();
|
||||||
|
boolean isSerialProvided = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conn = getConnection();
|
conn = getConnection();
|
||||||
@ -522,6 +556,28 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
sql += buildStatusQuery(statusList);
|
sql += buildStatusQuery(statusList);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
//Filter Group with serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ?) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||||
|
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
@ -551,6 +607,14 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
stmt.setString(paramIdx++, status);
|
stmt.setString(paramIdx++, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isSerialProvided) {
|
||||||
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||||
stmt.setInt(paramIdx, request.getRowCount());
|
stmt.setInt(paramIdx, request.getRowCount());
|
||||||
|
|
||||||
@ -1035,6 +1099,17 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
query += buildStatusQuery(status);
|
query += buildStatusQuery(status);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
// Loop through custom properties and add conditions
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
query += " AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = DM_DEVICE.ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query = query + " ORDER BY DM_DEVICE.ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
query = query + " ORDER BY DM_DEVICE.ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||||
|
|
||||||
@ -1059,6 +1134,12 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
ps.setString(index++, deviceStatus);
|
ps.setString(index++, deviceStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set custom property values in the loop
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
ps.setString(index++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
ps.setInt(index++, offsetValue);
|
ps.setInt(index++, offsetValue);
|
||||||
ps.setInt(index, limitValue);
|
ps.setInt(index, limitValue);
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
||||||
@ -92,14 +93,40 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
"d.DEVICE_IDENTIFICATION, " +
|
"d.DEVICE_IDENTIFICATION, " +
|
||||||
"t.NAME AS DEVICE_TYPE ";
|
"t.NAME AS DEVICE_TYPE ";
|
||||||
|
|
||||||
if (serial != null) {
|
//Filter by serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_INFO i " +
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
"WHERE DEVICE_TYPE_ID = t.ID " +
|
sql = sql +
|
||||||
"AND d.ID= i.DEVICE_ID " +
|
"FROM DM_DEVICE d " +
|
||||||
"AND i.KEY_FIELD = 'serial' " +
|
"INNER JOIN DM_DEVICE_TYPE t ON d.DEVICE_TYPE_ID = t.ID " +
|
||||||
"AND i.VALUE_FIELD LIKE ? " +
|
"WHERE ";
|
||||||
"AND d.TENANT_ID = ? ";
|
if (serial != null) {
|
||||||
isSerialProvided = true;
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
boolean firstCondition = true;
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
if (!firstCondition) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
firstCondition = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sql += "AND d.TENANT_ID = ? ";
|
||||||
} else {
|
} else {
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
||||||
}
|
}
|
||||||
@ -138,6 +165,11 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
if (isSerialProvided) {
|
if (isSerialProvided) {
|
||||||
stmt.setString(paramIdx++, "%" + serial + "%");
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
}
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, tenantId);
|
stmt.setInt(paramIdx++, tenantId);
|
||||||
if (isDeviceTypeProvided) {
|
if (isDeviceTypeProvided) {
|
||||||
stmt.setString(paramIdx++, deviceType);
|
stmt.setString(paramIdx++, deviceType);
|
||||||
@ -435,6 +467,8 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
boolean isStatusProvided = false;
|
boolean isStatusProvided = false;
|
||||||
Date since = request.getSince();
|
Date since = request.getSince();
|
||||||
boolean isSinceProvided = false;
|
boolean isSinceProvided = false;
|
||||||
|
String serial = request.getSerialNumber();
|
||||||
|
boolean isSerialProvided = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conn = getConnection();
|
conn = getConnection();
|
||||||
@ -502,6 +536,28 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
sql += buildStatusQuery(statusList);
|
sql += buildStatusQuery(statusList);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
//Filter Group with serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ?) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
sql = sql + " LIMIT ? OFFSET ?";
|
sql = sql + " LIMIT ? OFFSET ?";
|
||||||
|
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
@ -531,6 +587,14 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
stmt.setString(paramIdx++, status);
|
stmt.setString(paramIdx++, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isSerialProvided) {
|
||||||
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, request.getRowCount());
|
stmt.setInt(paramIdx++, request.getRowCount());
|
||||||
stmt.setInt(paramIdx, request.getStartIndex());
|
stmt.setInt(paramIdx, request.getStartIndex());
|
||||||
|
|
||||||
@ -1014,6 +1078,17 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
query += buildStatusQuery(status);
|
query += buildStatusQuery(status);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
// Loop through custom properties and add conditions
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
query += " AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = DM_DEVICE.ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query = query + " LIMIT ? OFFSET ?";
|
query = query + " LIMIT ? OFFSET ?";
|
||||||
|
|
||||||
@ -1038,6 +1113,12 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
ps.setString(index++, deviceStatus);
|
ps.setString(index++, deviceStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set custom property values in the loop
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
ps.setString(index++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
ps.setInt(index++, offsetValue);
|
ps.setInt(index++, offsetValue);
|
||||||
ps.setInt(index, limitValue);
|
ps.setInt(index, limitValue);
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
* This class holds the generic implementation of DeviceDAO which can be used to support ANSI db syntax.
|
||||||
@ -94,14 +95,40 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
"d.DEVICE_IDENTIFICATION, " +
|
"d.DEVICE_IDENTIFICATION, " +
|
||||||
"t.NAME AS DEVICE_TYPE ";
|
"t.NAME AS DEVICE_TYPE ";
|
||||||
|
|
||||||
if (serial != null) {
|
//Filter by serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t, DM_DEVICE_INFO i " +
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
"WHERE DEVICE_TYPE_ID = t.ID " +
|
sql = sql +
|
||||||
"AND d.ID= i.DEVICE_ID " +
|
"FROM DM_DEVICE d " +
|
||||||
"AND i.KEY_FIELD = 'serial' " +
|
"INNER JOIN DM_DEVICE_TYPE t ON d.DEVICE_TYPE_ID = t.ID " +
|
||||||
"AND i.VALUE_FIELD LIKE ? " +
|
"WHERE ";
|
||||||
"AND d.TENANT_ID = ? ";
|
if (serial != null) {
|
||||||
isSerialProvided = true;
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
boolean firstCondition = true;
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
if (!firstCondition) {
|
||||||
|
sql += "AND ";
|
||||||
|
}
|
||||||
|
sql += "EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d.ID " +
|
||||||
|
"AND di.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ? ) ";
|
||||||
|
firstCondition = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sql += "AND d.TENANT_ID = ? ";
|
||||||
} else {
|
} else {
|
||||||
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
sql = sql + "FROM DM_DEVICE d, DM_DEVICE_TYPE t WHERE DEVICE_TYPE_ID = t.ID AND d.TENANT_ID = ? ";
|
||||||
}
|
}
|
||||||
@ -145,6 +172,11 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
if (isSerialProvided) {
|
if (isSerialProvided) {
|
||||||
stmt.setString(paramIdx++, "%" + serial + "%");
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
}
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, tenantId);
|
stmt.setInt(paramIdx++, tenantId);
|
||||||
if (isSinceProvided) {
|
if (isSinceProvided) {
|
||||||
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
|
stmt.setTimestamp(paramIdx++, new Timestamp(since.getTime()));
|
||||||
@ -455,6 +487,8 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
boolean isStatusProvided = false;
|
boolean isStatusProvided = false;
|
||||||
Date since = request.getSince();
|
Date since = request.getSince();
|
||||||
boolean isSinceProvided = false;
|
boolean isSinceProvided = false;
|
||||||
|
String serial = request.getSerialNumber();
|
||||||
|
boolean isSerialProvided = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conn = getConnection();
|
conn = getConnection();
|
||||||
@ -522,6 +556,28 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
sql += buildStatusQuery(statusList);
|
sql += buildStatusQuery(statusList);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
//Filter Group with serial number or any Custom Property in DM_DEVICE_INFO
|
||||||
|
if (serial != null || !request.getCustomProperty().isEmpty()) {
|
||||||
|
if (serial != null) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di " +
|
||||||
|
"WHERE di.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di.KEY_FIELD = 'serial' " +
|
||||||
|
"AND di.VALUE_FIELD LIKE ?) ";
|
||||||
|
isSerialProvided = true;
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
sql += "AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = d1.DEVICE_ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||||
|
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
@ -551,6 +607,14 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
stmt.setString(paramIdx++, status);
|
stmt.setString(paramIdx++, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isSerialProvided) {
|
||||||
|
stmt.setString(paramIdx++, "%" + serial + "%");
|
||||||
|
}
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||||
stmt.setInt(paramIdx, request.getRowCount());
|
stmt.setInt(paramIdx, request.getRowCount());
|
||||||
|
|
||||||
@ -883,6 +947,17 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
query += buildStatusQuery(status);
|
query += buildStatusQuery(status);
|
||||||
isStatusProvided = true;
|
isStatusProvided = true;
|
||||||
}
|
}
|
||||||
|
// Loop through custom properties and add conditions
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
query += " AND EXISTS (" +
|
||||||
|
"SELECT VALUE_FIELD " +
|
||||||
|
"FROM DM_DEVICE_INFO di2 " +
|
||||||
|
"WHERE di2.DEVICE_ID = DM_DEVICE.ID " +
|
||||||
|
"AND di2.KEY_FIELD = '" + entry.getKey() + "' " +
|
||||||
|
"AND di2.VALUE_FIELD LIKE ?)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query = query + " ORDER BY DM_DEVICE.ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
query = query + " ORDER BY DM_DEVICE.ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||||
|
|
||||||
@ -907,6 +982,12 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
|||||||
ps.setString(index++, deviceStatus);
|
ps.setString(index++, deviceStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set custom property values in the loop
|
||||||
|
if (!request.getCustomProperty().isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
|
||||||
|
ps.setString(index++, "%" + entry.getValue() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
ps.setInt(index++, offsetValue);
|
ps.setInt(index++, offsetValue);
|
||||||
ps.setInt(index, limitValue);
|
ps.setInt(index, limitValue);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user