Add time check (#63)
Some checks failed
Deploy Docker Image / build-and-deploy (push) Has been cancelled

This commit is contained in:
struga 2024-09-20 16:30:37 +03:00 committed by GitHub
parent 2071f1b6e0
commit 572ff3bd71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 115 additions and 43 deletions

View File

@ -16,6 +16,7 @@ public class AllHookTablesRow {
private String pubKey;
private boolean enabled;
private double availability;
private String createdAt;
private WebhookAdditionalFilter webhookAdditionalFilter;
}

View File

@ -21,6 +21,9 @@ import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
@ -37,6 +40,7 @@ public class HookDaoImpl implements HookDao {
rs.getString("pub_key"),
rs.getBoolean("enabled"),
rs.getDouble("availability"),
rs.getString("created_at"),
new WebhookAdditionalFilter(EventType.valueOf(rs.getString("event_type")),
rs.getString("invoice_shop_id"),
rs.getString("invoice_status"),
@ -57,6 +61,7 @@ public class HookDaoImpl implements HookDao {
" w.enabled, " +
" w.topic, " +
" w.availability, " +
" w.created_at, " +
" k.pub_key, " +
" wte.hook_id, " +
" wte.event_type, " +
@ -174,6 +179,7 @@ public class HookDaoImpl implements HookDao {
hook.setPubKey(allHookTablesRow.getPubKey());
hook.setEnabled(allHookTablesRow.isEnabled());
hook.setAvailability(allHookTablesRow.getAvailability());
hook.setCreatedAt(allHookTablesRow.getCreatedAt());
hook.setFilters(rows.stream()
.map(AllHookTablesRow::getWebhookAdditionalFilter)
.collect(Collectors.toSet()));
@ -192,6 +198,7 @@ public class HookDaoImpl implements HookDao {
" w.enabled, " +
" w.topic, " +
" w.availability, " +
" w.created_at, " +
" k.pub_key, " +
" wte.hook_id, " +
" wte.event_type, " +
@ -228,14 +235,16 @@ public class HookDaoImpl implements HookDao {
String pubKey = createOrGetPubKey(hook.getPartyId());
hook.setPubKey(pubKey);
hook.setEnabled(true);
final String sql = "INSERT INTO hook.webhook(party_id, url, topic) " +
"VALUES (:party_id, :url, CAST(:topic as hook.message_topic)) RETURNING ID";
final String sql = "INSERT INTO hook.webhook(party_id, url, topic, created_at) " +
"VALUES (:party_id, :url, CAST(:topic as hook.message_topic), :created_at) RETURNING ID";
MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("party_id", hook.getPartyId())
.addValue("url", hook.getUrl())
.addValue("topic", hook.getTopic());
.addValue("topic", hook.getTopic())
.addValue("created_at", new Timestamp(LocalDateTime.now()
.toInstant(ZoneOffset.UTC).toEpochMilli()))
;
try {
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
int updateCount = jdbcTemplate.update(sql, params, keyHolder);

View File

@ -47,21 +47,21 @@ public class InvoicingDaoImpl implements InvoicingMessageDao {
"RETURNING id";
MapSqlParameterSource sqlParameterSources = new MapSqlParameterSource()
.addValue(InvoicingRowMapper.EVENT_TIME, message.getEventTime())
.addValue(InvoicingRowMapper.SEQUENCE_ID, message.getSequenceId())
.addValue(InvoicingRowMapper.CHANGE_ID, message.getChangeId())
.addValue(InvoicingRowMapper.TYPE, message.getType().getValue())
.addValue(InvoicingRowMapper.PARTY_ID, message.getPartyId())
.addValue(InvoicingRowMapper.EVENT_TYPE, message.getEventType().toString())
.addValue(InvoicingRowMapper.INVOICE_ID, message.getSourceId())
.addValue(InvoicingRowMapper.SHOP_ID, message.getShopId())
.addValue(InvoicingRowMapper.INVOICE_STATUS, message.getInvoiceStatus().getValue())
.addValue(InvoicingRowMapper.PAYMENT_ID, message.getPaymentId())
.addValue(InvoicingRowMapper.PAYMENT_STATUS,
message.getPaymentStatus() != null ? message.getPaymentStatus().getValue() : null)
.addValue(InvoicingRowMapper.REFUND_ID, message.getRefundId())
.addValue(InvoicingRowMapper.REFUND_STATUS,
message.getRefundStatus() != null ? message.getRefundStatus().getValue() : null);
.addValue(InvoicingRowMapper.EVENT_TIME, message.getEventTime())
.addValue(InvoicingRowMapper.SEQUENCE_ID, message.getSequenceId())
.addValue(InvoicingRowMapper.CHANGE_ID, message.getChangeId())
.addValue(InvoicingRowMapper.TYPE, message.getType().getValue())
.addValue(InvoicingRowMapper.PARTY_ID, message.getPartyId())
.addValue(InvoicingRowMapper.EVENT_TYPE, message.getEventType().toString())
.addValue(InvoicingRowMapper.INVOICE_ID, message.getSourceId())
.addValue(InvoicingRowMapper.SHOP_ID, message.getShopId())
.addValue(InvoicingRowMapper.INVOICE_STATUS, message.getInvoiceStatus().getValue())
.addValue(InvoicingRowMapper.PAYMENT_ID, message.getPaymentId())
.addValue(InvoicingRowMapper.PAYMENT_STATUS,
message.getPaymentStatus() != null ? message.getPaymentStatus().getValue() : null)
.addValue(InvoicingRowMapper.REFUND_ID, message.getRefundId())
.addValue(InvoicingRowMapper.REFUND_STATUS,
message.getRefundStatus() != null ? message.getRefundStatus().getValue() : null);
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(sql, sqlParameterSources, keyHolder);
return keyHolder.getKey() == null ? null : keyHolder.getKey().longValue();
@ -91,7 +91,7 @@ public class InvoicingDaoImpl implements InvoicingMessageDao {
@Override
public List<WebhookMessageModel<InvoicingMessage>> getWebhookModels(Long messageId) {
final String sql = "select m.*, w.id as hook_id, w.url, pk.priv_key" +
final String sql = "select m.*, w.id as hook_id, w.url, pk.priv_key" +
" from hook.message m" +
" join hook.webhook w on m.party_id = w.party_id " +
" and w.enabled and w.topic=CAST(:message_type as hook.message_topic)" +
@ -111,12 +111,14 @@ public class InvoicingDaoImpl implements InvoicingMessageDao {
@Override
public Long getParentId(Long hookId, String invoiceId, Long messageId) {
final String sql = "select m.id" +
log.info("hookId: {}, invoiceId: {}, messageId: {}", hookId, invoiceId, messageId);
final String sql = "select m.id" +
" from hook.message m " +
" join hook.webhook w on w.id=:hook_id" +
" join hook.webhook_to_events wte on wte.hook_id = w.id" +
" where m.invoice_id =:invoice_id" +
" and m.id <:id " +
" and m.event_time::timestamp >= w.created_at" +
" and m.event_type = wte.event_type " +
" and (m.shop_id = wte.invoice_shop_id or wte.invoice_shop_id is null) " +
" and (m.invoice_status = wte.invoice_status or wte.invoice_status is null) " +

View File

@ -23,4 +23,5 @@ public class Hook {
private String privKey;
private boolean enabled;
private double availability;
private String createdAt;
}

View File

@ -2,13 +2,15 @@ package dev.vality.hooker.model;
import dev.vality.hooker.model.interaction.UserInteraction;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.beans.BeanUtils;
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Data
@ToString
@ToString(callSuper = true)
public class InvoicingMessage extends Message {
private InvoicingMessageEnum type;

View File

@ -2,9 +2,11 @@ package dev.vality.hooker.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Message {
private Long id;
private Long sequenceId;

View File

@ -0,0 +1,5 @@
ALTER TABLE hook.webhook ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
UPDATE hook.webhook SET created_at = NOW() - INTERVAL '2 DAYS';
ALTER TABLE hook.webhook_to_events ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
UPDATE hook.webhook_to_events SET created_at = NOW() - INTERVAL '2 DAYS';

View File

@ -5,6 +5,7 @@ import dev.vality.hooker.dao.impl.InvoicingDaoImpl;
import dev.vality.hooker.model.*;
import dev.vality.hooker.utils.BuildUtils;
import dev.vality.swag_webhook_events.model.Event;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -14,6 +15,7 @@ import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@Slf4j
@PostgresqlSpringBootITest
public class InvoicingDaoImplTest {
@ -37,27 +39,14 @@ public class InvoicingDaoImplTest {
private Hook hook;
@BeforeEach
public void setUp() {
hook = Hook.builder()
.partyId(partyId)
.topic(Event.TopicEnum.INVOICESTOPIC.getValue())
.url("zzz")
.filters(Set.of(
WebhookAdditionalFilter.builder()
.eventType(EventType.INVOICE_CREATED)
.build(),
WebhookAdditionalFilter.builder()
.eventType(EventType.INVOICE_PAYMENT_STATUS_CHANGED)
.invoicePaymentStatus("processed")
.build(),
WebhookAdditionalFilter.builder()
.eventType(EventType.INVOICE_PAYMENT_STATUS_CHANGED)
.invoicePaymentStatus("captured")
.build()
))
.build();
public void setUp() throws InterruptedException {
hook = createHookModel();
hook = hookDao.create(hook);
log.info("hookOld: {}", hookDao.getHookById(hook.getId()));
Thread.sleep(1000L); // Sleep for lag between create hook and events
hookDao.create(hook);
messageIdOne = messageDao.save(BuildUtils.buildMessage(InvoicingMessageEnum.INVOICE.getValue(),
invoiceOne, partyId, EventType.INVOICE_CREATED,
InvoiceStatusEnum.UNPAID, null));
@ -75,6 +64,27 @@ public class InvoicingDaoImplTest {
InvoiceStatusEnum.PAID, null));
}
private Hook createHookModel() {
return Hook.builder()
.partyId(partyId)
.topic(Event.TopicEnum.INVOICESTOPIC.getValue())
.url("zzz")
.filters(Set.of(
WebhookAdditionalFilter.builder()
.eventType(EventType.INVOICE_CREATED)
.build(),
WebhookAdditionalFilter.builder()
.eventType(EventType.INVOICE_PAYMENT_STATUS_CHANGED)
.invoicePaymentStatus("processed")
.build(),
WebhookAdditionalFilter.builder()
.eventType(EventType.INVOICE_PAYMENT_STATUS_CHANGED)
.invoicePaymentStatus("captured")
.build()
))
.build();
}
@Test
public void testGetInvoicingMessage() {
InvoicingMessage messageOne = messageDao.getInvoicingMessage(
@ -153,4 +163,39 @@ public class InvoicingDaoImplTest {
Long parentEventIdThree = messageDao.getParentId(hook.getId(), invoiceThree, messageIdThree);
assertEquals(-1, parentEventIdThree);
}
@Test
public void testGetParentEventIdWithOldHook() throws InterruptedException {
Hook hookOld = hookDao.create(createHookModel());
log.info("hookOld: {}", hookDao.getHookById(hookOld.getId()));
Thread.sleep(1000L); // Sleep for lag between create hook and events
String newInvoiceId = "new_invoice";
var oldMessageId = messageDao.save(BuildUtils.buildMessage(InvoicingMessageEnum.INVOICE.getValue(),
newInvoiceId, partyId, EventType.INVOICE_CREATED,
InvoiceStatusEnum.UNPAID, null, 1L, 1));
Long parentEventId = messageDao.getParentId(hookOld.getId(), newInvoiceId, oldMessageId);
assertEquals(-1, parentEventId);
hookDao.delete(hookOld.getId());
log.info("hookOld: {}", hookDao.getHookById(hookOld.getId()));
Thread.sleep(2000L);
Hook hookModel = createHookModel();
hookModel.setCreatedAt(null);
Hook hookNew = hookDao.create(hookModel);
log.info("hookNew: {}", hookDao.getHookById(hookNew.getId()));
Thread.sleep(1000L);
var newMessageId = messageDao.save(BuildUtils.buildMessage(InvoicingMessageEnum.PAYMENT.getValue(),
newInvoiceId, partyId, EventType.INVOICE_PAYMENT_STATUS_CHANGED,
InvoiceStatusEnum.PAID, PaymentStatusEnum.CAPTURED, 1L, 2));
parentEventId = messageDao.getParentId(hookNew.getId(), newInvoiceId, newMessageId);
assertEquals(-1, parentEventId);
}
}

View File

@ -12,11 +12,15 @@ import dev.vality.geck.serializer.kit.tbase.TBaseHandler;
import dev.vality.hooker.dao.WebhookAdditionalFilter;
import dev.vality.hooker.model.*;
import dev.vality.swag_webhook_events.model.Event;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
@Slf4j
public class BuildUtils {
private static int messageId = 1;
@ -29,7 +33,7 @@ public class BuildUtils {
InvoiceStatusEnum invoiceStatus, PaymentStatusEnum paymentStatus,
Long sequenceId, Integer changeId) {
InvoicingMessage message = new InvoicingMessage();
message.setEventTime("2016-03-22T06:12:27Z");
message.setEventTime(LocalDateTime.now().toInstant(ZoneOffset.UTC).toString());
message.setType(InvoicingMessageEnum.lookup(type));
message.setPartyId(partyId);
message.setEventType(eventType);
@ -47,6 +51,7 @@ public class BuildUtils {
}
message.setSequenceId(sequenceId);
message.setChangeId(changeId);
log.info("Create message: {}", message);
return message;
}