Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<fraudo.version>1.0.9</fraudo.version>
<clickhouse-jdbc.version>0.3.1</clickhouse-jdbc.version>
<fraudbusters-proto.version>1.128-79c32f2</fraudbusters-proto.version>
<fraudbusters-proto.version>1.134-b64531d</fraudbusters-proto.version>
<trusted.tokens.proto.version>1.7-6d29f86</trusted.tokens.proto.version>
<wb.list.proto.version>1.44-5dbd6d4</wb.list.proto.version>
<dgraph4j.version>21.12.0</dgraph4j.version>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.vality.fraudbusters.constant;

public interface FilterField {

String getValue();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import lombok.Getter;

@AllArgsConstructor
public enum FraudResultField {
public enum FraudResultField implements FilterField {

RESULT_STATUS("resultStatus"),
CHECKED_RULE("checkedRule"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import lombok.Getter;

@AllArgsConstructor
public enum PaymentField {
public enum PaymentField implements FilterField {

EVENT_TIME("eventTime"),
SHOP_ID("shopId"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import dev.vality.damsel.fraudbusters.Filter;
import dev.vality.damsel.fraudbusters.Page;
import dev.vality.damsel.fraudbusters.Sort;
import dev.vality.fraudbusters.constant.FilterField;
import dev.vality.fraudbusters.constant.FraudResultField;
import dev.vality.fraudbusters.constant.PaymentField;
import dev.vality.fraudbusters.constant.SortOrder;
import dev.vality.fraudbusters.service.dto.FieldType;
Expand Down Expand Up @@ -75,18 +77,24 @@ private Set<SearchFieldDto> assembleSearchFields(Filter filter) {
if (filter.isSetInvoiceId() && StringUtils.hasLength(filter.getInvoiceId())) {
addSearchField(searchFields, PaymentField.INVOICE_ID, FieldType.STRING, filter.getInvoiceId());
}
if (filter.isSetTemplate() && StringUtils.hasLength(filter.getTemplate())) {
addSearchField(searchFields, FraudResultField.CHECKED_TEMPLATE, FieldType.STRING, filter.getTemplate());
}
if (filter.isSetRule() && StringUtils.hasLength(filter.getRule())) {
addSearchField(searchFields, FraudResultField.CHECKED_RULE, FieldType.STRING, filter.getRule());
}
return searchFields;
}

private void addSearchField(Set<SearchFieldDto> searchFields,
PaymentField cardToken,
FieldType string,
String filter) {
FilterField field,
FieldType type,
String filterValue) {
searchFields.add(
SearchFieldDto.builder()
.field(cardToken)
.type(string)
.value(filter)
.field(field)
.type(type)
.value(filterValue)
.build()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void insertBatch(List<Event> events) {

@Override
public List<Event> getByFilter(FilterDto filter) {
String filters = FilterUtil.appendFilters(filter);
String filters = FilterUtil.appendFraudResultFilters(filter);
String query = FraudResultQuery.SELECT_HISTORY_FRAUD_RESULT + filters;
MapSqlParameterSource params = FilterUtil.initParams(filter);
return namedParameterJdbcTemplate.query(query, params, eventMapper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void insertBatch(List<CheckedPayment> batch) {

@Override
public List<CheckedPayment> getByFilter(FilterDto filter) {
String filters = FilterUtil.appendFilters(filter);
String filters = FilterUtil.appendPaymentFilters(filter);
String query = PaymentQuery.SELECT_HISTORY_PAYMENT + filters;
MapSqlParameterSource params = FilterUtil.initParams(filter);
return namedParameterJdbcTemplate.query(query, params, checkedPaymentMapper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FraudResultQuery {

public static final String SELECT_HISTORY_FRAUD_RESULT = String.format("""
private static final String FROM_WHERE_PARAMS_SOURCE = String.format("""
FROM
%s
WHERE
timestamp >= toDate(:from)
and timestamp <= toDate(:to)
and toDateTime(eventTime) >= toDateTime(:from)
and toDateTime(eventTime) <= toDateTime(:to)
and shopId != 'TEST'""",
EventSource.FRAUD_EVENTS_UNIQUE.getTable());

public static final String SELECT_HISTORY_FRAUD_RESULT_IDS = "SELECT id\n" + FROM_WHERE_PARAMS_SOURCE;

public static final String SELECT_HISTORY_FRAUD_RESULT = """
SELECT
eventTime,
partyId,
Expand All @@ -30,13 +43,5 @@ public class FraudResultQuery {
checkedTemplate,
mobile,
recurrent
FROM
%s
WHERE
timestamp >= toDate(:from)
and timestamp <= toDate(:to)
and toDateTime(eventTime) >= toDateTime(:from)
and toDateTime(eventTime) <= toDateTime(:to)
and shopId != 'TEST'""",
EventSource.FRAUD_EVENTS_UNIQUE.getTable());
""" + FROM_WHERE_PARAMS_SOURCE;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package dev.vality.fraudbusters.repository.clickhouse.util;


import dev.vality.fraudbusters.constant.FraudResultField;
import dev.vality.fraudbusters.constant.PaymentField;
import dev.vality.fraudbusters.constant.QueryParamName;
import dev.vality.fraudbusters.repository.clickhouse.query.FraudResultQuery;
import dev.vality.fraudbusters.service.dto.FieldType;
import dev.vality.fraudbusters.service.dto.FilterDto;
import dev.vality.fraudbusters.service.dto.SearchFieldDto;
Expand All @@ -18,11 +21,20 @@
public class FilterUtil {

public static String appendFilters(FilterDto filter) {
return appendFilters(filter, FraudResultFilterMode.NONE);
}

private static String appendFilters(FilterDto filter, FraudResultFilterMode fraudResultFilterMode) {
StringBuilder filters = new StringBuilder();
Set<SearchFieldDto> searchFields = filter.getSearchFields();
if (!CollectionUtils.isEmpty(searchFields)) {
addLikeSearchFields(filters, searchFields);
addEqualSearchFields(filters, searchFields);
if (fraudResultFilterMode == FraudResultFilterMode.DIRECT) {
addDirectFraudResultSearchFields(filters, searchFields);
} else if (fraudResultFilterMode == FraudResultFilterMode.PAYMENT_SUBQUERY) {
addPaymentFraudResultSearchFields(filters, searchFields);
}
}
String sorting = String.format(" ORDER BY (eventTime, id) %s ", filter.getSort().getOrder().name());
String limit = " LIMIT :size ";
Expand All @@ -33,9 +45,18 @@ public static String appendFilters(FilterDto filter) {
return filters.append(sorting).append(limit).toString();
}

public static String appendPaymentFilters(FilterDto filter) {
return appendFilters(filter, FraudResultFilterMode.PAYMENT_SUBQUERY);
}

public static String appendFraudResultFilters(FilterDto filter) {
return appendFilters(filter, FraudResultFilterMode.DIRECT);
}

private static void addLikeSearchFields(StringBuilder filters, Set<SearchFieldDto> searchFields) {
searchFields.stream()
.filter(searchField -> searchField.getType().equals(FieldType.STRING))
.filter(searchField -> searchField.getField() instanceof PaymentField)
.forEach(searchField ->
filters
.append(" and like(")
Expand All @@ -48,6 +69,7 @@ private static void addLikeSearchFields(StringBuilder filters, Set<SearchFieldDt
private static void addEqualSearchFields(StringBuilder filters, Set<SearchFieldDto> searchFields) {
searchFields.stream()
.filter(searchField -> searchField.getType().equals(FieldType.ENUM))
.filter(searchField -> searchField.getField() instanceof PaymentField)
.forEach(searchField ->
filters
.append(" and ")
Expand All @@ -57,6 +79,28 @@ private static void addEqualSearchFields(StringBuilder filters, Set<SearchFieldD
.append("'"));
}

private static void addPaymentFraudResultSearchFields(StringBuilder filters, Set<SearchFieldDto> searchFields) {
boolean containsFraudResultFields = searchFields.stream()
.anyMatch(searchField -> searchField.getField() instanceof FraudResultField);
if (!containsFraudResultFields) {
return;
}
filters.append(" and id in (")
.append(FraudResultQuery.SELECT_HISTORY_FRAUD_RESULT_IDS);
addDirectFraudResultSearchFields(filters, searchFields);
filters.append(")");
}

private static void addDirectFraudResultSearchFields(StringBuilder filters, Set<SearchFieldDto> searchFields) {
searchFields.stream()
.filter(searchField -> searchField.getField() instanceof FraudResultField)
.forEach(searchField -> filters
.append(" and ")
.append(searchField.getField().getValue())
.append(" = :")
.append(searchField.getField().getValue()));
}

public static MapSqlParameterSource initParams(FilterDto filter) {
MapSqlParameterSource params = new MapSqlParameterSource();
if (Objects.nonNull(filter.getLastId())) {
Expand All @@ -70,7 +114,20 @@ private static MapSqlParameterSource addTimeParams(MapSqlParameterSource params,
params.addValue(QueryParamName.FROM, filter.getTimeFrom())
.addValue(QueryParamName.TO, filter.getTimeTo())
.addValue(QueryParamName.SIZE, filter.getSize());
if (!CollectionUtils.isEmpty(filter.getSearchFields())) {
filter.getSearchFields().stream()
.filter(searchField -> searchField.getField() instanceof FraudResultField)
.forEach(searchField -> params.addValue(
searchField.getField().getValue(),
searchField.getValue()));
}
return params;
}

private enum FraudResultFilterMode {
NONE,
PAYMENT_SUBQUERY,
DIRECT
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package dev.vality.fraudbusters.service.dto;

import dev.vality.fraudbusters.constant.PaymentField;
import dev.vality.fraudbusters.constant.FilterField;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class SearchFieldDto {

private PaymentField field;
private FilterField field;
private FieldType type;
private String value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package dev.vality.fraudbusters.converter;

import dev.vality.damsel.domain.PaymentTool;
import dev.vality.damsel.fraudbusters.Payment;
import dev.vality.damsel.fraudbusters.PaymentStatus;
import dev.vality.damsel.proxy_inspector.Context;
import dev.vality.fraudbusters.domain.CheckedPayment;
import dev.vality.fraudbusters.domain.FraudRequest;
import dev.vality.fraudbusters.fraud.model.PaymentModel;
import dev.vality.fraudbusters.util.BeanUtil;
import dev.vality.fraudbusters.util.PaymentTypeByContextResolver;
import org.junit.jupiter.api.Test;

import static dev.vality.fraudbusters.constant.ClickhouseUtilsValue.UNKNOWN;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CardTokenNormalizationTest {

private final ContextToFraudRequestConverter contextConverter =
new ContextToFraudRequestConverter(new PaymentTypeByContextResolver());
private final PaymentToPaymentModelConverter historicalPaymentConverter =
new PaymentToPaymentModelConverter();
private final PaymentToCheckedPaymentConverter checkedPaymentConverter =
new PaymentToCheckedPaymentConverter(new PaymentTypeByContextResolver());

@Test
void normalizesAbsentOnlineBankCardToUnknownToken() {
Context context = BeanUtil.createContext();
context.getPayment().getPayment().getPayer().getPaymentResource()
.getResource().setPaymentTool(new PaymentTool());

FraudRequest fraudRequest = contextConverter.convert(context);

assertEquals(UNKNOWN, fraudRequest.getFraudModel().getCardToken());
}

@Test
void normalizesMissingOnlineCardTokenToUnknown() {
Context context = BeanUtil.createContext();
context.getPayment().getPayment().getPayer().getPaymentResource()
.getResource().getPaymentTool().getBankCard().unsetToken();

FraudRequest fraudRequest = contextConverter.convert(context);

assertEquals(UNKNOWN, fraudRequest.getFraudModel().getCardToken());
}

@Test
void normalizesMissingHistoricalCardTokenToUnknown() {
Payment payment = BeanUtil.createPayment(PaymentStatus.captured);
payment.getPaymentTool().getBankCard().unsetToken();

PaymentModel paymentModel = historicalPaymentConverter.convert(payment);

assertEquals(UNKNOWN, paymentModel.getCardToken());
}

@Test
void normalizesMissingStoredPaymentCardTokenToUnknown() {
Payment payment = BeanUtil.createPayment(PaymentStatus.captured);
payment.getPaymentTool().getBankCard().unsetToken();

CheckedPayment checkedPayment = checkedPaymentConverter.convert(payment);

assertEquals(UNKNOWN, checkedPayment.getCardToken());
}

@Test
void preservesPresentCardToken() {
String cardToken = "card-token";
Context context = BeanUtil.createContext();
context.getPayment().getPayment().getPayer().getPaymentResource()
.getResource().getPaymentTool().getBankCard().setToken(cardToken);

FraudRequest fraudRequest = contextConverter.convert(context);

assertEquals(cardToken, fraudRequest.getFraudModel().getCardToken());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import dev.vality.damsel.fraudbusters.Page;
import dev.vality.damsel.fraudbusters.Sort;
import dev.vality.damsel.fraudbusters.SortOrder;
import dev.vality.fraudbusters.constant.FraudResultField;
import dev.vality.fraudbusters.constant.PaymentField;
import dev.vality.fraudbusters.factory.TestObjectsFactory;
import dev.vality.fraudbusters.service.dto.FieldType;
import dev.vality.fraudbusters.service.dto.FilterDto;
import dev.vality.fraudbusters.service.dto.SearchFieldDto;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -93,7 +95,15 @@ void convert() {
.filter(searchFieldDto -> searchFieldDto.getField().equals(PaymentField.LAST_DIGITS))
.map(SearchFieldDto::getValue)
.anyMatch(value -> filter.getMaskedPan().equals(value)));
assertTrue(searchFields.stream()
.anyMatch(searchFieldDto -> searchFieldDto.getField().equals(FraudResultField.CHECKED_TEMPLATE)
&& searchFieldDto.getType().equals(FieldType.STRING)
&& filter.getTemplate().equals(searchFieldDto.getValue())));
assertTrue(searchFields.stream()
.anyMatch(searchFieldDto -> searchFieldDto.getField().equals(FraudResultField.CHECKED_RULE)
&& searchFieldDto.getType().equals(FieldType.STRING)
&& filter.getRule().equals(searchFieldDto.getValue())));
assertEquals(sort.getField(), dto.getSort().getField());
assertEquals(sort.getOrder(), SortOrder.valueOf(dto.getSort().getOrder().name()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.apache.thrift.TBase;
import org.awaitility.Awaitility;
import org.awaitility.Durations;
import org.junit.Ignore;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.ExtendWith;
import org.rnorth.ducttape.unreliables.Unreliables;
Expand Down Expand Up @@ -75,7 +74,7 @@
"dgraph.negotiationType=PLAINTEXT"
})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@Ignore
@DgraphDisabled
public abstract class DgraphAbstractIntegrationTest {

@Autowired
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/dev/vality/fraudbusters/dgraph/DgraphDisabled.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.vality.fraudbusters.dgraph;

import org.junit.jupiter.api.Disabled;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Disabled("Dgraph is no longer used")
public @interface DgraphDisabled {
}
Loading
Loading