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 @@ -11,7 +11,7 @@
<packaging>jar</packaging>

<properties>
<java.version>21</java.version>
<java.version>25</java.version>
<lombok.version>1.18.44</lombok.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
import net.hypixel.nerdbot.tickets.model.TicketFieldValue;
import net.hypixel.nerdbot.discord.util.DiscordBotEnvironment;

import net.hypixel.nerdbot.marmalade.validation.Validator;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* Primary event listener for the ticketing system.
Expand Down Expand Up @@ -177,6 +180,37 @@ public void onModalInteraction(ModalInteractionEvent event) {

if (templateOpt.isPresent()) {
TicketTemplate template = templateOpt.get();

// Validate all fields at once so the user sees every problem in one reply
Validator validator = Validator.create();
for (TicketTemplateField field : template.getFields()) {
ModalMapping mapping = event.getValue(field.getId());
String value = mapping != null ? mapping.getAsString() : "";

if (field.isRequired()) {
validator.notBlank(value, field.getLabel());
}
if (value != null && !value.isEmpty()) {
if (field.getMinLength() > 0) {
validator.minLength(value, field.getMinLength(), field.getLabel());
}
if (field.getMaxLength() > 0) {
validator.maxLength(value, field.getMaxLength(), field.getLabel());
}
}
}

if (validator.hasErrors()) {
String errorMessage = validator.getErrors().stream()
.map(e -> "- " + e.fieldName() + ": " + e.message())
.collect(Collectors.joining("\n"));
event.getHook().editOriginal("Please fix the following errors:\n" + errorMessage).queue(
null,
error -> log.error("Failed to send validation error reply to user {}", userId, error)
);
return;
}

for (TicketTemplateField field : template.getFields()) {
ModalMapping mapping = event.getValue(field.getId());
if (mapping != null && !mapping.getAsString().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import net.hypixel.nerdbot.tickets.model.Ticket;
import net.hypixel.nerdbot.tickets.model.TicketReservationResult;
import net.hypixel.nerdbot.tickets.model.TicketStatus;
import net.hypixel.nerdbot.marmalade.exception.RepositoryException;
import net.hypixel.nerdbot.marmalade.functional.Result;
import net.hypixel.nerdbot.marmalade.storage.repository.Repository;
import org.bson.Document;
import org.bson.conversions.Bson;
Expand Down Expand Up @@ -107,31 +109,38 @@ public com.mongodb.client.result.DeleteResult deleteFromDatabase(String id) {

/**
* Override findById to use integer type for ticketNumber filter.
* Checks the open ticket cache, then the closed ticket cache, then MongoDB.
*/
@Override
public Ticket findById(String id) {
public Result<Ticket, RepositoryException> findById(String id) {
Ticket cachedObject = getCache().getIfPresent(id);
if (cachedObject != null) {
log.debug("Found ticket with ID {} in cache", id);
return cachedObject;
return Result.success(cachedObject);
}

// Also check closed ticket cache
Ticket closedTicket = closedTicketCache.getIfPresent(id);
if (closedTicket != null) {
log.debug("Found ticket with ID {} in closed cache", id);
return closedTicket;
return Result.success(closedTicket);
}

// Use integer for ticketNumber filter to match MongoDB's storage type
Document document = getMongoCollection().find(Filters.eq("ticketNumber", Integer.parseInt(id))).first();
if (document != null) {
Ticket ticket = documentToEntity(document);
cacheTicketAppropriately(ticket);
return ticket;
try {
// Use integer for ticketNumber filter to match MongoDB's storage type
Document document = getMongoCollection().find(Filters.eq("ticketNumber", Integer.parseInt(id))).first();
if (document != null) {
Ticket ticket = documentToEntity(document);
cacheTicketAppropriately(ticket);
return Result.success(ticket);
}
} catch (com.mongodb.MongoException e) {
log.error("Database error looking up ticket with ID {}", id, e);
return Result.failure(new RepositoryException("Database error looking up ticket ID: " + id, e));
}

return null;
log.debug("Ticket with ID {} not found in cache or database", id);
return Result.failure(new RepositoryException("Not found: " + id));
}

/**
Expand Down Expand Up @@ -237,10 +246,13 @@ public Optional<Ticket> findByChannelId(String channelId) {
String ticketId = channelIdIndex.get(channelId);
if (ticketId != null) {
// Try open ticket cache first (most common case)
Ticket cachedTicket = findById(ticketId);
if (cachedTicket != null) {
log.debug("Found open ticket {} in cache for thread {}", cachedTicket.getFormattedTicketId(), channelId);
return Optional.of(cachedTicket);
Result<Ticket, RepositoryException> findResult = findById(ticketId);
if (findResult.isSuccess()) {
Ticket cachedTicket = findResult.orElse(null);
if (cachedTicket != null) {
log.debug("Found open ticket {} in cache for thread {}", cachedTicket.getFormattedTicketId(), channelId);
return Optional.of(cachedTicket);
}
}

// Try closed ticket cache
Expand Down
Loading