MIFOSX-237: ensure big decimal entries are compared correctly and only transactions with changes are audited.
This commit is contained in:
+14
-10
@@ -8435,10 +8435,7 @@ Request Body:
|
|||||||
<div class="method-description">
|
<div class="method-description">
|
||||||
<h4>Delete Entry(s) in Data Table</h4>
|
<h4>Delete Entry(s) in Data Table</h4>
|
||||||
<p>
|
<p>
|
||||||
Deletes the entry (if it exists) for data tables that are one to
|
Deletes the entry (if it exists) for data tables that are one-to-one with the application table. <br> Deletes the entries (if they exist) for data tables that are one-to-many with the application table.
|
||||||
one with the application table. <br> Deletes the entries (if
|
|
||||||
they exist) for data tables that are one to many with the
|
|
||||||
application table.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="method-example">
|
<div class="method-example">
|
||||||
@@ -8446,14 +8443,17 @@ Request Body:
|
|||||||
DELETE https://DomainName/api/v1/datatables/{datatable}/{apptableId}
|
DELETE https://DomainName/api/v1/datatables/{datatable}/{apptableId}
|
||||||
</code>
|
</code>
|
||||||
<code class="method-request">
|
<code class="method-request">
|
||||||
DELETE datatables/Additional Client Fields Data/1
|
DELETE datatables/extra_client_details/1
|
||||||
|
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
Request Body:
|
Request Body:
|
||||||
{}
|
{}
|
||||||
</code>
|
</code>
|
||||||
<code class="method-response">{ "resourceId": 1 } </code>
|
<code class="method-response">
|
||||||
|
{
|
||||||
|
"resourceId": 1
|
||||||
|
}
|
||||||
|
</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -8461,7 +8461,7 @@ Request Body:
|
|||||||
class="old-syle-anchor"> </a>
|
class="old-syle-anchor"> </a>
|
||||||
<div class="method-section">
|
<div class="method-section">
|
||||||
<div class="method-description">
|
<div class="method-description">
|
||||||
<h4>Delete Entry in Data Table (One to Many)</h4>
|
<h4>Delete Entry in Datatable (One to Many)</h4>
|
||||||
<p>Deletes the entry (if it exists) for data tables that are
|
<p>Deletes the entry (if it exists) for data tables that are
|
||||||
one to many with the application table.</p>
|
one to many with the application table.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -8470,13 +8470,17 @@ Request Body:
|
|||||||
DELETE https://DomainName/api/v1/datatables/{datatable}/{apptableId}/{datatableId}
|
DELETE https://DomainName/api/v1/datatables/{datatable}/{apptableId}/{datatableId}
|
||||||
</code>
|
</code>
|
||||||
<code class="method-request">
|
<code class="method-request">
|
||||||
DELETE datatables/Extra Family Details Data/1/2
|
DELETE datatables/extra_family_details/1/2
|
||||||
|
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Request Body:
|
Request Body:
|
||||||
{}
|
{}
|
||||||
</code>
|
</code>
|
||||||
<code class="method-response">{ "resourceId": 1 } </code>
|
<code class="method-response">
|
||||||
|
{
|
||||||
|
"resourceId": 1
|
||||||
|
}
|
||||||
|
</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- end of datatables api docs -->
|
<!-- end of datatables api docs -->
|
||||||
|
|||||||
+3
-3
@@ -23,8 +23,8 @@ public class CommandWrapper {
|
|||||||
private final Long datatableId;
|
private final Long datatableId;
|
||||||
private final Long codeId;
|
private final Long codeId;
|
||||||
private final String transactionId;
|
private final String transactionId;
|
||||||
private String supportedEntityType;
|
private final String supportedEntityType;
|
||||||
private Long supportedEntityId;
|
private final Long supportedEntityId;
|
||||||
|
|
||||||
public static CommandWrapper wrap(final String actionName, final String enityName, final Long resourceId) {
|
public static CommandWrapper wrap(final String actionName, final String enityName, final Long resourceId) {
|
||||||
return new CommandWrapper(null, actionName, enityName, resourceId);
|
return new CommandWrapper(null, actionName, enityName, resourceId);
|
||||||
@@ -163,7 +163,7 @@ public class CommandWrapper {
|
|||||||
|| (isUpdateOperation() && this.entityId != null);
|
|| (isUpdateOperation() && this.entityId != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUpdateOperation() {
|
public boolean isUpdateOperation() {
|
||||||
return this.actionName.equalsIgnoreCase("UPDATE");
|
return this.actionName.equalsIgnoreCase("UPDATE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
commandSourceResult.updateJsonTo(changesOnlyJson);
|
commandSourceResult.updateJsonTo(changesOnlyJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.hasChanges() && wrapper.isUpdate()) {
|
if (!result.hasChanges() && wrapper.isUpdateOperation()) {
|
||||||
commandSourceResult.updateJsonTo(null);
|
commandSourceResult.updateJsonTo(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-9
@@ -79,7 +79,6 @@ public class DatatablesApiResource {
|
|||||||
this.readWriteNonCoreDataService.registerDatatable(datatable, apptable);
|
this.readWriteNonCoreDataService.registerDatatable(datatable, apptable);
|
||||||
|
|
||||||
final CommandProcessingResult result = new CommandProcessingResultBuilder().withResourceIdAsString(datatable).build();
|
final CommandProcessingResult result = new CommandProcessingResultBuilder().withResourceIdAsString(datatable).build();
|
||||||
|
|
||||||
return this.toApiJsonSerializer.serialize(result);
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,8 +150,10 @@ public class DatatablesApiResource {
|
|||||||
public String createDatatableEntry(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
|
public String createDatatableEntry(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
|
||||||
final String apiRequestBodyAsJson) {
|
final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createDatatable(datatable, apptableId, null)
|
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||||
.withJson(apiRequestBodyAsJson).build();
|
.createDatatable(datatable, apptableId, null) //
|
||||||
|
.withJson(apiRequestBodyAsJson) //
|
||||||
|
.build();
|
||||||
|
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
|
||||||
@@ -166,8 +167,10 @@ public class DatatablesApiResource {
|
|||||||
public String updateDatatableEntryOnetoOne(@PathParam("datatable") final String datatable,
|
public String updateDatatableEntryOnetoOne(@PathParam("datatable") final String datatable,
|
||||||
@PathParam("apptableId") final Long apptableId, final String apiRequestBodyAsJson) {
|
@PathParam("apptableId") final Long apptableId, final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDatatable(datatable, apptableId, null)
|
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||||
.withJson(apiRequestBodyAsJson).build();
|
.updateDatatable(datatable, apptableId, null) //
|
||||||
|
.withJson(apiRequestBodyAsJson) //
|
||||||
|
.build();
|
||||||
|
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
|
||||||
@@ -182,8 +185,10 @@ public class DatatablesApiResource {
|
|||||||
@PathParam("apptableId") final Long apptableId, @PathParam("datatableId") final Long datatableId,
|
@PathParam("apptableId") final Long apptableId, @PathParam("datatableId") final Long datatableId,
|
||||||
final String apiRequestBodyAsJson) {
|
final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDatatable(datatable, apptableId, datatableId)
|
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||||
.withJson(apiRequestBodyAsJson).build();
|
.updateDatatable(datatable, apptableId, datatableId) //
|
||||||
|
.withJson(apiRequestBodyAsJson) //
|
||||||
|
.build();
|
||||||
|
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
|
||||||
@@ -196,7 +201,9 @@ public class DatatablesApiResource {
|
|||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
public String deleteDatatableEntries(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId) {
|
public String deleteDatatableEntries(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId) {
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDatatable(datatable, apptableId, null).build();
|
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||||
|
.deleteDatatable(datatable, apptableId, null) //
|
||||||
|
.build();
|
||||||
|
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
|
||||||
@@ -210,7 +217,9 @@ public class DatatablesApiResource {
|
|||||||
public String deleteDatatableEntries(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
|
public String deleteDatatableEntries(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
|
||||||
@PathParam("datatableId") final Long datatableId) {
|
@PathParam("datatableId") final Long datatableId) {
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDatatable(datatable, apptableId, datatableId).build();
|
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||||
|
.deleteDatatable(datatable, apptableId, datatableId) //
|
||||||
|
.build();
|
||||||
|
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
|
||||||
|
|||||||
+25
-1
@@ -11,7 +11,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Immutable data object for generic resultset data.
|
* Immutable data object for generic resultset data.
|
||||||
*/
|
*/
|
||||||
public class GenericResultsetData {
|
public final class GenericResultsetData {
|
||||||
|
|
||||||
private final List<ResultsetColumnHeaderData> columnHeaders;
|
private final List<ResultsetColumnHeaderData> columnHeaders;
|
||||||
private final List<ResultsetRowData> data;
|
private final List<ResultsetRowData> data;
|
||||||
@@ -28,4 +28,28 @@ public class GenericResultsetData {
|
|||||||
public List<ResultsetRowData> getData() {
|
public List<ResultsetRowData> getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getColTypeOfColumnNamed(final String columnName) {
|
||||||
|
|
||||||
|
String colType = null;
|
||||||
|
for (ResultsetColumnHeaderData columnHeader : this.columnHeaders) {
|
||||||
|
if (columnHeader.isNamed(columnName)) {
|
||||||
|
colType = columnHeader.getColumnType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return colType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNoEntries() {
|
||||||
|
return this.data.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEntries() {
|
||||||
|
return !hasNoEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMoreThanOneEntry() {
|
||||||
|
return this.data.size() > 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
@@ -80,6 +80,10 @@ public final class ResultsetColumnHeaderData {
|
|||||||
this.columnDisplayType = displayType;
|
this.columnDisplayType = displayType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNamed(final String columnName) {
|
||||||
|
return this.columnName.equalsIgnoreCase(columnName);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isAnyText() {
|
private boolean isAnyText() {
|
||||||
return isText() || isTinyText() || isMediumText() || isLongText();
|
return isText() || isTinyText() || isMediumText() || isLongText();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -30,6 +30,9 @@ public class DeleteOneToOneDatatableEntryCommandHandler implements NewCommandSou
|
|||||||
|
|
||||||
this.writePlatformService.deleteDatatableEntries(command.entityName(), command.getApptableId());
|
this.writePlatformService.deleteDatatableEntries(command.entityName(), command.getApptableId());
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(command.getApptableId()).build();
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(command.getApptableId()) //
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+33
-30
@@ -242,29 +242,26 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Object> updateDatatableEntryOneToOne(final String datatable, final Long appTableId, final JsonCommand command) {
|
public Map<String, Object> updateDatatableEntryOneToOne(final String datatable, final Long appTableId, final JsonCommand command) {
|
||||||
|
|
||||||
GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, null);
|
final GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, null);
|
||||||
|
|
||||||
if (grs.getData().size() == 0) throw new DatatableNotFoundException(datatable, appTableId);
|
if (grs.hasNoEntries()) { throw new DatatableNotFoundException(datatable, appTableId); }
|
||||||
|
|
||||||
if (grs.getData().size() > 1)
|
if (grs.hasMoreThanOneEntry()) { throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update",
|
||||||
throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update", "Application Table: " + datatable
|
"Application table: " + datatable + " Foreign key id: " + appTableId); }
|
||||||
+ " Foreign Key Id: " + appTableId);
|
|
||||||
|
|
||||||
String fkName = getFKField(queryForApplicationTableName(datatable));
|
final String fkName = getFKField(queryForApplicationTableName(datatable));
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
|
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
|
||||||
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
||||||
|
|
||||||
final Map<String, Object> changes = getAffectedAndChangedColumns(grs, dataParams, fkName);
|
final Map<String, Object> changes = getAffectedAndChangedColumns(grs, dataParams, fkName);
|
||||||
|
|
||||||
if (changes.size() == 0) return changes;
|
if (!changes.isEmpty()) {
|
||||||
|
final String updateOneToOneDatatableSql = getUpdateSql(datatable, fkName, appTableId, changes);
|
||||||
|
|
||||||
final String sql = getUpdateSql(datatable, fkName, appTableId, changes);
|
if (StringUtils.isNotBlank(updateOneToOneDatatableSql)) {
|
||||||
|
this.jdbcTemplate.update(updateOneToOneDatatableSql);
|
||||||
if (StringUtils.isNotBlank(sql)) {
|
}
|
||||||
this.jdbcTemplate.update(sql);
|
|
||||||
} else {
|
|
||||||
logger.info("No Changes");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
@@ -301,9 +298,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
|
|
||||||
final String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
final String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
||||||
|
|
||||||
final String sql = getDeleteEntriesSql(datatable, getFKField(appTable), appTableId);
|
final String deleteOneToOneEntrySql = getDeleteEntriesSql(datatable, getFKField(appTable), appTableId);
|
||||||
|
|
||||||
this.jdbcTemplate.update(sql);
|
int rowsDeleted = this.jdbcTemplate.update(deleteOneToOneEntrySql);
|
||||||
|
if (rowsDeleted < 1) { throw new DatatableNotFoundException(datatable, appTableId); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -334,9 +332,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
sql = sql + "select * from `" + datatable + "` where id = " + id;
|
sql = sql + "select * from `" + datatable + "` where id = " + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order != null) sql = sql + " order by " + order;
|
if (order != null) {
|
||||||
|
sql = sql + " order by " + order;
|
||||||
|
}
|
||||||
|
|
||||||
List<ResultsetRowData> result = fillDatatableResultSetDataRows(sql);
|
final List<ResultsetRowData> result = fillDatatableResultSetDataRows(sql);
|
||||||
|
|
||||||
return new GenericResultsetData(columnHeaders, result);
|
return new GenericResultsetData(columnHeaders, result);
|
||||||
}
|
}
|
||||||
@@ -513,13 +513,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
private Map<String, Object> getAffectedAndChangedColumns(final GenericResultsetData grs, final Map<String, String> queryParams,
|
private Map<String, Object> getAffectedAndChangedColumns(final GenericResultsetData grs, final Map<String, String> queryParams,
|
||||||
final String fkName) {
|
final String fkName) {
|
||||||
|
|
||||||
Map<String, String> affectedColumns = getAffectedColumns(grs.getColumnHeaders(), queryParams, fkName);
|
final Map<String, String> affectedColumns = getAffectedColumns(grs.getColumnHeaders(), queryParams, fkName);
|
||||||
Map<String, Object> affectedAndChangedColumns = new HashMap<String, Object>();
|
final Map<String, Object> affectedAndChangedColumns = new HashMap<String, Object>();
|
||||||
String columnValue;
|
|
||||||
|
|
||||||
for (String key : affectedColumns.keySet()) {
|
for (final String key : affectedColumns.keySet()) {
|
||||||
columnValue = affectedColumns.get(key);
|
final String columnValue = affectedColumns.get(key);
|
||||||
if (columnChanged(key, columnValue, grs)) {
|
final String colType = grs.getColTypeOfColumnNamed(key);
|
||||||
|
if (columnChanged(key, columnValue, colType, grs)) {
|
||||||
affectedAndChangedColumns.put(key, columnValue);
|
affectedAndChangedColumns.put(key, columnValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,7 +527,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
return affectedAndChangedColumns;
|
return affectedAndChangedColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean columnChanged(final String key, final String keyValue, final GenericResultsetData grs) {
|
private boolean columnChanged(final String key, final String keyValue, final String colType, final GenericResultsetData grs) {
|
||||||
|
|
||||||
List<String> columnValues = grs.getData().get(0).getRow();
|
List<String> columnValues = grs.getData().get(0).getRow();
|
||||||
|
|
||||||
@@ -537,12 +537,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
if (key.equals(grs.getColumnHeaders().get(i).getColumnName())) {
|
if (key.equals(grs.getColumnHeaders().get(i).getColumnName())) {
|
||||||
columnValue = columnValues.get(i);
|
columnValue = columnValues.get(i);
|
||||||
|
|
||||||
if (notTheSame(columnValue, keyValue)) {
|
if (notTheSame(columnValue, keyValue, colType)) {
|
||||||
// logger.info("Difference - Column: " + key +
|
|
||||||
// "- Current Value: " + columnValue + " New Value: " +
|
|
||||||
// keyValue);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -691,13 +687,20 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean notTheSame(final String currValue, final String pValue) {
|
private boolean notTheSame(final String currValue, final String pValue, final String colType) {
|
||||||
if (StringUtils.isEmpty(currValue) && StringUtils.isEmpty(pValue)) return false;
|
if (StringUtils.isEmpty(currValue) && StringUtils.isEmpty(pValue)) return false;
|
||||||
|
|
||||||
if (StringUtils.isEmpty(currValue)) return true;
|
if (StringUtils.isEmpty(currValue)) return true;
|
||||||
|
|
||||||
if (StringUtils.isEmpty(pValue)) return true;
|
if (StringUtils.isEmpty(pValue)) return true;
|
||||||
|
|
||||||
|
if ("DECIMAL".equalsIgnoreCase(colType)) {
|
||||||
|
final BigDecimal currentDecimal = BigDecimal.valueOf(Double.valueOf(currValue));
|
||||||
|
final BigDecimal newDecimal = BigDecimal.valueOf(Double.valueOf(pValue));
|
||||||
|
|
||||||
|
return currentDecimal.compareTo(newDecimal) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (currValue.equals(pValue)) return false;
|
if (currValue.equals(pValue)) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user