diff --git a/.env.example b/.env.example index 46ca945..87573d6 100644 --- a/.env.example +++ b/.env.example @@ -2,3 +2,7 @@ BACKEND_SERVER_PORT=8080 BACKEND_DATASOURCE_URL=jdbc:postgresql://localhost:5433/postgres BACKEND_DATASOURCE_USERNAME=postgres BACKEND_DATASOURCE_PASSWORD=postgres + +PRETIX_DEFAULT_ORGANIZER=org +PRETIX_DEFAULT_EVENT=event +PRETIX_API_KEY=OwO diff --git a/.gitignore b/.gitignore index 7448e74..6288371 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,8 @@ build/ .vscode/ ### draw.io ### -.$*.drawio.bkp \ No newline at end of file +.$*.drawio.bkp + +### Configurations ### +.env +.env.local diff --git a/application/pom.xml b/application/pom.xml index b2abb14..ada7b96 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -30,11 +30,6 @@ org.springframework.boot spring-boot-starter-jooq - - - org.springframework.boot - spring-boot-starter-data-jpa - org.springframework.boot spring-boot-starter-mail @@ -78,28 +73,6 @@ caffeine 3.1.8 - - com.github.pengrad - java-telegram-bot-api - 7.9.1 - - - - org.json - json - 20240303 - - - - org.apache.httpcomponents - httpclient - 4.5.14 - - - org.apache.httpcomponents.client5 - httpclient5 - 5.2 - org.zalando logbook-spring-boot-starter @@ -137,6 +110,7 @@ org.springframework.boot spring-boot-maven-plugin + ${spring.boot.version} diff --git a/application/src/main/java/net/furizon/backend/db/entities/pretix/Event.java b/application/src/main/java/net/furizon/backend/db/entities/pretix/Event.java deleted file mode 100644 index 7627450..0000000 --- a/application/src/main/java/net/furizon/backend/db/entities/pretix/Event.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.furizon.backend.db.entities.pretix; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import jakarta.persistence.Temporal; -import jakarta.persistence.TemporalType; -import jakarta.persistence.Transient; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; - -import java.util.Date; -import java.util.Map; -import java.util.Set; - -// TODO -> Replace on JOOQ - -@Entity -@Table(name = "events") -@Getter -@Setter -public final class Event { - @Id - @Column(name = "event_slug") - @Setter(AccessLevel.NONE) - private String slug; - - @Column(name = "event_public_url") - private String publicUrl; - - @Transient - @Setter(AccessLevel.NONE) - @Getter(AccessLevel.NONE) - private Map eventNames; - private String eventNamesRaw; //map lang -> name - - @Column(name = "event_date_from") - @Temporal(TemporalType.TIMESTAMP) - private Date dateFrom; - @Column(name = "event_date_end") - @Temporal(TemporalType.TIMESTAMP) - private Date dateEnd; - - @Column(name = "event_is_current") - private boolean isCurrentEvent; - - @OneToMany(mappedBy = "orderEvent", fetch = FetchType.LAZY) - private Set orders; -} diff --git a/application/src/main/java/net/furizon/backend/db/entities/pretix/Order.java b/application/src/main/java/net/furizon/backend/db/entities/pretix/Order.java deleted file mode 100644 index db3df87..0000000 --- a/application/src/main/java/net/furizon/backend/db/entities/pretix/Order.java +++ /dev/null @@ -1,242 +0,0 @@ -package net.furizon.backend.db.entities.pretix; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import jakarta.persistence.Transient; -import lombok.AccessLevel; -import lombok.Getter; -import net.furizon.backend.db.entities.users.User; -import net.furizon.backend.infrastructure.pretix.model.ExtraDays; -import net.furizon.backend.infrastructure.pretix.model.OrderStatus; -import net.furizon.backend.infrastructure.pretix.model.QuestionType; -import net.furizon.backend.infrastructure.pretix.model.Sponsorship; -import net.furizon.backend.service.pretix.PretixService; -import net.furizon.backend.utils.pretix.Constants; -import org.apache.http.entity.ContentType; -import org.json.JSONArray; -import org.json.JSONObject; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeoutException; - -// TODO -> Replace on JOOQ - -@Entity -@Table(name = "orders") -@Getter -public class Order { - @Id - private String code; - - private OrderStatus orderStatus; - - @Getter(AccessLevel.NONE) - private long dailyDays = 0L; //bitmask of days - - private Sponsorship sponsorship = Sponsorship.NONE; - - private ExtraDays extraDays = ExtraDays.NONE; - - private int roomCapacity = 0; // 0 = has no room - - private String hotelLocation = "ITALY"; - - private String pretixOrderSecret = "GABIBBO"; - - private boolean hasMembership = false; - - private int answersMainPositionId = -1; - - @Getter(AccessLevel.NONE) - private String answers; - - @ManyToOne - @JoinColumn(name = "user_id") - private User orderOwner; - - @ManyToOne - @JoinColumn(name = "event_id") - private Event orderEvent; - - - @Transient - @Getter(AccessLevel.NONE) - private Map answersData = null; - - private void loadAnswers(PretixService ps) { - JSONArray jsonArray = new JSONArray(answers); - Map answersData = new HashMap(); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject obj = jsonArray.getJSONObject(i); - int questionId = obj.getInt("question"); - String answerIdentifier = ps.translateQuestionId(questionId); - String value = obj.getString("answer"); - Object o = switch (ps.translateQuestionType(questionId)) { - case NUMBER -> Float.parseFloat(value); - case STRING_ONE_LINE -> value; - case STRING_MULTI_LINE -> value; - case BOOLEAN -> value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"); - case LIST_SINGLE_CHOICE -> value; - case LIST_MULTIPLE_CHOICE -> value; - case FILE -> Constants.QUESTIONS_FILE_KEEP; - case DATE -> LocalDate.parse(value); - case TIME -> LocalTime.parse(value); - case DATE_TIME -> ZonedDateTime.parse(value); - case COUNTRY_CODE -> value; - case PHONE_NUMBER -> value; - }; - answersData.put(answerIdentifier, o); - } - this.answersData = answersData; - } - - private void saveAnswers(PretixService ps) { - if (answersData == null) { - loadAnswers(ps); - } - JSONArray jsonArray = new JSONArray(); - for (String key : answersData.keySet()) { - Object o = answersData.get(key); - String out = switch (ps.translateQuestionType(key)) { - case QuestionType.NUMBER -> String.valueOf(o); - case STRING_ONE_LINE -> (String) o; - case STRING_MULTI_LINE -> (String) o; - case BOOLEAN -> ((boolean) o) ? "true" : "false"; - case LIST_SINGLE_CHOICE -> (String) o; - case LIST_MULTIPLE_CHOICE -> (String) o; - case FILE -> (String) o; - case DATE -> o.toString(); - case TIME -> o.toString(); - case DATE_TIME -> o.toString(); - case COUNTRY_CODE -> (String) o; - case PHONE_NUMBER -> (String) o; - }; - out = out.strip(); - if (!out.isEmpty()) { - jsonArray.put(out); - } - } - answers = jsonArray.toString(); - } - - public Object getAnswerValue(String answer, PretixService ps) { - if (answersData == null) { - loadAnswers(ps); - } - return answersData.get(answer); - - } - - public void setAnswerFile( - String answer, - ContentType mimeType, - String fileName, - byte[] bytes, - PretixService ps - ) throws TimeoutException { - String newAns = ps.uploadFile(mimeType, fileName, bytes); - this.setAnswerValue(answer, newAns, ps); - } - - public void setAnswerValue(String answer, Object value, PretixService ps) { - if (answersData == null) { - loadAnswers(ps); - } - answersData.put(answer, value); - saveAnswers(ps); - } - - public void removeAnswer(String answer, PretixService ps) { - if (answersData == null) { - loadAnswers(ps); - } - answersData.remove(answer); - saveAnswers(ps); - } - - public String getAnswersRaw() { - return answers; - } - - public void resetFileUploadAnswers(PretixService ps) { - //After uploading a file, we need to change it's value to "file:keep" - for (String key : answersData.keySet()) { - if (ps.translateQuestionType(key) == QuestionType.FILE) { - answersData.put(key, Constants.QUESTIONS_FILE_KEEP); - } - } - saveAnswers(ps); - } - - public boolean isDaily() { - return dailyDays != 0L; - } - - public boolean hasDay(int day) { - return (dailyDays & (1L << day)) != 0L; - } - - @Transient - @Getter(AccessLevel.NONE) - private Set dailyDaysSet = null; - - public Set getDays() { - if (dailyDaysSet == null) { - Set s = new HashSet<>(); - for (int i = 0; i < 64; i++) { - if (hasDay(i)) { - s.add(i); - } - } - dailyDaysSet = s; - } - return dailyDaysSet; - } - - public boolean ownsRoom() { - return roomCapacity > 0; - } - - public void update( - String code, - OrderStatus status, - String pretixOrderSecret, - int positionId, - Set days, - Sponsorship sponsorship, - ExtraDays extraDays, - int roomCapacity, - String hotelLocation, - boolean hasMembership, - User orderOwner, - Event orderEvent, - JSONArray answersJson - ) { - this.code = code; - this.orderStatus = status; - this.extraDays = extraDays; - this.sponsorship = sponsorship; - this.roomCapacity = roomCapacity; - this.hasMembership = hasMembership; - this.hotelLocation = hotelLocation; - this.pretixOrderSecret = pretixOrderSecret; - this.answersMainPositionId = positionId; - this.answers = answersJson.toString(); - this.answersData = null; - this.dailyDaysSet = null; - - this.dailyDays = 0L; - for (Integer day : days) { - dailyDays |= 1L << day; - } - } -} diff --git a/application/src/main/java/net/furizon/backend/db/entities/users/User.java b/application/src/main/java/net/furizon/backend/db/entities/users/User.java deleted file mode 100644 index d65879b..0000000 --- a/application/src/main/java/net/furizon/backend/db/entities/users/User.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.furizon.backend.db.entities.users; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import net.furizon.backend.db.entities.pretix.Order; - -import java.util.Set; - -// TODO -> Replace on JOOQ - -/** - * The user class represent a past, present or future attendee at the convention, - * it may be the author of published images, owner of a room or a roomie, - * owns one or more membership cards, either expired or not. - * May be linked to any orders placed in pretix. - *

- * TODO: handle nickname and fursona name problem - */ -@Entity -@Table(name = "users") -@NoArgsConstructor -@Getter -public final class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_id", nullable = false) - private long id; - - @Column(name = "user_secret", nullable = false) - private String secret; - - @Setter - @Column(name = "user_first_name") - // TODO -> nullable? - private String firstName; - - @Setter - @Column(name = "user_last_name") - // TODO -> nullable? - private String lastName; - - @Setter - @Column(name = "user_locale") - // TODO -> nullable? - private String locale = "en"; - - @OneToMany(mappedBy = "orderOwner") - // TODO -> nullable? - private Set orders; - - public User(String secret) { - this.secret = secret; - } -} diff --git a/application/src/main/java/net/furizon/backend/db/repositories/pretix/OrderRepository.java b/application/src/main/java/net/furizon/backend/db/repositories/pretix/OrderRepository.java deleted file mode 100644 index 5a3cb67..0000000 --- a/application/src/main/java/net/furizon/backend/db/repositories/pretix/OrderRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.furizon.backend.db.repositories.pretix; - -import net.furizon.backend.db.entities.pretix.Order; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.ListCrudRepository; - -import java.util.Optional; - -public interface OrderRepository extends ListCrudRepository { - @Query(value = "SELECT O FROM Order O INNER JOIN Event E on O.orderEvent = E WHERE O.code = ?1 AND E.slug = ?2") - Optional findByCodeAndEvent(String orderCode, String eventSlug); -} diff --git a/application/src/main/java/net/furizon/backend/feature/event/Event.java b/application/src/main/java/net/furizon/backend/feature/event/Event.java deleted file mode 100644 index 8bf425c..0000000 --- a/application/src/main/java/net/furizon/backend/feature/event/Event.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.furizon.backend.feature.event; - -import lombok.Builder; -import lombok.Data; -import lombok.RequiredArgsConstructor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.data.util.Pair; - -import java.net.URI; -import java.net.URISyntaxException; -import java.time.OffsetDateTime; -import java.util.Set; - -@RequiredArgsConstructor -@Data -@Builder -public class Event { - @NotNull - private final String slug; - - @Nullable - private final OffsetDateTime dateEnd; - - @Nullable - private final OffsetDateTime dateFrom; - - @Nullable - private final Boolean isCurrent; - - @Nullable - private final String publicUrl; - - @Nullable - private final Set eventNames; - - @Nullable - public Pair getOrganizerAndEventPair() { - if (publicUrl == null) { - return null; - } - - try { - URI uri = new URI(publicUrl); - - // Split the path by "/" and filter out any empty parts - String[] parts = uri.getPath().split("/"); - - if (parts.length >= 3) { - String organizer = parts[1]; // First part after base is the organizer - String eventName = parts[2]; // Second part after base is the event name - - return Pair.of(organizer, eventName); - } else { - throw new IllegalArgumentException("URL does not contain organizer and event name"); - } - } catch (URISyntaxException e) { - return null; - } - } -} diff --git a/application/src/main/java/net/furizon/backend/feature/event/finder/JooqEventFinder.java b/application/src/main/java/net/furizon/backend/feature/event/finder/JooqEventFinder.java deleted file mode 100644 index 06116bd..0000000 --- a/application/src/main/java/net/furizon/backend/feature/event/finder/JooqEventFinder.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.furizon.backend.feature.event.finder; - -import lombok.RequiredArgsConstructor; -import net.furizon.backend.feature.event.Event; -import net.furizon.backend.feature.event.mapper.JooqEventMapper; -import net.furizon.jooq.infrastructure.query.SqlQuery; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jooq.util.postgres.PostgresDSL; -import org.springframework.stereotype.Component; - -import static net.furizon.jooq.generated.Tables.EVENTS; - -@Component -@RequiredArgsConstructor -public class JooqEventFinder implements EventFinder { - public final SqlQuery query; - - @Override - public @Nullable Event findEventBySlug(@NotNull String slug) { - return query.fetchFirst( - PostgresDSL - .select( - EVENTS.EVENT_SLUG, - EVENTS.EVENT_DATE_END, - EVENTS.EVENT_DATE_FROM, - EVENTS.EVENT_IS_CURRENT, - EVENTS.EVENT_PUBLIC_URL, - EVENTS.EVENT_NAMES - ) - .from(EVENTS) - .where(EVENTS.EVENT_SLUG.eq(slug)) - ) - .mapOrNull(JooqEventMapper::map); - } -} diff --git a/application/src/main/java/net/furizon/backend/feature/event/mapper/JooqEventMapper.java b/application/src/main/java/net/furizon/backend/feature/event/mapper/JooqEventMapper.java deleted file mode 100644 index 04f5147..0000000 --- a/application/src/main/java/net/furizon/backend/feature/event/mapper/JooqEventMapper.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.furizon.backend.feature.event.mapper; - -import net.furizon.backend.feature.event.Event; -import org.jetbrains.annotations.NotNull; -import org.jooq.Record; - -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Collectors; - -import static net.furizon.jooq.generated.Tables.EVENTS; - -public class JooqEventMapper { - @NotNull - public static Event map(Record record) { - return Event.builder() - .slug(record.get(EVENTS.EVENT_SLUG)) - .dateEnd( - Optional.ofNullable(record.get(EVENTS.EVENT_DATE_END)) - .map(OffsetDateTime::parse) - .orElse(null) - ) - .dateFrom( - Optional.ofNullable(record.get(EVENTS.EVENT_DATE_FROM)) - .map(OffsetDateTime::parse) - .orElse(null) - ) - .isCurrent(record.get(EVENTS.EVENT_IS_CURRENT)) - .publicUrl(record.get(EVENTS.EVENT_PUBLIC_URL)) - .eventNames( - Optional.ofNullable(record.get(EVENTS.EVENT_NAMES)) - .map(it -> - Arrays.stream(it.split(",")).collect(Collectors.toSet()) - ) - .orElse(null) - ) - .build(); - } -} diff --git a/application/src/main/java/net/furizon/backend/feature/event/usecase/ReloadEventsUseCase.java b/application/src/main/java/net/furizon/backend/feature/event/usecase/ReloadEventsUseCase.java deleted file mode 100644 index 7ddd56a..0000000 --- a/application/src/main/java/net/furizon/backend/feature/event/usecase/ReloadEventsUseCase.java +++ /dev/null @@ -1,104 +0,0 @@ -package net.furizon.backend.feature.event.usecase; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.feature.event.Event; -import net.furizon.backend.feature.event.action.insert.InsertNewEventAction; -import net.furizon.backend.feature.event.finder.EventFinder; -import net.furizon.backend.feature.event.finder.pretix.PretixEventFinder; -import net.furizon.backend.feature.organizer.finder.OrganizersFinder; -import net.furizon.backend.infrastructure.pretix.PretixConfig; -import net.furizon.backend.infrastructure.pretix.PretixPagingUtil; -import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; -import net.furizon.backend.infrastructure.usecase.UseCase; -import net.furizon.backend.infrastructure.usecase.UseCaseInput; -import net.furizon.backend.infrastructure.web.exception.ApiException; -import org.jetbrains.annotations.NotNull; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collection; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -/** - * This use case should get all events from Pretix - * Insert it to Database if not exist there (yet) - * Returns the current event object or null if non was found - */ -@Component -@RequiredArgsConstructor -@Slf4j -public class ReloadEventsUseCase implements UseCase> { - // TODO -> Think about cache version for organizers? - private final OrganizersFinder organizersFinder; - - private final PretixEventFinder pretixEventFinder; - - private final EventFinder eventFinder; - - private final PretixConfig pretixConfig; - - private final InsertNewEventAction insertEventAction; - - @Transactional - @NotNull - @Override - public Optional executor(@NotNull UseCaseInput input) { - final var organizers = organizersFinder.getPagedOrganizers(PretixPaging.DEFAULT_PAGE).getResults(); - if (organizers == null) { - throw new ApiException("Could not get organizers from pretix"); - } - - AtomicReference currentEvent = new AtomicReference<>(null); - for (final var organizer : organizers) { - PretixPagingUtil.fetchAll( - paging -> pretixEventFinder.getPagedEvents(organizer.getSlug(), paging), - result -> { - final var events = result.getFirst(); - final var eventsName = events.stream().map(it -> it.getName().values()) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - - for (final var event : events) { - final var databaseEvent = eventFinder.findEventBySlug(event.getSlug()); - if (databaseEvent == null) { - final boolean isCurrentEvent = pretixConfig - .getDefaultOrganizer() - .equals(organizer.getSlug()) && pretixConfig - .getDefaultEvent() - .equals(event.getSlug()); - - final var newEvent = Event.builder() - .slug(event.getSlug()) - .publicUrl(event.getPublicUrl()) - .eventNames(eventsName) - .isCurrent(isCurrentEvent) - .dateEnd(event.getDateFrom()) // huh? namings in db not the same as in pretix? - .dateFrom(event.getDateTo()) // is from is start? - .build(); - - insertEventAction.invoke(newEvent); - - // in case if we won't find an existed current event - if (isCurrentEvent) { - currentEvent.set(newEvent); - } - } - - if (databaseEvent != null && Boolean.TRUE.equals(databaseEvent.getIsCurrent())) { - currentEvent.set(databaseEvent); - } - } - } - ); - } - - if (currentEvent.get() == null) { - log.warn("Could not find the current event"); - } - - return Optional.ofNullable(currentEvent.get()); - } -} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/event/Event.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/Event.java new file mode 100644 index 0000000..dcbafa8 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/Event.java @@ -0,0 +1,58 @@ +package net.furizon.backend.feature.pretix.event; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import net.furizon.backend.infrastructure.pretix.PretixGenericUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.time.OffsetDateTime; +import java.util.Map; + +@RequiredArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class Event { + @NotNull + private final String slug; + + @Nullable + private OffsetDateTime dateTo; + + @Nullable + private OffsetDateTime dateFrom; + + private boolean isCurrent; + + @NotNull + private String publicUrl; + + @Nullable + private Map eventNames; + + public static class EventBuilder { + public EventBuilder slug(String fullSlug) { + this.slug = fullSlug; + return this; + } + public EventBuilder slug(String eventSlug, String organizerSlug) { + this.slug = PretixGenericUtils.buildOrgEventSlug(eventSlug, organizerSlug); + return this; + } + } + + @Data + public static class OrganizerAndEventPair { + private final String organizer; + private final String event; + } + + @NotNull + public OrganizerAndEventPair getOrganizerAndEventPair() { + String[] sp = slug.split("/"); + return new OrganizerAndEventPair(sp[0], sp[1]); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/event/PretixEvent.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/PretixEvent.java similarity index 93% rename from application/src/main/java/net/furizon/backend/feature/event/PretixEvent.java rename to application/src/main/java/net/furizon/backend/feature/pretix/event/PretixEvent.java index 2751d09..9106a58 100644 --- a/application/src/main/java/net/furizon/backend/feature/event/PretixEvent.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/PretixEvent.java @@ -1,4 +1,4 @@ -package net.furizon.backend.feature.event; +package net.furizon.backend.feature.pretix.event; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; diff --git a/application/src/main/java/net/furizon/backend/feature/event/action/insert/InsertNewEventAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/insert/InsertNewEventAction.java similarity index 51% rename from application/src/main/java/net/furizon/backend/feature/event/action/insert/InsertNewEventAction.java rename to application/src/main/java/net/furizon/backend/feature/pretix/event/action/insert/InsertNewEventAction.java index aaef8e9..2a2f81f 100644 --- a/application/src/main/java/net/furizon/backend/feature/event/action/insert/InsertNewEventAction.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/insert/InsertNewEventAction.java @@ -1,6 +1,6 @@ -package net.furizon.backend.feature.event.action.insert; +package net.furizon.backend.feature.pretix.event.action.insert; -import net.furizon.backend.feature.event.Event; +import net.furizon.backend.feature.pretix.event.Event; import org.jetbrains.annotations.NotNull; public interface InsertNewEventAction { diff --git a/application/src/main/java/net/furizon/backend/feature/event/action/insert/JooqInsertNewEventAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/insert/JooqInsertNewEventAction.java similarity index 65% rename from application/src/main/java/net/furizon/backend/feature/event/action/insert/JooqInsertNewEventAction.java rename to application/src/main/java/net/furizon/backend/feature/pretix/event/action/insert/JooqInsertNewEventAction.java index 4515c95..af3e950 100644 --- a/application/src/main/java/net/furizon/backend/feature/event/action/insert/JooqInsertNewEventAction.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/insert/JooqInsertNewEventAction.java @@ -1,7 +1,8 @@ -package net.furizon.backend.feature.event.action.insert; +package net.furizon.backend.feature.pretix.event.action.insert; import lombok.RequiredArgsConstructor; -import net.furizon.backend.feature.event.Event; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.infrastructure.jackson.JsonSerializer; import net.furizon.jooq.infrastructure.command.SqlCommand; import org.jetbrains.annotations.NotNull; import org.jooq.util.postgres.PostgresDSL; @@ -17,6 +18,8 @@ public class JooqInsertNewEventAction implements InsertNewEventAction { private final SqlCommand command; + private final JsonSerializer jsonSerializer; + @Override public void invoke(@NotNull Event event) { command.execute( @@ -24,7 +27,7 @@ public void invoke(@NotNull Event event) { .insertInto( EVENTS, EVENTS.EVENT_SLUG, - EVENTS.EVENT_DATE_END, + EVENTS.EVENT_DATE_TO, EVENTS.EVENT_DATE_FROM, EVENTS.EVENT_IS_CURRENT, EVENTS.EVENT_PUBLIC_URL, @@ -33,15 +36,18 @@ public void invoke(@NotNull Event event) { .values( event.getSlug(), Optional - .ofNullable(event.getDateEnd()).map(OffsetDateTime::toString) + .ofNullable(event.getDateTo()) + .map(OffsetDateTime::toString) .orElse(null), Optional - .ofNullable(event.getDateFrom()).map(OffsetDateTime::toString) + .ofNullable(event.getDateFrom()) + .map(OffsetDateTime::toString) .orElse(null), - event.getIsCurrent(), + event.isCurrent(), event.getPublicUrl(), Optional - .ofNullable(event.getEventNames()).map(it -> String.join(",", it)) + .ofNullable(event.getEventNames()) + .map(jsonSerializer::serializeAsString) .orElse(null) ) ); diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/event/action/update/JooqUpdateEventAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/update/JooqUpdateEventAction.java new file mode 100644 index 0000000..732e307 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/update/JooqUpdateEventAction.java @@ -0,0 +1,45 @@ +package net.furizon.backend.feature.pretix.event.action.update; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.infrastructure.jackson.JsonSerializer; +import net.furizon.jooq.infrastructure.command.SqlCommand; +import org.jetbrains.annotations.NotNull; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import java.time.OffsetDateTime; +import java.util.Optional; + +import static net.furizon.jooq.generated.Tables.EVENTS; + +@Component +@RequiredArgsConstructor +public class JooqUpdateEventAction implements UpdateEventAction { + private final SqlCommand command; + + private final JsonSerializer jsonSerializer; + + @Override + public void invoke(@NotNull final Event event) { + command.execute( + PostgresDSL + .update(EVENTS) + .set(EVENTS.EVENT_DATE_FROM, Optional + .ofNullable(event.getDateFrom()) + .map(OffsetDateTime::toString) + .orElse(null)) + .set(EVENTS.EVENT_IS_CURRENT, event.isCurrent()) + .set(EVENTS.EVENT_PUBLIC_URL, event.getPublicUrl()) + .set(EVENTS.EVENT_NAMES, Optional + .ofNullable(event.getEventNames()) + .map(jsonSerializer::serializeAsString) + .orElse(null)) + .set(EVENTS.EVENT_DATE_TO, Optional + .ofNullable(event.getDateTo()) + .map(OffsetDateTime::toString) + .orElse(null)) + .where(EVENTS.EVENT_SLUG.eq(event.getSlug())) + ); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/event/action/update/UpdateEventAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/update/UpdateEventAction.java new file mode 100644 index 0000000..ebf4ee7 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/action/update/UpdateEventAction.java @@ -0,0 +1,8 @@ +package net.furizon.backend.feature.pretix.event.action.update; + +import net.furizon.backend.feature.pretix.event.Event; +import org.jetbrains.annotations.NotNull; + +public interface UpdateEventAction { + void invoke(@NotNull final Event event); +} diff --git a/application/src/main/java/net/furizon/backend/feature/event/finder/EventFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/EventFinder.java similarity index 62% rename from application/src/main/java/net/furizon/backend/feature/event/finder/EventFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/event/finder/EventFinder.java index 779e51d..7929408 100644 --- a/application/src/main/java/net/furizon/backend/feature/event/finder/EventFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/EventFinder.java @@ -1,6 +1,6 @@ -package net.furizon.backend.feature.event.finder; +package net.furizon.backend.feature.pretix.event.finder; -import net.furizon.backend.feature.event.Event; +import net.furizon.backend.feature.pretix.event.Event; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/JooqEventFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/JooqEventFinder.java new file mode 100644 index 0000000..33b4695 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/JooqEventFinder.java @@ -0,0 +1,37 @@ +package net.furizon.backend.feature.pretix.event.finder; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.event.mapper.JooqEventMapper; +import net.furizon.jooq.infrastructure.query.SqlQuery; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import static net.furizon.jooq.generated.Tables.EVENTS; + +@Component +@RequiredArgsConstructor +public class JooqEventFinder implements EventFinder { + private final SqlQuery query; + + private final JooqEventMapper mapper; + + @Override + public @Nullable Event findEventBySlug(@NotNull String slug) { + return query.fetchFirst( + PostgresDSL + .select( + EVENTS.EVENT_SLUG, + EVENTS.EVENT_DATE_TO, + EVENTS.EVENT_DATE_FROM, + EVENTS.EVENT_IS_CURRENT, + EVENTS.EVENT_PUBLIC_URL, + EVENTS.EVENT_NAMES + ) + .from(EVENTS) + .where(EVENTS.EVENT_SLUG.eq(slug)) + ).mapOrNull(mapper::map); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/event/finder/pretix/PretixEventFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/pretix/PretixEventFinder.java similarity index 66% rename from application/src/main/java/net/furizon/backend/feature/event/finder/pretix/PretixEventFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/event/finder/pretix/PretixEventFinder.java index 6f13855..fa60e7f 100644 --- a/application/src/main/java/net/furizon/backend/feature/event/finder/pretix/PretixEventFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/pretix/PretixEventFinder.java @@ -1,6 +1,6 @@ -package net.furizon.backend.feature.event.finder.pretix; +package net.furizon.backend.feature.pretix.event.finder.pretix; -import net.furizon.backend.feature.event.PretixEvent; +import net.furizon.backend.feature.pretix.event.PretixEvent; import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; import org.jetbrains.annotations.NotNull; diff --git a/application/src/main/java/net/furizon/backend/feature/event/finder/pretix/RestPretixEventFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/pretix/RestPretixEventFinder.java similarity index 88% rename from application/src/main/java/net/furizon/backend/feature/event/finder/pretix/RestPretixEventFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/event/finder/pretix/RestPretixEventFinder.java index 556398e..c2f02b3 100644 --- a/application/src/main/java/net/furizon/backend/feature/event/finder/pretix/RestPretixEventFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/finder/pretix/RestPretixEventFinder.java @@ -1,8 +1,8 @@ -package net.furizon.backend.feature.event.finder.pretix; +package net.furizon.backend.feature.pretix.event.finder.pretix; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.feature.event.PretixEvent; +import net.furizon.backend.feature.pretix.event.PretixEvent; import net.furizon.backend.infrastructure.http.client.HttpClient; import net.furizon.backend.infrastructure.http.client.HttpRequest; import net.furizon.backend.infrastructure.pretix.PretixConfig; @@ -21,7 +21,7 @@ @Slf4j public class RestPretixEventFinder implements PretixEventFinder { private final ParameterizedTypeReference> pretixEvents = - new ParameterizedTypeReference<>() { + new ParameterizedTypeReference<>() { }; @Qualifier("pretixHttpClient") @@ -32,7 +32,7 @@ public class RestPretixEventFinder implements PretixEventFinder { public PretixPaging getPagedEvents(@NotNull String organizer, int page) { final var request = HttpRequest.>create() .method(HttpMethod.GET) - .path("/organizers/{organizer}/events") + .path("/organizers/{organizer}/events/") .queryParam("page", String.valueOf(page)) .uriVariable("organizer", organizer) .responseParameterizedType(pretixEvents) diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/event/mapper/JooqEventMapper.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/mapper/JooqEventMapper.java new file mode 100644 index 0000000..4fff499 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/mapper/JooqEventMapper.java @@ -0,0 +1,57 @@ +package net.furizon.backend.feature.pretix.event.mapper; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jooq.Record; +import org.springframework.stereotype.Component; + +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Optional; + +import static net.furizon.jooq.generated.Tables.EVENTS; + +@Component +@RequiredArgsConstructor +@Slf4j +public class JooqEventMapper { + private final TypeReference> typeRef = new TypeReference<>() {}; + + private final ObjectMapper objectMapper; + + @NotNull + public Event map(Record record) { + return Event.builder() + .slug(record.get(EVENTS.EVENT_SLUG)) + .dateTo( + Optional.ofNullable(record.get(EVENTS.EVENT_DATE_TO)) + .map(OffsetDateTime::parse) + .orElse(null) + ) + .dateFrom( + Optional.ofNullable(record.get(EVENTS.EVENT_DATE_FROM)) + .map(OffsetDateTime::parse) + .orElse(null) + ) + .isCurrent(record.get(EVENTS.EVENT_IS_CURRENT)) + .publicUrl(record.get(EVENTS.EVENT_PUBLIC_URL)) + .eventNames( + Optional.ofNullable(record.get(EVENTS.EVENT_NAMES)) + .map(it -> { + try { + return objectMapper.readValue(it, typeRef); + } catch (JsonProcessingException e) { + log.error("Could not parse event names", e); + throw new RuntimeException(e); + } + }) + .orElse(null) + ) + .build(); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/event/usecase/ReloadEventsUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/event/usecase/ReloadEventsUseCase.java new file mode 100644 index 0000000..08ef91c --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/event/usecase/ReloadEventsUseCase.java @@ -0,0 +1,106 @@ +package net.furizon.backend.feature.pretix.event.usecase; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.event.PretixEvent; +import net.furizon.backend.feature.pretix.event.action.insert.InsertNewEventAction; +import net.furizon.backend.feature.pretix.event.action.update.UpdateEventAction; +import net.furizon.backend.feature.pretix.event.finder.EventFinder; +import net.furizon.backend.feature.pretix.event.finder.pretix.PretixEventFinder; +import net.furizon.backend.feature.pretix.organizer.PretixOrganizer; +import net.furizon.backend.feature.pretix.organizer.finder.OrganizersFinder; +import net.furizon.backend.infrastructure.pretix.PretixConfig; +import net.furizon.backend.infrastructure.pretix.PretixPagingUtil; +import net.furizon.backend.infrastructure.usecase.UseCase; +import net.furizon.backend.infrastructure.usecase.UseCaseInput; +import net.furizon.backend.infrastructure.pretix.PretixGenericUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +/** + * This use case should get all events from Pretix + * Insert it to Database if not exist there (yet) or update them + * Returns the current event object or null if non was found + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class ReloadEventsUseCase implements UseCase> { + private final OrganizersFinder organizersFinder; + private final PretixEventFinder pretixEventFinder; + private final EventFinder eventFinder; + + private final InsertNewEventAction insertEventAction; + private final UpdateEventAction updateEventAction; + + private final PretixConfig pretixConfig; + + @Transactional + @NotNull + @Override + public Optional executor(@NotNull UseCaseInput input) { + AtomicReference currentEvent = new AtomicReference<>(null); + List organizers = PretixPagingUtil.fetchAll(organizersFinder::getPagedOrganizers); + for (final PretixOrganizer organizer : organizers) { + PretixPagingUtil.forEachElement( + paging -> pretixEventFinder.getPagedEvents(organizer.getSlug(), paging), + result -> { + final PretixEvent event = result.getLeft(); + + Event dbEvent = eventFinder.findEventBySlug( + PretixGenericUtils.buildOrgEventSlug(event.getSlug(), organizer.getSlug())); + boolean isCurrentEvent = pretixConfig + .getDefaultOrganizer() + .equals(organizer.getSlug()) + && pretixConfig + .getDefaultEvent() + .equals(event.getSlug()); + + + if (dbEvent == null) { + //Create new event + Event newEvent = Event.builder() + .slug(event.getSlug(), organizer.getSlug()) + .publicUrl(event.getPublicUrl()) + .eventNames(event.getName()) + .isCurrent(isCurrentEvent) + .dateTo(event.getDateTo()) // namings in db not the same as in pretix? + .dateFrom(event.getDateFrom()) // is from is start? + .build(); + + insertEventAction.invoke(newEvent); + + // in case if we won't find an existed current event + if (isCurrentEvent) { + currentEvent.set(newEvent); + } + } else { + //Update existing event + dbEvent.setPublicUrl(event.getPublicUrl()); + dbEvent.setDateFrom(event.getDateFrom()); + dbEvent.setDateTo(event.getDateTo()); + dbEvent.setEventNames(event.getName()); + dbEvent.setCurrent(isCurrentEvent); + updateEventAction.invoke(dbEvent); + } + + if (dbEvent != null && dbEvent.isCurrent()) { + currentEvent.set(dbEvent); + } + } + ); + } + + if (currentEvent.get() == null) { + log.warn("Could not find the current event"); + } + + return Optional.ofNullable(currentEvent.get()); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/Order.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/Order.java new file mode 100644 index 0000000..f7c8434 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/Order.java @@ -0,0 +1,227 @@ +package net.furizon.backend.feature.pretix.order; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.user.User; +import net.furizon.backend.infrastructure.pretix.Const; +import net.furizon.backend.infrastructure.pretix.PretixGenericUtils; +import net.furizon.backend.infrastructure.pretix.model.ExtraDays; +import net.furizon.backend.infrastructure.pretix.model.OrderStatus; +import net.furizon.backend.infrastructure.pretix.model.Sponsorship; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + +@RequiredArgsConstructor +@AllArgsConstructor +@Data +@Builder +@Slf4j +public class Order { + @NotNull + @Setter(AccessLevel.NONE) + private final String code; + + @NotNull + private OrderStatus orderStatus; + + @Builder.Default + @NotNull + private Sponsorship sponsorship = Sponsorship.NONE; + + @Builder.Default + @NotNull + private ExtraDays extraDays = ExtraDays.NONE; + + @NotNull + private final Set dailyDays; + + @Builder.Default + private short roomCapacity = 0; // 0 = has no room + + @Nullable + private String hotelLocation; + + @NotNull + private String pretixOrderSecret; + + //Manually defining getters/setters because lombok's default names are ugly lol + @Builder.Default + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) + private boolean hasMembership = false; + + @Builder.Default + private int answersMainPositionId = -1; + + @Nullable + private User orderOwner; //TODO load from db! (lazy load?) + + @NotNull + private Event orderEvent; //TODO load from db! (lazy load?) + + @NotNull + @Setter(AccessLevel.NONE) + private Map answers; + + public boolean isDaily() { + return !dailyDays.isEmpty(); + } + + public boolean hasDay(int day) { + return dailyDays.contains(day); + } + + public boolean hasMembership() { + return hasMembership; + } + + public void setMembership(boolean membership) { + this.hasMembership = membership; + } + + @NotNull + public Optional getAnswer(String questionIdentifier) { + return Optional.ofNullable(answers.get(questionIdentifier)); + } + + public boolean hasAnswer(String questionIdentifier) { + return answers.containsKey(questionIdentifier); + } + + public boolean deleteAnswer(String questionIdentifier) { + return answers.remove(questionIdentifier) != null; + } + + public void setAnswer(String questionIdentifier, Object answer) { + if (answer instanceof String + || answer instanceof Float + || answer instanceof Boolean + || answer instanceof String[] + || answer instanceof LocalDate + || answer instanceof LocalTime + || answer instanceof ZonedDateTime) { + answers.put(questionIdentifier, answer); + } else { + throw new IllegalArgumentException("answer must be of one of the following types: " + + "String, " + + "Float, " + + "Boolean, " + + "String[], " + + "LocalDate, " + + "LocalTime, " + + "ZonedDateTime"); + } + } + + public long getDailyDaysBitmask() { + long ret = 0L; + for (int day : dailyDays) { + ret |= (1L << day); + } + return ret; + } + + public List getAllAnswers(@NotNull PretixInformation pretixInformation) { + final var list = new ArrayList(); + final var answers = getAnswers(); + for (String key : answers.keySet()) { + final var questionId = pretixInformation.getQuestionIdFromIdentifier(key); + if (questionId.isEmpty()) { + continue; + } + + int id = questionId.get(); + var type = pretixInformation.getQuestionTypeFromId(id); + if (type.isEmpty()) { + continue; + } + Object o = answers.get(key); + String out = switch (type.get()) { + case NUMBER -> Float.toString((float) o); + case STRING_ONE_LINE, FILE, COUNTRY_CODE, PHONE_NUMBER, STRING_MULTI_LINE, LIST_SINGLE_CHOICE -> + (String) o; + case BOOLEAN -> ((boolean) o) ? "True" : "False"; //fuck python + case LIST_MULTIPLE_CHOICE -> String.join(", ", (String[]) o); + case DATE, TIME -> o.toString(); + case DATE_TIME -> ((ZonedDateTime) o).format(PretixGenericUtils.PRETIX_DATETIME_FORMAT); + }; + + if (out != null && !(out = out.strip()).isEmpty()) { + list.add(new PretixAnswer(id, out)); + } + } + + return list; + } + + public static class OrderBuilder { + public OrderBuilder dailyDays(Set days) { + dailyDays = days; + return this; + } + + public OrderBuilder dailyDays(long days) { + dailyDays = new TreeSet<>(); + for (int i = 0; i < 63; i++) { + if ((days & (1L << i)) != 0L) { + dailyDays.add(i); + } + } + return this; + } + + public OrderBuilder answers(@NotNull List answers, @NotNull PretixInformation pi) { + this.answers = new HashMap<>(); + for (PretixAnswer answer : answers) { + int questionId = answer.getQuestionId(); + var identifier = pi.getQuestionIdentifierFromId(questionId); + if (identifier.isEmpty()) { + throw new IllegalArgumentException("Answer identifier is empty"); + } + + String answerIdentifier = identifier.get(); + String value = answer.getAnswer(); + if (value == null) { + throw new IllegalArgumentException("Answer " + answerIdentifier + " has null value"); + } + + var type = pi.getQuestionTypeFromId(questionId); + if (type.isPresent()) { + Object o = switch (type.get()) { + case NUMBER -> Float.parseFloat(value); + case STRING_ONE_LINE, STRING_MULTI_LINE, COUNTRY_CODE, PHONE_NUMBER, + LIST_SINGLE_CHOICE -> value; + case BOOLEAN -> value.equalsIgnoreCase("true") + || value.equalsIgnoreCase("yes"); + case LIST_MULTIPLE_CHOICE -> value.split(", "); + case FILE -> Const.QUESTIONS_FILE_KEEP; + case DATE -> LocalDate.parse(value); + case TIME -> LocalTime.parse(value); + case DATE_TIME -> ZonedDateTime.parse(value, PretixGenericUtils.PRETIX_DATETIME_FORMAT); + }; + this.answers.put(answerIdentifier, o); + } + } + return this; + } + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixAnswer.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixAnswer.java new file mode 100644 index 0000000..ec2a0f5 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixAnswer.java @@ -0,0 +1,16 @@ +package net.furizon.backend.feature.pretix.order; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.jetbrains.annotations.Nullable; + +@Data +@AllArgsConstructor +public class PretixAnswer { + @JsonProperty("question") + private final int questionId; + + @Nullable + private String answer; +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixOrder.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixOrder.java new file mode 100644 index 0000000..7fc480d --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixOrder.java @@ -0,0 +1,21 @@ +package net.furizon.backend.feature.pretix.order; + +import lombok.Data; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@Data +public class PretixOrder { + @NotNull + private final String code; + + @NotNull + private final String secret; + + @NotNull + private final String status; + + @NotNull + private final List positions; +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixPosition.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixPosition.java new file mode 100644 index 0000000..7f0019a --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/PretixPosition.java @@ -0,0 +1,22 @@ +package net.furizon.backend.feature.pretix.order; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@Data +public class PretixPosition { + @JsonProperty("item") + private final int itemId; + + @JsonProperty("id") + private final int positionId; + + @JsonProperty("variation") + private final int variationId; + + @NotNull + private final List answers; +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/deleteOrder/DeleteOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/deleteOrder/DeleteOrderAction.java new file mode 100644 index 0000000..4c74d69 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/deleteOrder/DeleteOrderAction.java @@ -0,0 +1,10 @@ +package net.furizon.backend.feature.pretix.order.action.deleteOrder; + +import net.furizon.backend.feature.pretix.order.Order; +import org.jetbrains.annotations.NotNull; + +public interface DeleteOrderAction { + void invoke(@NotNull final Order order); + + void invoke(@NotNull final String code); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/deleteOrder/JooqDeleteOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/deleteOrder/JooqDeleteOrderAction.java new file mode 100644 index 0000000..0d19b66 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/deleteOrder/JooqDeleteOrderAction.java @@ -0,0 +1,30 @@ +package net.furizon.backend.feature.pretix.order.action.deleteOrder; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.jooq.infrastructure.command.SqlCommand; +import org.jetbrains.annotations.NotNull; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import static net.furizon.jooq.generated.Tables.ORDERS; + +@Component +@RequiredArgsConstructor +public class JooqDeleteOrderAction implements DeleteOrderAction { + private final SqlCommand command; + + @Override + public void invoke(@NotNull final Order order) { + this.invoke(order.getCode()); + } + + @Override + public void invoke(@NotNull final String code) { + command.execute( + PostgresDSL + .deleteFrom(ORDERS) + .where(ORDERS.ORDER_CODE.eq(code)) + ); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/insertNewOrder/InsertNewOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/insertNewOrder/InsertNewOrderAction.java new file mode 100644 index 0000000..34c3c39 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/insertNewOrder/InsertNewOrderAction.java @@ -0,0 +1,12 @@ +package net.furizon.backend.feature.pretix.order.action.insertNewOrder; + +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; + +public interface InsertNewOrderAction { + void invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/insertNewOrder/JooqInsertNewOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/insertNewOrder/JooqInsertNewOrderAction.java new file mode 100644 index 0000000..8a2708b --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/insertNewOrder/JooqInsertNewOrderAction.java @@ -0,0 +1,61 @@ +package net.furizon.backend.feature.pretix.order.action.insertNewOrder; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.jackson.JsonSerializer; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.jooq.infrastructure.command.SqlCommand; +import org.jetbrains.annotations.NotNull; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import static net.furizon.jooq.generated.Tables.ORDERS; + +@Component +@RequiredArgsConstructor +public class JooqInsertNewOrderAction implements InsertNewOrderAction { + private final SqlCommand command; + + private final JsonSerializer jsonSerializer; + + @Override + public void invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ) { + command.execute( + PostgresDSL + .insertInto( + ORDERS, + ORDERS.ORDER_CODE, + ORDERS.ORDER_STATUS, + ORDERS.ORDER_SPONSORSHIP_TYPE, + ORDERS.ORDER_EXTRA_DAYS_TYPE, + ORDERS.ORDER_DAILY_DAYS, + ORDERS.ORDER_ROOM_CAPACITY, + ORDERS.ORDER_HOTEL_LOCATION, + ORDERS.ORDER_SECRET, + ORDERS.HAS_MEMBERSHIP, + ORDERS.ORDER_ANSWERS_MAIN_POSITION_ID, + //ORDERS.USER_ID, TODO + //ORDERS.EVENT_ID, + ORDERS.ORDER_ANSWERS_JSON + ) + .values( + order.getCode(), + (short) order.getOrderStatus().ordinal(), + (short) order.getSponsorship().ordinal(), + (short) order.getExtraDays().ordinal(), + order.getDailyDaysBitmask(), + order.getRoomCapacity(), + order.getHotelLocation(), + order.getPretixOrderSecret(), + order.hasMembership(), + order.getAnswersMainPositionId(), + //order.getOrderOwner(), + //order.getOrderEvent(), + jsonSerializer.serializeAsJson(order.getAllAnswers(pretixInformation)) + ) + ); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/pushAnswer/PushPretixAnswerAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/pushAnswer/PushPretixAnswerAction.java new file mode 100644 index 0000000..2d2535c --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/pushAnswer/PushPretixAnswerAction.java @@ -0,0 +1,12 @@ +package net.furizon.backend.feature.pretix.order.action.pushAnswer; + +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; + +public interface PushPretixAnswerAction { + boolean invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/pushAnswer/RestPushPretixAnswerAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/pushAnswer/RestPushPretixAnswerAction.java new file mode 100644 index 0000000..061feb4 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/pushAnswer/RestPushPretixAnswerAction.java @@ -0,0 +1,49 @@ +package net.furizon.backend.feature.pretix.order.action.pushAnswer; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.dto.PushPretixAnswerRequest; +import net.furizon.backend.infrastructure.http.client.HttpClient; +import net.furizon.backend.infrastructure.http.client.HttpRequest; +import net.furizon.backend.infrastructure.pretix.PretixConfig; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; + +@Component +@RequiredArgsConstructor +@Slf4j +public class RestPushPretixAnswerAction implements PushPretixAnswerAction { + @Qualifier("pretixHttpClient") + private final HttpClient pretixHttpClient; + + @Override + public boolean invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ) { + final var pair = order.getOrderEvent().getOrganizerAndEventPair(); + final var request = HttpRequest.create() + .method(HttpMethod.PATCH) + .path("/organizers/{organizer}/events/{event}/orderpositions/{position}/") + .uriVariable("organizer", pair.getOrganizer()) + .uriVariable("event", pair.getEvent()) + .uriVariable("position", String.valueOf(order.getAnswersMainPositionId())) + .contentType(MediaType.APPLICATION_JSON) + .body(new PushPretixAnswerRequest(order.getAllAnswers(pretixInformation))) + .responseType(Void.class) + .build(); + try { + return pretixHttpClient.send(PretixConfig.class, request).getStatusCode() == HttpStatus.OK; + } catch (final HttpClientErrorException ex) { + log.error("Error while sending Pretix answer to order ", ex); + return false; + } + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/updateOrder/JooqUpdateOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/updateOrder/JooqUpdateOrderAction.java new file mode 100644 index 0000000..298b8c7 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/updateOrder/JooqUpdateOrderAction.java @@ -0,0 +1,44 @@ +package net.furizon.backend.feature.pretix.order.action.updateOrder; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.jackson.JsonSerializer; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.jooq.infrastructure.command.SqlCommand; +import org.jetbrains.annotations.NotNull; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import static net.furizon.jooq.generated.Tables.ORDERS; + +@Component +@RequiredArgsConstructor +public class JooqUpdateOrderAction implements UpdateOrderAction { + private final SqlCommand command; + + private final JsonSerializer serializer; + + @Override + public void invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ) { + command.execute( + PostgresDSL + .update(ORDERS) + .set(ORDERS.ORDER_STATUS, (short) order.getOrderStatus().ordinal()) + .set(ORDERS.ORDER_SPONSORSHIP_TYPE, (short) order.getSponsorship().ordinal()) + .set(ORDERS.ORDER_EXTRA_DAYS_TYPE, (short) order.getExtraDays().ordinal()) + .set(ORDERS.ORDER_DAILY_DAYS, order.getDailyDaysBitmask()) + .set(ORDERS.ORDER_ROOM_CAPACITY, order.getRoomCapacity()) + .set(ORDERS.ORDER_HOTEL_LOCATION, order.getHotelLocation()) + .set(ORDERS.ORDER_SECRET, order.getPretixOrderSecret()) + .set(ORDERS.HAS_MEMBERSHIP, order.hasMembership()) + .set(ORDERS.ORDER_ANSWERS_MAIN_POSITION_ID, order.getAnswersMainPositionId()) + //.set(ORDERS.USER_ID, order.getOrderOwner()) + //.set(ORDERS.EVENT_ID, order.getOrderEvent()) + .set(ORDERS.ORDER_ANSWERS_JSON, serializer.serializeAsJson(order.getAllAnswers(pretixInformation))) + .where(ORDERS.ORDER_CODE.eq(order.getCode())) + ); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/updateOrder/UpdateOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/updateOrder/UpdateOrderAction.java new file mode 100644 index 0000000..837e77a --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/updateOrder/UpdateOrderAction.java @@ -0,0 +1,12 @@ +package net.furizon.backend.feature.pretix.order.action.updateOrder; + +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; + +public interface UpdateOrderAction { + void invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/upsertOrder/JooqUpsertOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/upsertOrder/JooqUpsertOrderAction.java new file mode 100644 index 0000000..4b2f2ca --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/upsertOrder/JooqUpsertOrderAction.java @@ -0,0 +1,89 @@ +package net.furizon.backend.feature.pretix.order.action.upsertOrder; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.jackson.JsonSerializer; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.jooq.infrastructure.command.SqlCommand; +import org.jetbrains.annotations.NotNull; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import static net.furizon.jooq.generated.Tables.ORDERS; + +@Component +@RequiredArgsConstructor +public class JooqUpsertOrderAction implements UpsertOrderAction { + private final SqlCommand command; + + private final JsonSerializer jsonSerializer; + + @Override + public void invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ) { + String code = order.getCode(); + short orderStatus = (short) order.getOrderStatus().ordinal(); + short sponsorship = (short) order.getSponsorship().ordinal(); + short extraDays = (short) order.getExtraDays().ordinal(); + long dailyDaysBitmask = order.getDailyDaysBitmask(); + short roomCapacity = order.getRoomCapacity(); + String hotelLocation = order.getHotelLocation(); + String orderSecret = order.getPretixOrderSecret(); + boolean membership = order.hasMembership(); + int answersMainPositionId = order.getAnswersMainPositionId(); + //User user = order.getOrderOwner(); + //Event event = order.getOrderEvent(); + final var answers = jsonSerializer.serializeAsJson(order.getAllAnswers(pretixInformation)); + + command.execute( + PostgresDSL + .insertInto( + ORDERS, + ORDERS.ORDER_CODE, + ORDERS.ORDER_STATUS, + ORDERS.ORDER_SPONSORSHIP_TYPE, + ORDERS.ORDER_EXTRA_DAYS_TYPE, + ORDERS.ORDER_DAILY_DAYS, + ORDERS.ORDER_ROOM_CAPACITY, + ORDERS.ORDER_HOTEL_LOCATION, + ORDERS.ORDER_SECRET, + ORDERS.HAS_MEMBERSHIP, + ORDERS.ORDER_ANSWERS_MAIN_POSITION_ID, + //ORDERS.USER_ID, TODO + //ORDERS.EVENT_ID, + ORDERS.ORDER_ANSWERS_JSON + ) + .values( + code, + orderStatus, + sponsorship, + extraDays, + dailyDaysBitmask, + roomCapacity, + hotelLocation, + orderSecret, + membership, + answersMainPositionId, + //user, + //event, + answers + ) + .onConflict(ORDERS.ORDER_CODE) + .doUpdate() + .set(ORDERS.ORDER_STATUS, orderStatus) + .set(ORDERS.ORDER_SPONSORSHIP_TYPE, sponsorship) + .set(ORDERS.ORDER_EXTRA_DAYS_TYPE, extraDays) + .set(ORDERS.ORDER_DAILY_DAYS, dailyDaysBitmask) + .set(ORDERS.ORDER_ROOM_CAPACITY, roomCapacity) + .set(ORDERS.ORDER_HOTEL_LOCATION, hotelLocation) + .set(ORDERS.ORDER_SECRET, orderSecret) + .set(ORDERS.HAS_MEMBERSHIP, membership) + .set(ORDERS.ORDER_ANSWERS_MAIN_POSITION_ID, answersMainPositionId) + //.set(ORDERS.USER_ID, user) + //.set(ORDERS.EVENT_ID, event) + .set(ORDERS.ORDER_ANSWERS_JSON, answers) + ); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/action/upsertOrder/UpsertOrderAction.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/upsertOrder/UpsertOrderAction.java new file mode 100644 index 0000000..672ca06 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/action/upsertOrder/UpsertOrderAction.java @@ -0,0 +1,12 @@ +package net.furizon.backend.feature.pretix.order.action.upsertOrder; + +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; + +public interface UpsertOrderAction { + void invoke( + @NotNull final Order order, + @NotNull final PretixInformation pretixInformation + ); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/controller/TestOrderController.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/controller/TestOrderController.java new file mode 100644 index 0000000..48ffb75 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/controller/TestOrderController.java @@ -0,0 +1,33 @@ +package net.furizon.backend.feature.pretix.order.controller; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.order.action.pushAnswer.PushPretixAnswerAction; +import net.furizon.backend.feature.pretix.order.finder.OrderFinder; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.backend.infrastructure.web.exception.ApiException; +import org.jetbrains.annotations.NotNull; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/internal/orders") +@RequiredArgsConstructor +public class TestOrderController { + private final PushPretixAnswerAction pushPretixAnswerAction; + + private final OrderFinder orderFinder; + + private final PretixInformation pretixService; + + @PutMapping("/{code}") + public Boolean pushAnswer(@PathVariable @NotNull String code) { + final var order = orderFinder.findOrderByCode(code); + if (order == null) { + throw new ApiException("No order found with code " + code); + } + + return pushPretixAnswerAction.invoke(order, pretixService); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/dto/PretixFileUploadResponse.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/dto/PretixFileUploadResponse.java new file mode 100644 index 0000000..38f7ded --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/dto/PretixFileUploadResponse.java @@ -0,0 +1,10 @@ +package net.furizon.backend.feature.pretix.order.dto; + +import lombok.Data; +import org.jetbrains.annotations.NotNull; + +@Data +public class PretixFileUploadResponse { + @NotNull + private final String id; +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/dto/PushPretixAnswerRequest.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/dto/PushPretixAnswerRequest.java new file mode 100644 index 0000000..acee675 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/dto/PushPretixAnswerRequest.java @@ -0,0 +1,11 @@ +package net.furizon.backend.feature.pretix.order.dto; + +import lombok.Data; +import net.furizon.backend.feature.pretix.order.PretixAnswer; + +import java.util.List; + +@Data +public class PushPretixAnswerRequest { + private final List answers; +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/JooqOrderFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/JooqOrderFinder.java new file mode 100644 index 0000000..8074c2d --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/JooqOrderFinder.java @@ -0,0 +1,54 @@ +package net.furizon.backend.feature.pretix.order.finder; + +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.mapper.JooqOrderMapper; +import net.furizon.jooq.infrastructure.query.SqlQuery; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jooq.util.postgres.PostgresDSL; +import org.springframework.stereotype.Component; + +import static net.furizon.jooq.generated.Tables.EVENTS; +import static net.furizon.jooq.generated.Tables.ORDERS; +import static net.furizon.jooq.generated.Tables.USERS; + +@Component +@RequiredArgsConstructor +public class JooqOrderFinder implements OrderFinder { + private final SqlQuery query; + + private final JooqOrderMapper orderMapper; + + @Override + public @Nullable Order findOrderByCode(@NotNull String code) { + return query.fetchFirst( + PostgresDSL.select( + ORDERS.ORDER_CODE, + ORDERS.ORDER_STATUS, + ORDERS.ORDER_SPONSORSHIP_TYPE, + ORDERS.ORDER_EXTRA_DAYS_TYPE, + ORDERS.ORDER_DAILY_DAYS, + ORDERS.ORDER_ROOM_CAPACITY, + ORDERS.ORDER_HOTEL_LOCATION, + ORDERS.ORDER_SECRET, + ORDERS.HAS_MEMBERSHIP, + ORDERS.ORDER_ANSWERS_MAIN_POSITION_ID, + ORDERS.ORDER_ANSWERS_JSON, + USERS.USER_ID, + EVENTS.EVENT_SLUG, + EVENTS.EVENT_DATE_TO, + EVENTS.EVENT_DATE_FROM, + EVENTS.EVENT_IS_CURRENT, + EVENTS.EVENT_PUBLIC_URL, + EVENTS.EVENT_NAMES + ) + .from(ORDERS) + .leftOuterJoin(USERS) + .on(USERS.USER_ID.eq(ORDERS.USER_ID)) + .leftOuterJoin(EVENTS) + .on(EVENTS.EVENT_SLUG.eq(ORDERS.EVENT_ID)) + .where(ORDERS.ORDER_CODE.eq(code)) + ).mapOrNull(orderMapper::map); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/OrderFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/OrderFinder.java new file mode 100644 index 0000000..aa2aacb --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/OrderFinder.java @@ -0,0 +1,10 @@ +package net.furizon.backend.feature.pretix.order.finder; + +import net.furizon.backend.feature.pretix.order.Order; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface OrderFinder { + @Nullable + Order findOrderByCode(@NotNull String code); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/pretix/PretixOrderFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/pretix/PretixOrderFinder.java new file mode 100644 index 0000000..8afe7db --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/pretix/PretixOrderFinder.java @@ -0,0 +1,23 @@ +package net.furizon.backend.feature.pretix.order.finder.pretix; + +import net.furizon.backend.feature.pretix.order.PretixOrder; +import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public interface PretixOrderFinder { + @NotNull + PretixPaging getPagedOrders( + @NotNull final String organizer, + @NotNull final String event, + int page + ); + + @NotNull + Optional fetchOrderByCode( + @NotNull final String organizer, + @NotNull final String event, + @NotNull final String code + ); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/pretix/RestPretixOrderFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/pretix/RestPretixOrderFinder.java new file mode 100644 index 0000000..a038fab --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/finder/pretix/RestPretixOrderFinder.java @@ -0,0 +1,76 @@ +package net.furizon.backend.feature.pretix.order.finder.pretix; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.order.PretixOrder; +import net.furizon.backend.infrastructure.http.client.HttpClient; +import net.furizon.backend.infrastructure.http.client.HttpRequest; +import net.furizon.backend.infrastructure.pretix.PretixConfig; +import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; + +import java.util.Optional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class RestPretixOrderFinder implements PretixOrderFinder { + private final ParameterizedTypeReference> pretixPagedOrder = + new ParameterizedTypeReference<>() {}; + + @Qualifier("pretixHttpClient") + private final HttpClient pretixHttpClient; + + @Override + public @NotNull PretixPaging getPagedOrders( + @NotNull final String organizer, + @NotNull final String event, + int page + ) { + final var request = HttpRequest.>create() + .method(HttpMethod.GET) + .path("/organizers/{organizer}/events/{event}/orders/") + .queryParam("page", String.valueOf(page)) + .uriVariable("organizer", organizer) + .uriVariable("event", event) + .responseParameterizedType(pretixPagedOrder) + .build(); + + try { + return Optional + .ofNullable(pretixHttpClient.send(PretixConfig.class, request).getBody()) + .orElse(PretixPaging.empty()); + } catch (final HttpClientErrorException ex) { + log.error(ex.getResponseBodyAsString()); + throw ex; + } + } + + @Override + public @NotNull Optional fetchOrderByCode( + @NotNull final String organizer, + @NotNull final String event, + @NotNull final String code + ) { + final var request = HttpRequest.create() + .method(HttpMethod.GET) + .path("/organizers/{organizer}/events/{event}/orders/{code}/") + .uriVariable("organizer", organizer) + .uriVariable("event", event) + .uriVariable("code", code) + .responseType(PretixOrder.class) + .build(); + + try { + return Optional.ofNullable(pretixHttpClient.send(PretixConfig.class, request).getBody()); + } catch (final HttpClientErrorException ex) { + log.error(ex.getResponseBodyAsString()); + throw ex; + } + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/mapper/JooqOrderMapper.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/mapper/JooqOrderMapper.java new file mode 100644 index 0000000..c85c5e3 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/mapper/JooqOrderMapper.java @@ -0,0 +1,61 @@ +package net.furizon.backend.feature.pretix.order.mapper; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import net.furizon.backend.feature.pretix.event.mapper.JooqEventMapper; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.PretixAnswer; +import net.furizon.backend.feature.user.mapper.JooqUserMapper; +import net.furizon.backend.infrastructure.pretix.model.ExtraDays; +import net.furizon.backend.infrastructure.pretix.model.OrderStatus; +import net.furizon.backend.infrastructure.pretix.model.Sponsorship; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import org.jetbrains.annotations.NotNull; +import org.jooq.Record; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static net.furizon.jooq.generated.Tables.ORDERS; +import static net.furizon.jooq.generated.Tables.USERS; + +@Component +@RequiredArgsConstructor +public class JooqOrderMapper { + private final TypeReference> pretixAnswerRef = new TypeReference<>() {}; + + private final ObjectMapper objectMapper; + + private final PretixInformation pretixInformation; + + private final JooqEventMapper jooqEventMapper; + + @NotNull + public Order map(Record record) { + try { + final var answerList = objectMapper.readValue( + record.get(ORDERS.ORDER_ANSWERS_JSON).data(), + pretixAnswerRef + ); + return Order.builder() + .code(record.get(ORDERS.ORDER_CODE)) + .orderStatus(OrderStatus.values()[record.get(ORDERS.ORDER_STATUS)]) + .sponsorship(Sponsorship.values()[record.get(ORDERS.ORDER_SPONSORSHIP_TYPE)]) + .extraDays(ExtraDays.values()[record.get(ORDERS.ORDER_EXTRA_DAYS_TYPE)]) + .dailyDays(record.get(ORDERS.ORDER_DAILY_DAYS)) + .roomCapacity(record.get(ORDERS.ORDER_ROOM_CAPACITY)) //TODO change after db regeneration + .hotelLocation(record.get(ORDERS.ORDER_HOTEL_LOCATION)) + .pretixOrderSecret(record.get(ORDERS.ORDER_SECRET)) + .hasMembership(record.get(ORDERS.HAS_MEMBERSHIP)) + .answersMainPositionId(record.get(ORDERS.ORDER_ANSWERS_MAIN_POSITION_ID)) + .orderOwner(record.get(USERS.USER_ID) != null ? JooqUserMapper.map(record) : null) + .orderEvent(jooqEventMapper.map(record)) + .answers(answerList, pretixInformation) + .build(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/FetchSingleOrderUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/FetchSingleOrderUseCase.java new file mode 100644 index 0000000..2675b71 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/FetchSingleOrderUseCase.java @@ -0,0 +1,67 @@ +package net.furizon.backend.feature.pretix.order.usecase; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.PretixOrder; +import net.furizon.backend.feature.pretix.order.action.deleteOrder.DeleteOrderAction; +import net.furizon.backend.feature.pretix.order.action.upsertOrder.UpsertOrderAction; +import net.furizon.backend.feature.pretix.order.finder.pretix.PretixOrderFinder; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.backend.infrastructure.usecase.UseCase; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class FetchSingleOrderUseCase implements UseCase> { + @NotNull + private final PretixOrderFinder pretixOrderFinder; + + @NotNull + private final UpsertOrderAction insertOrUpdateOrderAction; + + @NotNull + private final DeleteOrderAction deleteOrderAction; + + @Transactional + @NotNull + @Override + public Optional executor(@NotNull Input input) { + Event event = input.event; + String orderCode = input.code; + var eventInfo = event.getOrganizerAndEventPair(); + + Optional pretixOrder = pretixOrderFinder.fetchOrderByCode( + eventInfo.getOrganizer(), + eventInfo.getEvent(), + orderCode + ); + + if (pretixOrder.isEmpty()) { + deleteOrderAction.invoke(orderCode); + return Optional.empty(); + } + + var orderOpt = input.pretixInformation.parseOrderFromId(pretixOrder.get(), event); + if (orderOpt.isEmpty()) { + deleteOrderAction.invoke(orderCode); + return Optional.empty(); + } + + Order order = orderOpt.get(); + insertOrUpdateOrderAction.invoke(order, input.pretixInformation); + return orderOpt; + } + + public record Input( + @NotNull Event event, + @NotNull String code, + @NotNull PretixInformation pretixInformation + ) {} +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/PushAnswersToPretixUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/PushAnswersToPretixUseCase.java new file mode 100644 index 0000000..9a8cca6 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/PushAnswersToPretixUseCase.java @@ -0,0 +1,34 @@ +package net.furizon.backend.feature.pretix.order.usecase; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.action.pushAnswer.PushPretixAnswerAction; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.backend.infrastructure.usecase.UseCase; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class PushAnswersToPretixUseCase implements UseCase { + @NotNull + private final PushPretixAnswerAction pushPretixAnswerAction; + + @NotNull + @Override + public Boolean executor(@NotNull PushAnswersToPretixUseCase.Input input) { + return pushPretixAnswerAction.invoke( + input.order, + input.pretixInformation + ); + } + + public record Input( + @NotNull Event event, + @NotNull Order order, + @NotNull PretixInformation pretixInformation + ) {} +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/ReloadOrdersUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/ReloadOrdersUseCase.java new file mode 100644 index 0000000..048ddce --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/ReloadOrdersUseCase.java @@ -0,0 +1,70 @@ +package net.furizon.backend.feature.pretix.order.usecase; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.action.deleteOrder.DeleteOrderAction; +import net.furizon.backend.feature.pretix.order.action.upsertOrder.UpsertOrderAction; +import net.furizon.backend.feature.pretix.order.finder.pretix.PretixOrderFinder; +import net.furizon.backend.infrastructure.pretix.PretixPagingUtil; +import net.furizon.backend.infrastructure.pretix.model.OrderStatus; +import net.furizon.backend.infrastructure.pretix.service.PretixInformation; +import net.furizon.backend.infrastructure.usecase.UseCase; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +/** + * This use case should get all orders from Pretix + * Insert it to Database if not exist there (yet) + * Returns true on success + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class ReloadOrdersUseCase implements UseCase { + @NotNull + private final PretixOrderFinder pretixOrderFinder; + + @NotNull + private final UpsertOrderAction insertOrUpdateOrderAction; + + @NotNull + private final DeleteOrderAction deleteOrderAction; + + @Transactional + @NotNull + @Override + public Boolean executor(@NotNull Input input) { + var eventInfo = input.event.getOrganizerAndEventPair(); + + PretixPagingUtil.forEachElement( + page -> pretixOrderFinder.getPagedOrders(eventInfo.getOrganizer(), eventInfo.getEvent(), page), + pretixOrder -> { + boolean shouldDelete = true; + + var orderOpt = input.pretixInformation.parseOrderFromId(pretixOrder.getLeft(), input.event); + if (orderOpt.isPresent()) { + Order order = orderOpt.get(); + OrderStatus os = order.getOrderStatus(); + if (os == OrderStatus.PENDING || os == OrderStatus.PAID) { + insertOrUpdateOrderAction.invoke(order, input.pretixInformation); + shouldDelete = false; + } + } + + if (shouldDelete) { + deleteOrderAction.invoke(pretixOrder.getLeft().getCode()); + } + } + ); + + return true; + } + + public record Input( + @NotNull Event event, + @NotNull PretixInformation pretixInformation + ) {} +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/UploadFileAnswerUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/UploadFileAnswerUseCase.java new file mode 100644 index 0000000..75dffcb --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/order/usecase/UploadFileAnswerUseCase.java @@ -0,0 +1,61 @@ +package net.furizon.backend.feature.pretix.order.usecase; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.order.dto.PretixFileUploadResponse; +import net.furizon.backend.infrastructure.http.client.HttpClient; +import net.furizon.backend.infrastructure.http.client.HttpRequest; +import net.furizon.backend.infrastructure.pretix.PretixConfig; +import net.furizon.backend.infrastructure.usecase.UseCase; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.HttpClientErrorException; + +import java.util.Optional; + +// TODO -> Why do we need this class if we don't use it? +@Component +@RequiredArgsConstructor +@Slf4j +public class UploadFileAnswerUseCase implements UseCase> { + private final ParameterizedTypeReference pretixFileUploadResponse = + new ParameterizedTypeReference<>() { + }; + + @Qualifier("pretixHttpClient") + private final HttpClient pretixHttpClient; + + @Transactional + @NotNull + @Override + public Optional executor(@NotNull UploadFileAnswerUseCase.Input file) { + // TODO -> Action + final var request = HttpRequest.create() + .method(HttpMethod.POST) + .path("/upload") + .body(file.data) + .responseParameterizedType(pretixFileUploadResponse) + .build(); + + try { + PretixFileUploadResponse r = pretixHttpClient.send(PretixConfig.class, request).getBody(); + return r != null + ? Optional.of(r.getId()) + : Optional.empty(); + } catch (final HttpClientErrorException ex) { + log.error(ex.getResponseBodyAsString()); + throw ex; + } + } + + public record Input( + byte @NotNull [] data, + @NotNull MediaType mediaType, + long contentSize + ) {} +} diff --git a/application/src/main/java/net/furizon/backend/feature/organizer/PretixOrganizer.java b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/PretixOrganizer.java similarity index 85% rename from application/src/main/java/net/furizon/backend/feature/organizer/PretixOrganizer.java rename to application/src/main/java/net/furizon/backend/feature/pretix/organizer/PretixOrganizer.java index dec987c..668eecf 100644 --- a/application/src/main/java/net/furizon/backend/feature/organizer/PretixOrganizer.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/PretixOrganizer.java @@ -1,4 +1,4 @@ -package net.furizon.backend.feature.organizer; +package net.furizon.backend.feature.pretix.organizer; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; diff --git a/application/src/main/java/net/furizon/backend/feature/organizer/controller/OrganizerController.java b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/controller/OrganizerController.java similarity index 66% rename from application/src/main/java/net/furizon/backend/feature/organizer/controller/OrganizerController.java rename to application/src/main/java/net/furizon/backend/feature/pretix/organizer/controller/OrganizerController.java index ec92501..7ec9d88 100644 --- a/application/src/main/java/net/furizon/backend/feature/organizer/controller/OrganizerController.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/controller/OrganizerController.java @@ -1,8 +1,8 @@ -package net.furizon.backend.feature.organizer.controller; +package net.furizon.backend.feature.pretix.organizer.controller; import lombok.RequiredArgsConstructor; -import net.furizon.backend.feature.organizer.PretixOrganizer; -import net.furizon.backend.feature.organizer.finder.OrganizersFinder; +import net.furizon.backend.feature.pretix.organizer.PretixOrganizer; +import net.furizon.backend.feature.pretix.organizer.finder.OrganizersFinder; import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -15,7 +15,7 @@ public class OrganizerController { private final OrganizersFinder finder; @GetMapping - PretixPaging organizers() { + public PretixPaging organizers() { return finder.getPagedOrganizers(1); } } diff --git a/application/src/main/java/net/furizon/backend/feature/organizer/finder/OrganizersFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/finder/OrganizersFinder.java similarity index 63% rename from application/src/main/java/net/furizon/backend/feature/organizer/finder/OrganizersFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/organizer/finder/OrganizersFinder.java index 33df73f..bdadfa7 100644 --- a/application/src/main/java/net/furizon/backend/feature/organizer/finder/OrganizersFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/finder/OrganizersFinder.java @@ -1,6 +1,6 @@ -package net.furizon.backend.feature.organizer.finder; +package net.furizon.backend.feature.pretix.organizer.finder; -import net.furizon.backend.feature.organizer.PretixOrganizer; +import net.furizon.backend.feature.pretix.organizer.PretixOrganizer; import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; import org.jetbrains.annotations.NotNull; diff --git a/application/src/main/java/net/furizon/backend/feature/organizer/finder/PretixOrganizersFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/finder/PretixOrganizersFinder.java similarity index 91% rename from application/src/main/java/net/furizon/backend/feature/organizer/finder/PretixOrganizersFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/organizer/finder/PretixOrganizersFinder.java index cc6d26d..fab763a 100644 --- a/application/src/main/java/net/furizon/backend/feature/organizer/finder/PretixOrganizersFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/organizer/finder/PretixOrganizersFinder.java @@ -1,8 +1,8 @@ -package net.furizon.backend.feature.organizer.finder; +package net.furizon.backend.feature.pretix.organizer.finder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.feature.organizer.PretixOrganizer; +import net.furizon.backend.feature.pretix.organizer.PretixOrganizer; import net.furizon.backend.infrastructure.http.client.HttpClient; import net.furizon.backend.infrastructure.http.client.HttpRequest; import net.furizon.backend.infrastructure.pretix.PretixConfig; @@ -32,7 +32,7 @@ public class PretixOrganizersFinder implements OrganizersFinder { public PretixPaging getPagedOrganizers(int page) { final var request = HttpRequest.>create() .method(HttpMethod.GET) - .path("/organizers") + .path("/organizers/") .queryParam("page", String.valueOf(page)) .responseParameterizedType(pretixOrganization) .build(); diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/HotelCapacityPair.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/HotelCapacityPair.java new file mode 100644 index 0000000..6635a8b --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/HotelCapacityPair.java @@ -0,0 +1,5 @@ +package net.furizon.backend.feature.pretix.product; + +import org.jetbrains.annotations.NotNull; + +public record HotelCapacityPair(@NotNull String hotel, short capacity) {} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProduct.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProduct.java new file mode 100644 index 0000000..72b8b07 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProduct.java @@ -0,0 +1,41 @@ +package net.furizon.backend.feature.pretix.product; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import net.furizon.backend.infrastructure.pretix.Const; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +@Data +public class PretixProduct { + private final int id; + + @NotNull + @JsonProperty("meta_data") + private final Map metadata; + + @NotNull + @JsonProperty("name") + private final Map names; + + @NotNull + private final List variations; + + @Nullable + public String getIdentifier() { + return metadata.get(Const.METADATA_IDENTIFIER_ITEM); + } + + public void forEachVariationByIdentifierPrefix( + String prefix, + BiConsumer callback + ) { + variations.stream() + .filter(v -> v.getIdentifier() != null && v.getIdentifier().startsWith(prefix)) + .forEach(v -> callback.accept(v, v.getIdentifier().substring(prefix.length()))); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProductResults.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProductResults.java new file mode 100644 index 0000000..a2975e8 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProductResults.java @@ -0,0 +1,37 @@ +package net.furizon.backend.feature.pretix.product; + +import net.furizon.backend.infrastructure.pretix.model.ExtraDays; +import net.furizon.backend.infrastructure.pretix.model.Sponsorship; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +public record PretixProductResults( + @NotNull Set ticketItemIds, + @NotNull Map dailyIdToDay, + @NotNull Set membershipCardItemIds, + @NotNull Set sponsorshipItemIds, + @NotNull Map sponsorshipIdToType, + @NotNull Map extraDaysIdToDay, + @NotNull Set roomItemIds, + @NotNull Map roomIdToInfo, + @NotNull Map> roomInfoToNames +) { + public PretixProductResults() { + this( + new TreeSet<>(), + new TreeMap<>(), + new TreeSet<>(), + new TreeSet<>(), + new TreeMap<>(), + new TreeMap<>(), + new TreeSet<>(), + new TreeMap<>(), + new HashMap<>() + ); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProductVariation.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProductVariation.java new file mode 100644 index 0000000..c85eec8 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/PretixProductVariation.java @@ -0,0 +1,27 @@ +package net.furizon.backend.feature.pretix.product; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import net.furizon.backend.infrastructure.pretix.Const; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +@Data +public class PretixProductVariation { + private final int id; + + @NotNull + @JsonProperty("value") + private final Map names; + + @NotNull + @JsonProperty("meta_data") + private final Map metadata; + + @Nullable + public String getIdentifier() { + return metadata.get(Const.METADATA_IDENTIFIER_ITEM); + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/finder/PretixProductFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/finder/PretixProductFinder.java new file mode 100644 index 0000000..bad66c8 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/finder/PretixProductFinder.java @@ -0,0 +1,14 @@ +package net.furizon.backend.feature.pretix.product.finder; + +import net.furizon.backend.feature.pretix.product.PretixProduct; +import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; +import org.jetbrains.annotations.NotNull; + +public interface PretixProductFinder { + @NotNull + PretixPaging getPagedProducts( + @NotNull String organizer, + @NotNull String event, + int page + ); +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/finder/RestPretixProductFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/finder/RestPretixProductFinder.java new file mode 100644 index 0000000..43585e0 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/finder/RestPretixProductFinder.java @@ -0,0 +1,54 @@ +package net.furizon.backend.feature.pretix.product.finder; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.product.PretixProduct; +import net.furizon.backend.infrastructure.http.client.HttpClient; +import net.furizon.backend.infrastructure.http.client.HttpRequest; +import net.furizon.backend.infrastructure.pretix.PretixConfig; +import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; + +import java.util.Optional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class RestPretixProductFinder implements PretixProductFinder { + private final ParameterizedTypeReference> pretixPagedProduct = + new ParameterizedTypeReference<>() {}; + + @Qualifier("pretixHttpClient") + private final HttpClient pretixHttpClient; + + @NotNull + @Override + public PretixPaging getPagedProducts( + @NotNull String organizer, + @NotNull String event, + int page + ) { + final var request = HttpRequest.>create() + .method(HttpMethod.GET) + .path("/organizers/{organizer}/events/{event}/items/") + .queryParam("page", String.valueOf(page)) + .uriVariable("organizer", organizer) + .uriVariable("event", event) + .responseParameterizedType(pretixPagedProduct) + .build(); + + try { + return Optional + .ofNullable(pretixHttpClient.send(PretixConfig.class, request).getBody()) + .orElse(PretixPaging.empty()); + } catch (final HttpClientErrorException ex) { + log.error(ex.getResponseBodyAsString()); + throw ex; + } + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/pretix/product/usecase/ReloadProductsUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/product/usecase/ReloadProductsUseCase.java new file mode 100644 index 0000000..753abef --- /dev/null +++ b/application/src/main/java/net/furizon/backend/feature/pretix/product/usecase/ReloadProductsUseCase.java @@ -0,0 +1,99 @@ +package net.furizon.backend.feature.pretix.product.usecase; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.product.HotelCapacityPair; +import net.furizon.backend.feature.pretix.product.PretixProduct; +import net.furizon.backend.feature.pretix.product.PretixProductResults; +import net.furizon.backend.feature.pretix.product.finder.PretixProductFinder; +import net.furizon.backend.infrastructure.pretix.Const; +import net.furizon.backend.infrastructure.pretix.PretixPagingUtil; +import net.furizon.backend.infrastructure.pretix.model.ExtraDays; +import net.furizon.backend.infrastructure.pretix.model.Sponsorship; +import net.furizon.backend.infrastructure.usecase.UseCase; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class ReloadProductsUseCase implements UseCase { + private final PretixProductFinder pretixProductFinder; + + @NotNull + @Override + public PretixProductResults executor(Event event) { + final var pair = event.getOrganizerAndEventPair(); + PretixProductResults result = new PretixProductResults(); + + PretixPagingUtil.forEachElement( + paged -> pretixProductFinder.getPagedProducts(pair.getOrganizer(), pair.getEvent(), paged), + r -> { + PretixProduct product = r.getLeft(); + String identifier = product.getIdentifier(); + if (identifier == null) { + return; + } + + if (identifier.startsWith(Const.METADATA_EXTRA_DAYS_TAG_PREFIX)) { + String s = identifier.substring(Const.METADATA_EXTRA_DAYS_TAG_PREFIX.length()); + ExtraDays ed = ExtraDays.get(Integer.parseInt(s)); + result.extraDaysIdToDay().put(product.getId(), ed); + + } else if (identifier.startsWith(Const.METADATA_EVENT_TICKET_DAILY_TAG_PREFIX)) { + String s = identifier.substring(Const.METADATA_EVENT_TICKET_DAILY_TAG_PREFIX.length()); + int day = Integer.parseInt(s); + result.dailyIdToDay().put(product.getId(), day); + + } else { + switch (identifier) { + case Const.METADATA_EVENT_TICKET: { + result.ticketItemIds().add(product.getId()); + break; + } + case Const.METADATA_MEMBERSHIP_CARD: { + result.membershipCardItemIds().add(product.getId()); + break; + } + case Const.METADATA_SPONSORSHIP: { + result.sponsorshipItemIds().add(product.getId()); + product.forEachVariationByIdentifierPrefix( + Const.METADATA_SPONSORSHIP_VARIATIONS_TAG_PREFIX, + (variation, strippedIdentifier) -> { + Sponsorship ss = Sponsorship.get(Integer.parseInt(strippedIdentifier)); + result.sponsorshipIdToType().put(variation.getId(), ss); + } + ); + break; + } + case Const.METADATA_ROOM: { + result.roomItemIds().add(product.getId()); + product.forEachVariationByIdentifierPrefix( + Const.METADATA_ROOM_TYPE_TAG_PREFIX, + (variation, strippedIdentifier) -> { + String[] sp = strippedIdentifier.split("_"); + String hotelName = sp[0]; + short capacity = Short.parseShort(sp[1]); + HotelCapacityPair p = new HotelCapacityPair(hotelName, capacity); + result.roomIdToInfo().put(variation.getId(), p); + result.roomInfoToNames().put(p, variation.getNames()); + } + ); + break; + } + + default: { + log.warn( + "Unrecognized identifier while parsing product ({}) :'{}'", + product.getId(), identifier + ); + break; + } + } + } + } + ); + return result; + } +} diff --git a/application/src/main/java/net/furizon/backend/feature/question/PretixQuestion.java b/application/src/main/java/net/furizon/backend/feature/pretix/question/PretixQuestion.java similarity index 84% rename from application/src/main/java/net/furizon/backend/feature/question/PretixQuestion.java rename to application/src/main/java/net/furizon/backend/feature/pretix/question/PretixQuestion.java index 9ac4db5..d10bd41 100644 --- a/application/src/main/java/net/furizon/backend/feature/question/PretixQuestion.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/question/PretixQuestion.java @@ -1,4 +1,4 @@ -package net.furizon.backend.feature.question; +package net.furizon.backend.feature.pretix.question; import lombok.Data; import net.furizon.backend.infrastructure.pretix.model.QuestionType; diff --git a/application/src/main/java/net/furizon/backend/feature/question/finder/PretixQuestionFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/question/finder/PretixQuestionFinder.java similarity index 70% rename from application/src/main/java/net/furizon/backend/feature/question/finder/PretixQuestionFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/question/finder/PretixQuestionFinder.java index 1aa6def..737472b 100644 --- a/application/src/main/java/net/furizon/backend/feature/question/finder/PretixQuestionFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/question/finder/PretixQuestionFinder.java @@ -1,6 +1,6 @@ -package net.furizon.backend.feature.question.finder; +package net.furizon.backend.feature.pretix.question.finder; -import net.furizon.backend.feature.question.PretixQuestion; +import net.furizon.backend.feature.pretix.question.PretixQuestion; import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; import org.jetbrains.annotations.NotNull; diff --git a/application/src/main/java/net/furizon/backend/feature/question/finder/RestPretixQuestionFinder.java b/application/src/main/java/net/furizon/backend/feature/pretix/question/finder/RestPretixQuestionFinder.java similarity index 91% rename from application/src/main/java/net/furizon/backend/feature/question/finder/RestPretixQuestionFinder.java rename to application/src/main/java/net/furizon/backend/feature/pretix/question/finder/RestPretixQuestionFinder.java index a01d8ff..b2059ce 100644 --- a/application/src/main/java/net/furizon/backend/feature/question/finder/RestPretixQuestionFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/question/finder/RestPretixQuestionFinder.java @@ -1,8 +1,8 @@ -package net.furizon.backend.feature.question.finder; +package net.furizon.backend.feature.pretix.question.finder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.feature.question.PretixQuestion; +import net.furizon.backend.feature.pretix.question.PretixQuestion; import net.furizon.backend.infrastructure.http.client.HttpClient; import net.furizon.backend.infrastructure.http.client.HttpRequest; import net.furizon.backend.infrastructure.pretix.PretixConfig; @@ -21,8 +21,7 @@ @Slf4j public class RestPretixQuestionFinder implements PretixQuestionFinder { private final ParameterizedTypeReference> pretixPagedQuestion = - new ParameterizedTypeReference<>() { - }; + new ParameterizedTypeReference<>() {}; @Qualifier("pretixHttpClient") private final HttpClient pretixHttpClient; @@ -36,7 +35,7 @@ public PretixPaging getPagedQuestions( ) { final var request = HttpRequest.>create() .method(HttpMethod.GET) - .path("/organizers/{organizer}/events/{event}/questions") + .path("/organizers/{organizer}/events/{event}/questions/") .queryParam("page", String.valueOf(page)) .uriVariable("organizer", organizer) .uriVariable("event", event) diff --git a/application/src/main/java/net/furizon/backend/feature/question/usecase/ReloadQuestionsUseCase.java b/application/src/main/java/net/furizon/backend/feature/pretix/question/usecase/ReloadQuestionsUseCase.java similarity index 58% rename from application/src/main/java/net/furizon/backend/feature/question/usecase/ReloadQuestionsUseCase.java rename to application/src/main/java/net/furizon/backend/feature/pretix/question/usecase/ReloadQuestionsUseCase.java index c6f0acc..82fefb6 100644 --- a/application/src/main/java/net/furizon/backend/feature/question/usecase/ReloadQuestionsUseCase.java +++ b/application/src/main/java/net/furizon/backend/feature/pretix/question/usecase/ReloadQuestionsUseCase.java @@ -1,16 +1,15 @@ -package net.furizon.backend.feature.question.usecase; +package net.furizon.backend.feature.pretix.question.usecase; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.feature.event.Event; -import net.furizon.backend.feature.question.PretixQuestion; -import net.furizon.backend.feature.question.finder.PretixQuestionFinder; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.question.PretixQuestion; +import net.furizon.backend.feature.pretix.question.finder.PretixQuestionFinder; import net.furizon.backend.infrastructure.pretix.PretixPagingUtil; import net.furizon.backend.infrastructure.usecase.UseCase; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; -import java.util.Collections; import java.util.List; @Component @@ -23,15 +22,11 @@ public class ReloadQuestionsUseCase implements UseCase executor(@NotNull Event input) { final var pair = input.getOrganizerAndEventPair(); - if (pair == null) { - log.warn("Couldn't find an organizer and event by provided input: {}", input); - return Collections.emptyList(); - } - return PretixPagingUtil.combineAll( + return PretixPagingUtil.fetchAll( paging -> pretixQuestionFinder.getPagedQuestions( - pair.getFirst(), - pair.getSecond(), + pair.getOrganizer(), + pair.getEvent(), paging ) ); diff --git a/application/src/main/java/net/furizon/backend/feature/user/finder/JooqUserFinder.java b/application/src/main/java/net/furizon/backend/feature/user/finder/JooqUserFinder.java index 51d946c..e09dcf3 100644 --- a/application/src/main/java/net/furizon/backend/feature/user/finder/JooqUserFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/user/finder/JooqUserFinder.java @@ -40,6 +40,17 @@ public User findById(long id) { .mapOrNull(JooqUserMapper::map); } + @Nullable + @Override + public User findBySecret(String secret) { + return sqlQuery + .fetchFirst( + selectUser() + .where(USERS.USER_SECRET.eq(secret)) + ) + .mapOrNull(JooqUserMapper::map); + } + private SelectJoinStep selectUser() { return DSL .select(USERS.USER_ID) diff --git a/application/src/main/java/net/furizon/backend/feature/user/finder/UserFinder.java b/application/src/main/java/net/furizon/backend/feature/user/finder/UserFinder.java index dbe5469..2b3e203 100644 --- a/application/src/main/java/net/furizon/backend/feature/user/finder/UserFinder.java +++ b/application/src/main/java/net/furizon/backend/feature/user/finder/UserFinder.java @@ -12,4 +12,7 @@ public interface UserFinder { @Nullable User findById(long id); + + @Nullable + User findBySecret(String secret); } diff --git a/application/src/main/java/net/furizon/backend/infrastructure/http/client/HttpRequest.java b/application/src/main/java/net/furizon/backend/infrastructure/http/client/HttpRequest.java index 5cc3a58..16060ef 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/http/client/HttpRequest.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/http/client/HttpRequest.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -36,6 +37,9 @@ public class HttpRequest { @Nullable private final Object body; + @Nullable + private final MediaType contentType; + @Nullable private final Class responseType; @@ -43,10 +47,11 @@ public class HttpRequest { private final ParameterizedTypeReference responseParameterizedType; public static class Builder { - private HttpMethod method = null; + private Class responseType; private String path = null; private Object body = null; - private Class responseType; + private HttpMethod method = null; + private MediaType contentType = null; private ParameterizedTypeReference responseParameterizedType; private final MultiValueMap headers = new LinkedMultiValueMap<>(); @@ -88,6 +93,11 @@ public Builder queryParams(@NotNull final MultiValueMap query return this; } + public Builder contentType(@NotNull final MediaType mediaType) { + this.contentType = mediaType; + return this; + } + public Builder body(@NotNull final Object body) { this.body = body; return this; @@ -113,6 +123,7 @@ public HttpRequest build() { uriVariables, queryParams, body, + contentType, responseType, responseParameterizedType ); diff --git a/application/src/main/java/net/furizon/backend/infrastructure/http/client/SimpleHttpClient.java b/application/src/main/java/net/furizon/backend/infrastructure/http/client/SimpleHttpClient.java index d3b8c3b..92f1425 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/http/client/SimpleHttpClient.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/http/client/SimpleHttpClient.java @@ -66,6 +66,9 @@ public ResponseEntity send( if (request.getBody() != null) { requestBodySpec = requestBodySpec.body(request.getBody()); } + if (request.getContentType() != null) { + requestBodySpec = requestBodySpec.contentType(request.getContentType()); + } if (request.getResponseParameterizedType() == null && request.getResponseType() == null) { throw new IllegalArgumentException("responseParameterizedType or responseType is required"); diff --git a/application/src/main/java/net/furizon/backend/infrastructure/jackson/JsonSerializer.java b/application/src/main/java/net/furizon/backend/infrastructure/jackson/JsonSerializer.java new file mode 100644 index 0000000..d13c0b5 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/infrastructure/jackson/JsonSerializer.java @@ -0,0 +1,12 @@ +package net.furizon.backend.infrastructure.jackson; + +import org.jetbrains.annotations.NotNull; +import org.jooq.JSON; + +public interface JsonSerializer { + @NotNull + String serializeAsString(Object object); + + @NotNull + JSON serializeAsJson(Object object); +} diff --git a/application/src/main/java/net/furizon/backend/infrastructure/jackson/SimpleJsonSerializer.java b/application/src/main/java/net/furizon/backend/infrastructure/jackson/SimpleJsonSerializer.java new file mode 100644 index 0000000..e67df31 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/infrastructure/jackson/SimpleJsonSerializer.java @@ -0,0 +1,31 @@ +package net.furizon.backend.infrastructure.jackson; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.jooq.JSON; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class SimpleJsonSerializer implements JsonSerializer { + private final ObjectMapper objectMapper; + + @Override + public @NotNull String serializeAsString(Object object) { + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + log.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + + @Override + public @NotNull JSON serializeAsJson(Object object) { + return JSON.valueOf(serializeAsString(object)); + } +} diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/Const.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/Const.java index d91ed72..e124eaf 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/pretix/Const.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/Const.java @@ -1,22 +1,21 @@ package net.furizon.backend.infrastructure.pretix; public class Const { + public static final String METADATA_IDENTIFIER_ITEM = "item_name"; + public static final String QUESTIONS_ACCOUNT_SECRET = "account_secret"; public static final String METADATA_EVENT_TICKET = "ticket"; - public static final String METADATA_EVENT_TICKET_DAILY_TAG_PREFIX = "ticket_daily_"; public static final String METADATA_MEMBERSHIP_CARD = "membership_card"; public static final String METADATA_SPONSORSHIP = "sponsorship"; - public static final String METADATA_SPONSORSHIP_VARIATIONS_TAG_PREFIX = "sponsorship_type_"; public static final String METADATA_EXTRA_DAYS_TAG_PREFIX = "extra_days_"; public static final String METADATA_ROOM = "room"; - public static final String METADATA_ROOM_TYPE_TAG_PREFIX = "room_type_"; public static final String QUESTIONS_FILE_KEEP = "file:keep"; diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixGenericUtils.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixGenericUtils.java new file mode 100644 index 0000000..982c423 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixGenericUtils.java @@ -0,0 +1,25 @@ +package net.furizon.backend.infrastructure.pretix; + +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; + +public class PretixGenericUtils { + public static String buildOrgEventSlug(String eventSlug, String organizerSlug) { + return organizerSlug + "/" + eventSlug; + } + + public static final DateTimeFormatter PRETIX_DATETIME_FORMAT = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(DateTimeFormatter.ISO_LOCAL_DATE) + .appendLiteral(' ') + .append(DateTimeFormatter.ISO_LOCAL_TIME) + .parseLenient() + .appendOffsetId() + .parseStrict() + .optionalStart() + .appendLiteral('[') + .parseCaseSensitive() + .appendZoneRegionId() + .appendLiteral(']') + .toFormatter(); +} diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixPagingUtil.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixPagingUtil.java index 6957e33..41563a2 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixPagingUtil.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/PretixPagingUtil.java @@ -1,7 +1,7 @@ package net.furizon.backend.infrastructure.pretix; import net.furizon.backend.infrastructure.pretix.dto.PretixPaging; -import org.springframework.data.util.Pair; +import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.List; @@ -9,7 +9,7 @@ import java.util.function.Function; public class PretixPagingUtil { - public static > void fetchAll( + public static > void forEachPage( Function callable, Consumer, P>> consumer ) { @@ -18,7 +18,8 @@ public static > void fetchAll( while (hasNext) { final P response = callable.apply(currentPage); if (response.getResults() == null) { - continue; + hasNext = false; + break; } consumer.accept(Pair.of(response.getResults(), response)); @@ -30,11 +31,18 @@ public static > void fetchAll( } } - public static > List combineAll( + public static > void forEachElement( + Function callable, + Consumer> consumer + ) { + forEachPage(callable, r -> r.getLeft().forEach(el -> consumer.accept(Pair.of(el, r.getRight())))); + } + + public static > List fetchAll( Function callable ) { final var combined = new ArrayList(); - fetchAll(callable, result -> combined.addAll(result.getFirst())); + forEachPage(callable, result -> combined.addAll(result.getLeft())); return combined; } diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/dto/PretixPaging.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/dto/PretixPaging.java index 2d32af0..f075795 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/pretix/dto/PretixPaging.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/dto/PretixPaging.java @@ -1,6 +1,7 @@ package net.furizon.backend.infrastructure.pretix.dto; import lombok.Data; +import net.minidev.json.annotate.JsonIgnore; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -12,6 +13,7 @@ public class PretixPaging { public static final int DEFAULT_PAGE = 1; + @JsonIgnore private final Pattern pageNumberPatter = Pattern.compile("page=(\\d+)"); private final int page; diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/CacheItemTypes.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/CacheItemTypes.java new file mode 100644 index 0000000..6451250 --- /dev/null +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/CacheItemTypes.java @@ -0,0 +1,8 @@ +package net.furizon.backend.infrastructure.pretix.model; + +public enum CacheItemTypes { + TICKETS, + MEMBERSHIP_CARDS, + SPONSORSHIPS, + ROOMS +} diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/ExtraDays.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/ExtraDays.java index fe03283..03cf9cf 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/ExtraDays.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/model/ExtraDays.java @@ -6,7 +6,7 @@ public enum ExtraDays { LATE, BOTH; - public static Sponsorship get(int ordinal) { - return Sponsorship.values()[ordinal]; + public static ExtraDays get(int ordinal) { + return ExtraDays.values()[ordinal]; } } diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/CachedPretixInformation.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/CachedPretixInformation.java index 2754338..f3c7d7c 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/CachedPretixInformation.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/CachedPretixInformation.java @@ -5,17 +5,38 @@ import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.feature.event.Event; -import net.furizon.backend.feature.event.usecase.ReloadEventsUseCase; -import net.furizon.backend.feature.question.usecase.ReloadQuestionsUseCase; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.event.usecase.ReloadEventsUseCase; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.PretixAnswer; +import net.furizon.backend.feature.pretix.order.PretixOrder; +import net.furizon.backend.feature.pretix.order.PretixPosition; +import net.furizon.backend.feature.pretix.order.usecase.ReloadOrdersUseCase; +import net.furizon.backend.feature.pretix.product.HotelCapacityPair; +import net.furizon.backend.feature.pretix.product.PretixProductResults; +import net.furizon.backend.feature.pretix.product.usecase.ReloadProductsUseCase; +import net.furizon.backend.feature.pretix.question.PretixQuestion; +import net.furizon.backend.feature.pretix.question.usecase.ReloadQuestionsUseCase; +import net.furizon.backend.feature.user.finder.UserFinder; +import net.furizon.backend.infrastructure.pretix.Const; +import net.furizon.backend.infrastructure.pretix.model.CacheItemTypes; +import net.furizon.backend.infrastructure.pretix.model.ExtraDays; +import net.furizon.backend.infrastructure.pretix.model.OrderStatus; import net.furizon.backend.infrastructure.pretix.model.QuestionType; +import net.furizon.backend.infrastructure.pretix.model.Sponsorship; import net.furizon.backend.infrastructure.usecase.UseCaseExecutor; import net.furizon.backend.infrastructure.usecase.UseCaseInput; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiFunction; import static net.furizon.backend.infrastructure.pretix.Const.QUESTIONS_ACCOUNT_SECRET; @@ -23,28 +44,46 @@ @RequiredArgsConstructor @Slf4j public class CachedPretixInformation implements PretixInformation { - @NotNull - private final UseCaseExecutor useCaseExecutor; + @NotNull private final UseCaseExecutor useCaseExecutor; - @NotNull - private final AtomicReference currentEvent = new AtomicReference<>(null); + @NotNull private final UserFinder userFinder; - @NotNull - private final AtomicReference questionSecretId = new AtomicReference<>(-1); + // *** CACHE - @NotNull - private final Cache questionTypeIdsCache = Caffeine.newBuilder().build(); + @NotNull private final AtomicReference currentEvent = new AtomicReference<>(null); - @NotNull - private final Cache questionIdentifiersCache = Caffeine.newBuilder().build(); + //Event Struct - @NotNull - private final Cache questionIdentifiersToIdCache = Caffeine.newBuilder().build(); + //Contains tickets, memberships, sponsors, rooms + @NotNull private final Cache> itemIdsCache = Caffeine.newBuilder().build(); + + //Questions + @NotNull private final AtomicReference questionSecretId = new AtomicReference<>(-1); + @NotNull private final Cache questionIdToType = Caffeine.newBuilder().build(); + @NotNull private final Cache questionIdToIdentifier = Caffeine.newBuilder().build(); + @NotNull private final Cache questionIdentifierToId = Caffeine.newBuilder().build(); + + //Tickets + @NotNull private final Cache dailyIdToDay = Caffeine.newBuilder().build(); //map id -> day idx + + //Sponsors + @NotNull private final Cache sponsorshipIdToType = Caffeine.newBuilder().build(); + + //Extra days + @NotNull private final Cache extraDaysIdToDay = Caffeine.newBuilder().build(); + + //Rooms + //map id -> (capacity, hotelName) + @NotNull private final Cache roomIdToInfo = Caffeine.newBuilder().build(); + //map capacity/name -> room name + @NotNull private final Cache> roomInfoToNames = + Caffeine.newBuilder().build(); @PostConstruct public void init() { log.info("[PRETIX] Initializing pretix information and cache it"); resetCache(); + reloadAllOrders(); } @NotNull @@ -60,61 +99,234 @@ public int getQuestionSecretId() { @NotNull @Override - public Optional getQuestionTypeById(int id) { - return Optional.ofNullable(questionTypeIdsCache.getIfPresent(id)); + public Optional getQuestionTypeFromId(int id) { + return Optional.ofNullable(questionIdToType.getIfPresent(id)); + } + + @NotNull + @Override + public Optional getQuestionTypeFromIdentifier(@NotNull String identifier) { + return Optional.ofNullable( + questionIdToType.getIfPresent(questionIdentifierToId.getIfPresent(identifier)) + ); + } + + @NotNull + @Override + public Optional getQuestionIdentifierFromId(int id) { + return Optional.ofNullable(questionIdToIdentifier.getIfPresent(id)); + } + + @NotNull + @Override + public Optional getQuestionIdFromIdentifier(@NotNull String identifier) { + return Optional.ofNullable(questionIdentifierToId.getIfPresent(identifier)); + } + + @NotNull + @Override + public Optional parseOrderFromId(@NotNull PretixOrder pretixOrder, @NotNull Event event) { + Integer cacheDay; + ExtraDays cacheExtraDays; + BiFunction checkItemId = (type, item) -> + Objects.requireNonNull(itemIdsCache.getIfPresent(type)).contains(item); + + boolean hasTicket = false; //If no ticket is found, we don't store the order at all + + String code = pretixOrder.getCode(); + String secret = pretixOrder.getSecret(); + OrderStatus status = OrderStatus.get(pretixOrder.getStatus()); + + Set days = new HashSet<>(); + Sponsorship sponsorship = Sponsorship.NONE; + ExtraDays extraDays = ExtraDays.NONE; + List answers = null; + int answersMainPositionId = 0; + String hotelLocation = null; + boolean membership = false; + String userSecret = null; + short roomCapacity = 0; + + List positions = pretixOrder.getPositions(); + if (positions.isEmpty()) { + status = OrderStatus.CANCELED; + } + + for (PretixPosition position : positions) { + int item = position.getItemId(); + + if (checkItemId.apply(CacheItemTypes.TICKETS, item)) { + hasTicket = true; + answersMainPositionId = position.getPositionId(); + answers = position.getAnswers(); + for (PretixAnswer answer : answers) { + int questionId = answer.getQuestionId(); + var questionType = getQuestionTypeFromId(questionId); + if (questionType.isPresent()) { + if (questionType.get() == QuestionType.FILE) { + answer.setAnswer(Const.QUESTIONS_FILE_KEEP); + } + if (questionId == this.getQuestionSecretId()) { + userSecret = answer.getAnswer(); + } + } + } + + } else if ((cacheDay = dailyIdToDay.getIfPresent(item)) != null) { + days.add(cacheDay); + + } else if (checkItemId.apply(CacheItemTypes.MEMBERSHIP_CARDS, item)) { + membership = true; + + } else if (checkItemId.apply(CacheItemTypes.SPONSORSHIPS, item)) { + Sponsorship s = sponsorshipIdToType.getIfPresent(position.getVariationId()); + if (s != null && s.ordinal() > sponsorship.ordinal()) { + sponsorship = s; //keep the best sponsorship + } + + } else if ((cacheExtraDays = extraDaysIdToDay.getIfPresent(item)) != null) { + if (extraDays != ExtraDays.BOTH) { + if (extraDays != cacheExtraDays && extraDays != ExtraDays.NONE) { + extraDays = ExtraDays.BOTH; + } else { + extraDays = cacheExtraDays; + } + } + + } else if (checkItemId.apply(CacheItemTypes.ROOMS, item)) { + HotelCapacityPair room = roomIdToInfo.getIfPresent(position.getVariationId()); + if (room != null) { + roomCapacity = room.capacity(); + hotelLocation = room.hotel(); + } + } + } + + if (hasTicket) { + Order order = Order.builder() + .code(code) + .orderStatus(status) + .sponsorship(sponsorship) + .extraDays(extraDays) + .dailyDays(days) + .roomCapacity(roomCapacity) + .hotelLocation(hotelLocation) + .pretixOrderSecret(secret) + .hasMembership(membership) + .answersMainPositionId(answersMainPositionId) + .orderOwner(userFinder.findBySecret(userSecret)) + .orderEvent(event) + .answers(answers, this) + .build(); + return Optional.of(order); + } + return Optional.empty(); } @Override public void resetCache() { log.info("[PRETIX] Resetting cache for pretix information"); - questionSecretId.set(-1); - currentEvent.set(null); - questionTypeIdsCache.invalidateAll(); - questionIdentifiersCache.invalidateAll(); - questionIdentifiersToIdCache.invalidateAll(); + + invalidateEventsCache(); + invalidateEventStructCache(); // reloading events + reloadEvents(); + reloadEventStructure(); + } + + private void invalidateEventsCache() { + log.info("[PRETIX] Resetting event cache"); + currentEvent.set(null); + } + + private void invalidateEventStructCache() { + log.info("[PRETIX] Resetting event's struct cache"); + + //General + itemIdsCache.invalidateAll(); + + //Questions + questionSecretId.set(-1); + questionIdToType.invalidateAll(); + questionIdToIdentifier.invalidateAll(); + questionIdentifierToId.invalidateAll(); + + //Tickets + dailyIdToDay.invalidateAll(); + + //Sponsors + sponsorshipIdToType.invalidateAll(); + + //Extra days + extraDaysIdToDay.invalidateAll(); + + //Rooms + roomIdToInfo.invalidateAll(); + roomInfoToNames.invalidateAll(); + } + + + private void reloadEvents() { useCaseExecutor - .execute( - ReloadEventsUseCase.class, - UseCaseInput.EMPTY - ) + .execute(ReloadEventsUseCase.class, UseCaseInput.EMPTY) .ifPresent(event -> { log.info("[PRETIX] Setting an event as current = '{}'", event); currentEvent.set(event); }); - - reloadQuestions(); } - private void reloadQuestions() { - final var event = currentEvent.get(); + private void reloadEventStructure() { + final Event event = currentEvent.get(); if (event == null) { - log.warn("[PRETIX] Current event is null, skipping question reload"); + log.warn("[PRETIX] Current event is null, skipping event structure reload"); return; } - final var questionList = useCaseExecutor.execute( - ReloadQuestionsUseCase.class, - event - ); + reloadQuestions(event); + reloadProducts(event); + } + + private void reloadQuestions(Event event) { + List questionList = useCaseExecutor.execute(ReloadQuestionsUseCase.class, event); questionList.forEach(question -> { - final var questionId = question.getId(); - final var questionType = question.getType(); - final var questionIdentifier = question.getIdentifier(); + int questionId = question.getId(); + QuestionType questionType = question.getType(); + String questionIdentifier = question.getIdentifier(); - questionTypeIdsCache.put(questionId, questionType); - questionIdentifiersCache.put(questionId, questionIdentifier); - questionIdentifiersToIdCache.put(questionIdentifier, questionId); + questionIdToType.put(questionId, questionType); + questionIdToIdentifier.put(questionId, questionIdentifier); + questionIdentifierToId.put(questionIdentifier, questionId); }); // searching QUESTIONS_ACCOUNT_SECRET - questionList - .stream() - .filter(it -> it.getIdentifier().equals(QUESTIONS_ACCOUNT_SECRET)) - .findFirst() - .ifPresent(it -> { - log.info("[PRETIX] Account secret id found, setup it on value = '{}'", it.getId()); - questionSecretId.set(it.getId()); - }); + Integer accountSecretId = questionIdentifierToId.getIfPresent(QUESTIONS_ACCOUNT_SECRET); + if (accountSecretId != null) { + log.info("[PRETIX] Account secret id found, setup it on value = '{}'", accountSecretId); + questionSecretId.set(accountSecretId); + } + } + + private void reloadProducts(Event event) { + PretixProductResults products = useCaseExecutor.execute(ReloadProductsUseCase.class, event); + + itemIdsCache.put(CacheItemTypes.TICKETS, products.ticketItemIds()); + itemIdsCache.put(CacheItemTypes.MEMBERSHIP_CARDS, products.membershipCardItemIds()); + itemIdsCache.put(CacheItemTypes.SPONSORSHIPS, products.sponsorshipItemIds()); + itemIdsCache.put(CacheItemTypes.ROOMS, products.roomItemIds()); + + dailyIdToDay.putAll(products.dailyIdToDay()); + sponsorshipIdToType.putAll(products.sponsorshipIdToType()); + extraDaysIdToDay.putAll(products.extraDaysIdToDay()); + roomIdToInfo.putAll(products.roomIdToInfo()); + roomInfoToNames.putAll(products.roomInfoToNames()); + } + + @Override + public void reloadAllOrders() { + var event = getCurrentEvent(); + if (event.isPresent()) { + var input = new ReloadOrdersUseCase.Input(event.get(), this); + useCaseExecutor.execute(ReloadOrdersUseCase.class, input); + } } } diff --git a/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/PretixInformation.java b/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/PretixInformation.java index 4828f89..92f2769 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/PretixInformation.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/pretix/service/PretixInformation.java @@ -1,6 +1,8 @@ package net.furizon.backend.infrastructure.pretix.service; -import net.furizon.backend.feature.event.Event; +import net.furizon.backend.feature.pretix.event.Event; +import net.furizon.backend.feature.pretix.order.Order; +import net.furizon.backend.feature.pretix.order.PretixOrder; import net.furizon.backend.infrastructure.pretix.model.QuestionType; import org.jetbrains.annotations.NotNull; @@ -13,7 +15,21 @@ public interface PretixInformation { int getQuestionSecretId(); @NotNull - Optional getQuestionTypeById(int id); + Optional getQuestionTypeFromId(int id); + + @NotNull + Optional getQuestionTypeFromIdentifier(@NotNull String identifier); + + @NotNull + Optional getQuestionIdentifierFromId(int id); + + @NotNull + Optional getQuestionIdFromIdentifier(@NotNull String identifier); + + @NotNull + Optional parseOrderFromId(@NotNull PretixOrder pretixOrder, @NotNull Event event); void resetCache(); + + void reloadAllOrders(); } diff --git a/application/src/main/java/net/furizon/backend/infrastructure/security/Permission.java b/application/src/main/java/net/furizon/backend/infrastructure/security/Permission.java index f4046cf..b6dc19e 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/security/Permission.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/security/Permission.java @@ -27,6 +27,8 @@ public enum Permission { */ REVIEW_UPLOADS("REVIEW_UPLOADS"); + + // TODO -> Why do you need it if enums can be as value (Enum.name()) // TODO -> Maybe Int ids? private final String value; diff --git a/application/src/main/java/net/furizon/backend/infrastructure/security/configuration/SecurityConfiguration.java b/application/src/main/java/net/furizon/backend/infrastructure/security/configuration/SecurityConfiguration.java index 0019547..065513f 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/security/configuration/SecurityConfiguration.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/security/configuration/SecurityConfiguration.java @@ -15,6 +15,7 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @@ -41,14 +42,14 @@ public class SecurityConfiguration { private final DatabaseSessionFilter databaseSessionFilter; @Bean - public SecurityFilterChain filterChain( - HttpSecurity http - ) throws Exception { + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // Map the allowed endpoints return http .cors(customizer -> - customizer.configurationSource(corsConfigurationSource()) + //customizer.configurationSource(corsConfigurationSource()) + customizer.disable() ) + .csrf(CsrfConfigurer::disable) .authorizeHttpRequests(customizer -> customizer .requestMatchers(antMatcher(HttpMethod.POST, "/api/v1/authentication/login")) .permitAll() @@ -87,8 +88,8 @@ private CorsConfigurationSource corsConfigurationSource() { return request -> { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins( - List.of("http://localhost")) - ; + List.of("*") // TODO -> Replace for prod + ); config.setAllowedMethods( List.of( HttpMethod.GET.name(), diff --git a/application/src/main/java/net/furizon/backend/infrastructure/usecase/SimpleUseCaseExecutor.java b/application/src/main/java/net/furizon/backend/infrastructure/usecase/SimpleUseCaseExecutor.java index 89eab7f..ba621e3 100644 --- a/application/src/main/java/net/furizon/backend/infrastructure/usecase/SimpleUseCaseExecutor.java +++ b/application/src/main/java/net/furizon/backend/infrastructure/usecase/SimpleUseCaseExecutor.java @@ -32,11 +32,20 @@ public > R execute( @NotNull I input ) { log.debug("Executing use case: {}", useCaseClass.getSimpleName()); + final var startTime = System.currentTimeMillis(); final UseCase useCase = useCaseMap.get(useCaseClass.getCanonicalName()); if (useCase == null) { throw new IllegalArgumentException("Use case not found: " + useCaseClass.getSimpleName()); } - return ((UseCase) useCase).executor(input); + final var result = ((UseCase) useCase).executor(input); + + log.debug( + "Use case '{}' finished with {} ms", + useCaseClass.getSimpleName(), + System.currentTimeMillis() - startTime + ); + + return result; } } diff --git a/application/src/main/java/net/furizon/backend/service/pretix/PretixService.java b/application/src/main/java/net/furizon/backend/service/pretix/PretixService.java index 89a113b..b41b816 100644 --- a/application/src/main/java/net/furizon/backend/service/pretix/PretixService.java +++ b/application/src/main/java/net/furizon/backend/service/pretix/PretixService.java @@ -1,16 +1,12 @@ package net.furizon.backend.service.pretix; -import lombok.RequiredArgsConstructor; +/*import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.db.entities.pretix.Order; -import net.furizon.backend.db.entities.users.User; -import net.furizon.backend.db.repositories.pretix.OrderRepository; import net.furizon.backend.infrastructure.pretix.PretixConfig; import net.furizon.backend.infrastructure.pretix.model.ExtraDays; import net.furizon.backend.infrastructure.pretix.model.OrderStatus; import net.furizon.backend.infrastructure.pretix.model.QuestionType; import net.furizon.backend.infrastructure.pretix.model.Sponsorship; -import net.furizon.backend.utils.Download; import net.furizon.backend.utils.TextUtil; import net.furizon.backend.utils.ThrowableSupplier; import net.furizon.backend.utils.pretix.Constants; @@ -33,17 +29,17 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; +import java.util.function.Consumer;*/ /** * Describes all the iteractions via Pretix */ -@Service -@Slf4j -@RequiredArgsConstructor -@Deprecated +//@Service +//@Slf4j +//@RequiredArgsConstructor +//@Deprecated public class PretixService { - private final OrderRepository orderRepository; + /*private final OrderRepository orderRepository; private final PretixConfig pretixConfig; private PretixIdsMap pretixIdsCache = null; @@ -265,20 +261,20 @@ private void parseOrderAndUpdateDatabase(JSONObject orderData) { } // Fetch Order by code - Order order = orderRepository.findByCodeAndEvent( + DeprOrder order = orderRepository.findByCodeAndEvent( code, //pretixConfig.getCurrentEventObj().getSlug() // not responsibility of config "" ).orElse(null); if (hasTicket && (status == OrderStatus.PENDING || status == OrderStatus.PAID)) { // fetch user from db by userSecret - User usr = null; + DeprUser usr = null; if (!TextUtil.isEmpty(userSecret)) { //usr = userRepository.findBySecret(userSecret).orElse(null); } if (order == null) { - order = new Order(); //order not found + order = new DeprOrder(); //order not found } order.update( @@ -356,7 +352,7 @@ public synchronized QuestionType translateQuestionType(String questionIdentifier } //Push orders to pretix - public synchronized void submitAnswersToPretix(Order order) throws TimeoutException { + public synchronized void submitAnswersToPretix(DeprOrder order) throws TimeoutException { JSONObject payload = new JSONObject(); JSONArray ans = order.getOrderStatus() == OrderStatus.CANCELED ? new JSONArray() @@ -524,5 +520,5 @@ private Download.Response doRequest( throw new TimeoutException("PRETIX_REQUESTS_MAX reached while " + opLogStr + " to pretix."); } return res; - } + }*/ } diff --git a/application/src/main/java/net/furizon/backend/service/users/UserService.java b/application/src/main/java/net/furizon/backend/service/users/UserService.java index 78be582..4dd3435 100644 --- a/application/src/main/java/net/furizon/backend/service/users/UserService.java +++ b/application/src/main/java/net/furizon/backend/service/users/UserService.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.utils.TextUtil; +import org.apache.logging.log4j.util.Strings; import org.jetbrains.annotations.NotNull; import org.springframework.dao.DuplicateKeyException; import org.springframework.security.core.userdetails.UserDetails; @@ -33,7 +33,7 @@ public String createUniqueSecret() { //} toReturn = null; } - if (TextUtil.isEmpty(toReturn)) { + if (Strings.isEmpty(toReturn)) { throw new DuplicateKeyException( "Failed to generate secret after " + MAX_USER_SECRET_GENERATION_TRIES + " times." ); diff --git a/application/src/main/java/net/furizon/backend/utils/Download.java b/application/src/main/java/net/furizon/backend/utils/Download.java deleted file mode 100644 index bb959ca..0000000 --- a/application/src/main/java/net/furizon/backend/utils/Download.java +++ /dev/null @@ -1,1174 +0,0 @@ -package net.furizon.backend.utils; - -import lombok.ToString; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CookieStore; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.config.RequestConfig.Builder; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPatch; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.DefaultHostnameVerifier; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.TrustAllStrategy; -import org.apache.http.conn.util.PublicSuffixMatcherLoader; -import org.apache.http.cookie.Cookie; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.impl.cookie.BasicClientCookie; -import org.apache.http.message.BasicHeader; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpCoreContext; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.SSLContexts; -import org.apache.http.util.EntityUtils; -import org.json.JSONObject; - -import javax.net.ssl.HostnameVerifier; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -/* - * GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - - */ - -// If it is an HttpClient class, why it calls Download? -// Anyway, better replace it -@Deprecated(forRemoval = true, since = "new http implementation") -public class Download { - public static final int DEFAULT_MAX_CONNECTIONS = 20; - public static final int DEFAULT_TIMEOUT = 4000; - private CookieStore cookieStore = new BasicCookieStore(); - private CredentialsProvider provider = new BasicCredentialsProvider(); - private PoolingHttpClientConnectionManager connManager; - private RequestConfig defaultParams; - private HttpHost defaultProxy; - private int defaultTimeout; - private HttpClient client; - - public Download() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { - this(DEFAULT_TIMEOUT, null, null, DEFAULT_MAX_CONNECTIONS, true); - } - - public Download( - int defaultTimeout, - Map - defaultHeaders, - HttpHost defaultProxy, - int maxConnections, - boolean checkSsl - ) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { - Builder requestConfigBuilder = RequestConfig.custom() - .setConnectionRequestTimeout(defaultTimeout) - .setConnectTimeout(defaultTimeout) - .setSocketTimeout(defaultTimeout) - .setRedirectsEnabled(true); - this.defaultTimeout = defaultTimeout; - if (defaultProxy != null) { - //App.LOGGER.config("Starting download client with a proxy " + proxy); - requestConfigBuilder.setProxy(defaultProxy); - this.defaultProxy = defaultProxy; - } - defaultParams = requestConfigBuilder.build(); - - HttpClientBuilder httpClientBuilder = HttpClients.custom() - .setDefaultCredentialsProvider(provider) - .setDefaultRequestConfig(defaultParams) - .setDefaultCookieStore(cookieStore); - if (defaultHeaders != null) { - List
hs = new LinkedList
(); - for (Entry e : defaultHeaders.entrySet()) { - hs.add(new BasicHeader(e.getKey(), e.getValue())); - } - httpClientBuilder.setDefaultHeaders(hs); - } - SSLConnectionSocketFactory scsf = null; - if (!checkSsl) { - //System.out.println("Starting download client without checking ssl certificates"); - scsf = new SSLConnectionSocketFactory( - SSLContexts.custom() - .loadTrustMaterial(null, TrustAllStrategy.INSTANCE) - .build(), - NoopHostnameVerifier.INSTANCE - ); - httpClientBuilder.setSSLSocketFactory(scsf); - httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE); - httpClientBuilder.setSSLContext( - new SSLContextBuilder() - .loadTrustMaterial(null, TrustAllStrategy.INSTANCE) - .build() - ); - } else { - HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault()); - scsf = new SSLConnectionSocketFactory(SSLContexts.createDefault(), hostnameVerifier); - } - connManager = new PoolingHttpClientConnectionManager( - RegistryBuilder.create() - .register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", scsf) - .build(), - null, - null, - null, //DNS to null I suppose? - -1L, - TimeUnit.MILLISECONDS - ); - connManager.setDefaultMaxPerRoute(maxConnections); - connManager.setMaxTotal(maxConnections); - httpClientBuilder.setConnectionManager(connManager); - - client = httpClientBuilder.build(); - } - - public enum RequestMethod { - GET, - POST, - PATCH - } - - public static class Request { - private RequestMethod method = RequestMethod.GET; - private boolean redirectsDisabled; - private Map headers = new LinkedHashMap(); - private List bodyParams = new ArrayList(); - private Download originalDwn; - private HttpEntity body; - private HttpHost proxy; - private int timeout; - private String url; - - public Request(String url) { - this.url = url; - } - - public Request addHeaders(Map headers) { - if (headers != null) { - this.headers.putAll(headers); - } - return this; - } - - public Request setHeader(String name, String value) { - headers.put(name, value); - return this; - } - - public Request setBodyParam(String name, String value) { - bodyParams.add(new BasicNameValuePair(name, value)); - return this; - } - - public Request setBody(Object body) throws UnsupportedEncodingException { - switch (body) { - case String s -> setBodyString(s); - case byte[] bytes -> setBodyRaw(bytes); - case JSONObject jsonObject -> setJson(jsonObject); - case null, default -> throw new RuntimeException("Unsupported object type"); - } - return this; - } - - public Request setPostBody(Object body, ContentType contentType) { - switch (body) { - case String s -> setBodyString(s, contentType); - case byte[] bytes -> setBodyRaw(bytes, contentType); - case JSONObject jsonObject -> setJson(jsonObject, contentType); - case null, default -> throw new RuntimeException("Unsupported object type"); - } - return this; - } - - public Request setBodyString(String body) throws UnsupportedEncodingException { - this.body = new StringEntity(body); - return this; - } - - public Request setBodyString(String body, ContentType contentType) { - this.body = new StringEntity(body, contentType); - headers.put(HttpHeaders.CONTENT_TYPE, contentType.toString()); - return this; - } - - public Request setBodyRaw(byte[] body) { - this.body = new ByteArrayEntity(body, ContentType.APPLICATION_OCTET_STREAM); - //headers.put("Content-type", contentType.toString()); - return this; - } - - public Request setBodyRaw(byte[] body, ContentType contentType) { - this.body = new ByteArrayEntity(body, contentType); - //headers.put("Content-type", contentType.toString()); - return this; - } - - public Request setJson(JSONObject json) { - body = new StringEntity(json.toString(), ContentType.APPLICATION_JSON); - return this; - } - - public Request setJson(JSONObject json, ContentType contentType) { - body = new StringEntity(json.toString(), contentType); - return this; - } - - public Request setTimeout(int timeout) { - this.timeout = timeout; - return this; - } - - public Request setProxy(HttpHost proxy) { - this.proxy = proxy; - return this; - } - - public Request setGet() { - method = RequestMethod.GET; - return this; - } - - public Request setPost() { - method = RequestMethod.POST; - return this; - } - - public Request setPatch() { - method = RequestMethod.PATCH; - return this; - } - - public Request setMethod(RequestMethod method) { - this.method = method; - return this; - } - - public Request disableRedirects() { - redirectsDisabled = true; - return this; - } - - public Request enableRedirects() { - redirectsDisabled = false; - return this; - } - - private Request setOriginalDwn(Download dwn) { - timeout = dwn.defaultTimeout; - originalDwn = dwn; - return this; - } - - public Response go() throws IOException { - return switch (method) { - case GET -> originalDwn.get(this); - case POST -> originalDwn.post(this); - case PATCH -> originalDwn.patch(this); - }; - } - - private void setHeaders(HttpRequestBase request) { - for (Entry e : headers.entrySet()) { - request.setHeader(e.getKey(), e.getValue()); - } - } - - private HttpEntity getEntity() throws UnsupportedEncodingException { - if (body != null) { - return body; - } - return new UrlEncodedFormEntity(bodyParams, "UTF-8"); - } - } - - @ToString - public static class Response { - private int respCode; - private ArrayList
respHeaders = new ArrayList
(); - private byte[] response; - private String respStr; - private String landingUrl; - private JSONObject respJson; - - private Response(HttpResponse response, HttpEntity responseEntity) throws IOException { - respCode = response.getStatusLine().getStatusCode(); - setResponseBody(responseEntity); - setHeaders(response.getAllHeaders()); - } - - public int getStatusCode() { - return respCode; - } - - public String getHeader(String name) { - return getHeader(name, 0); - } - - public String getHeader(String name, int headerNo) { - int found = 0; - for (Header h : respHeaders) { - if (h.getName().equalsIgnoreCase(name)) { - if (found++ == headerNo) { - return h.getValue(); - } - } - } - return null; - } - - public String getLandingUrl() { - return landingUrl; - } - - public byte[] getResponseRaw() { - return response; - } - - public String getResponse() { - if (respStr == null) { - respStr = new String(response); - } - return respStr; - } - - public JSONObject getResponseJson() { - if (respJson == null) { - respJson = new JSONObject(getResponse()); - } - return respJson; - } - - private void setHeaders(Header[] headers) { - for (Header h : headers) { - respHeaders.add(h); - } - } - - private void setResponseBody(HttpEntity resp) throws IOException { - response = EntityUtils.toByteArray(resp); - EntityUtils.consume(resp); - } - } - - private Response doRequest(Request req, HttpRequestBase httpReq) throws IOException { - boolean updateTimeout = req.timeout != defaultTimeout; - boolean updateProxy = req.proxy != null && !Objects.equals(req.proxy, defaultProxy); - if (updateTimeout || updateProxy || req.redirectsDisabled) { - Builder requestConfigBuilder = RequestConfig.custom(); - if (updateTimeout) { - requestConfigBuilder.setConnectionRequestTimeout(req.timeout) - .setConnectTimeout(req.timeout) - .setSocketTimeout(req.timeout); - } - if (updateProxy) { - requestConfigBuilder.setProxy(req.proxy); - } - if (req.redirectsDisabled) { - requestConfigBuilder.setRedirectsEnabled(false); - } - httpReq.setConfig(requestConfigBuilder.build()); - } - req.setHeaders(httpReq); - HttpContext context = new BasicHttpContext(); - HttpResponse response = client.execute(httpReq, context); - HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST); - HttpHost currentHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); - String currentUrl = (currentReq.getURI().isAbsolute()) - ? currentReq.getURI().toString() - : (currentHost.toURI() + currentReq.getURI()); - HttpEntity entity = response.getEntity(); - if (entity != null) { - Response resp = new Response(response, entity); - resp.landingUrl = currentUrl; - httpReq.releaseConnection(); - return resp; - } - return null; - } - - public Request get(String url) { - return new Request(url).setGet().setOriginalDwn(this); - } - - public Response get(Request req) throws IOException { - HttpGet httpGet = new HttpGet(req.url); - return doRequest(req, httpGet); - } - - public Request post(String url) { - return new Request(url).setPost().setOriginalDwn(this); - } - - public Response post(Request req) throws IOException { - HttpPost httpPost = new HttpPost(req.url); - httpPost.setEntity(req.getEntity()); - return doRequest(req, httpPost); - } - - public Request patch(String url) { - return new Request(url).setPatch().setOriginalDwn(this); - } - - public Response patch(Request req) throws IOException { - HttpPatch httpPatch = new HttpPatch(req.url); - httpPatch.setEntity(req.getEntity()); - return doRequest(req, httpPatch); - } - - public Download setLogin(String username, String password) { - provider.setCredentials( - AuthScope.ANY, - new UsernamePasswordCredentials(username, password) - ); - return this; - } - - public Download setCookie(String key, String value, String domain, String path) { - BasicClientCookie cookie = new BasicClientCookie(key, value); - cookie.setPath(path); - cookie.setDomain(domain); - cookieStore.addCookie(cookie); - return this; - } - - public String getCookie(String name) { - return getCookieObj(name, 0).getValue(); - } - - public Cookie getCookieObj(String name, int cookieNo) { - List cookies = cookieStore.getCookies(); - int found = 0; - for (Cookie c : cookies) { - if (c.getName().equalsIgnoreCase(name)) { - if (found++ == cookieNo) { - return c; - } - } - } - return null; - } - - public List getCookies() { - return new ArrayList(cookieStore.getCookies()); - } - - @SuppressWarnings("unused") - private static void copyright() { - System.out.println("Download engine made by https://stranck.ovh (c)\n" - + "\n" - + "Need help? Contact me!\n" - + "Telegram channel: https://t.me/Stranck\n" - + "Telegram user: https://t.me/LucaStranck\n" - + "YouTube channel: https://www.youtube.com/channel/UCmMWUz0QZ7WhIBx-1Dz-IGg\n" - + "Twitter: https://twitter.com/LStranck https://twitter.com/stranckV2\n" - + "Instagram: https://www.instagram.com/stranck/\n" - + "Github: https://github.com/stranck\n" - + "Pastebin: https://pastebin.com/u/Stranck\n"); - } -} \ No newline at end of file diff --git a/application/src/main/java/net/furizon/backend/utils/SecurityUtil.java b/application/src/main/java/net/furizon/backend/utils/SecurityUtil.java index 62ed57a..f454f5c 100644 --- a/application/src/main/java/net/furizon/backend/utils/SecurityUtil.java +++ b/application/src/main/java/net/furizon/backend/utils/SecurityUtil.java @@ -1,28 +1,28 @@ package net.furizon.backend.utils; -import lombok.extern.slf4j.Slf4j; -import net.furizon.backend.db.entities.users.User; +/*import lombok.extern.slf4j.Slf4j; +import net.furizon.backend.db.entities.users.DeprUser; import net.furizon.backend.infrastructure.web.exception.ApiException; import org.springframework.http.HttpStatus; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; -import java.util.Optional; +import java.util.Optional;*/ -@Slf4j +//@Slf4j public class SecurityUtil { - private static final SecurityContextRepository securityContextRepository = + /*private static final SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository(); /** * Get the authenticated user from the SecurityContextHolder * * @throws ApiException if the user is not found in the SecurityContextHolder - */ - public static User getAuthenticatedUser() { + *//* + public static DeprUser getAuthenticatedUser() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - if (principal instanceof User user) { + if (principal instanceof DeprUser user) { return user; } else { log.error("User requested but not found in SecurityContextHolder"); @@ -33,12 +33,12 @@ public static User getAuthenticatedUser() { } } - public static Optional getOptionalAuthenticatedUser() { + public static Optional getOptionalAuthenticatedUser() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - if (principal instanceof User user) { + if (principal instanceof DeprUser user) { return Optional.of(user); } else { return Optional.empty(); } - } + }*/ } diff --git a/application/src/main/java/net/furizon/backend/utils/TextUtil.java b/application/src/main/java/net/furizon/backend/utils/TextUtil.java deleted file mode 100644 index 7ae1e47..0000000 --- a/application/src/main/java/net/furizon/backend/utils/TextUtil.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.furizon.backend.utils; - -public class TextUtil { - public static String leadingSlash(String input) { - return Character.valueOf(input.charAt(input.length() - 1)).equals('/') ? input : input + "/"; - } - - public static boolean isEmpty(String value) { - return value == null || value.trim().isEmpty(); - } -} diff --git a/application/src/main/java/net/furizon/backend/utils/ThrowableSupplier.java b/application/src/main/java/net/furizon/backend/utils/ThrowableSupplier.java deleted file mode 100644 index 56b198b..0000000 --- a/application/src/main/java/net/furizon/backend/utils/ThrowableSupplier.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.furizon.backend.utils; - -@FunctionalInterface -public interface ThrowableSupplier { - T get() throws E; -} diff --git a/application/src/main/java/net/furizon/backend/utils/pretix/Constants.java b/application/src/main/java/net/furizon/backend/utils/pretix/Constants.java deleted file mode 100644 index d76c812..0000000 --- a/application/src/main/java/net/furizon/backend/utils/pretix/Constants.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.furizon.backend.utils.pretix; - -// TODO -> Remove it later -@Deprecated -public class Constants { - public static final String METADATA_IDENTIFIER_ITEM = "item_name"; - //public static final String METADATA_CATEGORY_IDENTIFIER = "category_name"; - - //public static final String CATEGORY_TICKETS = "tickets"; - //public static final String CATEGORY_MEMBERSHIPS = "memberships"; - //public static final String CATEGORY_SPONSORSHIPS = "sponsorships"; - - - public static final String METADATA_EVENT_TICKET = "ticket"; - public static final String METADATA_EVENT_TICKET_DAILY_TAG_PREFIX = "ticket_daily_"; - - public static final String METADATA_MEMBERSHIP_CARD = "membership_card"; - - public static final String METADATA_SPONSORSHIP = "sponsorship"; - public static final String METADATA_SPONSORSHIP_VARIATIONS_TAG_PREFIX = "sponsorship_type_"; - - public static final String METADATA_EXTRA_DAYS_TAG_PREFIX = "extra_days_"; - - public static final String METADATA_ROOM = "room"; - public static final String METADATA_ROOM_TYPE_TAG_PREFIX = "room_type_"; - - public static final String QUESTIONS_ACCOUNT_SECRET = "account_secret"; - - public static final String QUESTIONS_FILE_KEEP = "file:keep"; - - // Why? you have Spring Http Codes Class :) - public static final int[] STATUS_CODES_WITH_404 = new int[]{200, 404}; - public static final int[] STATUS_CODES_ONLY_200 = new int[]{200}; - public static final int[] STATUS_CODES_FILE_UPLOAD = new int[]{201}; -} diff --git a/application/src/main/resources/application.properties.example b/application/src/main/resources/application.properties.example deleted file mode 100644 index 4a71a05..0000000 --- a/application/src/main/resources/application.properties.example +++ /dev/null @@ -1,9 +0,0 @@ -spring.application.name=backend -spring.datasource.url=jdbc:postgresql://localhost:5432/db -spring.datasource.username=userr -spring.datasource.password=pass -spring.jpa.hibernate.ddl-auto=update -spring.datasource.driver-class-name=org.postgresql.Driver -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect -server.servlet.context-path=/api/v1 -#logging.level.org.springframework.security=DEBUG \ No newline at end of file diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index 8863032..2a4215f 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -2,6 +2,8 @@ server: port: ${BACKEND_SERVER_PORT:9090} spring: + jpa: + open-in-view: false application: name: fz-backend datasource: @@ -21,7 +23,7 @@ logbook: pretix: url: ${PRETIX_BASE_URL:http://localhost:8000} apiPath: ${PRETIX_API_PATH:/api/v1/} - api-key: ${PRETIX_API_KEY:zcz7tfhipd6t3i51pf29vgrpbstab19r4wtlv5r464sasdknxzo7nk6c4ixxnmg2} + api-key: ${PRETIX_API_KEY:OwO} default-organizer: ${PRETIX_DEFAULT_ORGANIZER:org} - default-event: ${PRETIX_DEFAULT_EVENT:org} + default-event: ${PRETIX_DEFAULT_EVENT:event} connection-timeout: ${PRETIX_HTTP_CLIENT_CONNECTION_TIMEOUT:10000} diff --git a/checkstyle.xml b/checkstyle.xml index ccb4322..2053320 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -156,8 +156,8 @@ @@ -189,7 +189,7 @@ - + diff --git a/db/migrations/000001_model.up.sql b/db/migrations/000001_model.up.sql index 0da7fcc..0aea8fe 100644 --- a/db/migrations/000001_model.up.sql +++ b/db/migrations/000001_model.up.sql @@ -1,146 +1,162 @@ -CREATE TABLE IF NOT EXISTS events ( - event_slug varchar(255) NOT NULL, - event_date_end varchar(32) NULL, -- Probable better to use timestamp type -- - event_date_from varchar(32) NULL, -- Probable better to use timestamp type -- - event_is_current bool NULL, - event_public_url text NULL, - event_names text NULL, - CONSTRAINT events_pkey PRIMARY KEY (event_slug) +CREATE TABLE IF NOT EXISTS events +( + event_slug varchar(255) NOT NULL, + event_date_to varchar(32) NULL, -- Probable better to use timestamp type -- + event_date_from varchar(32) NULL, -- Probable better to use timestamp type -- + event_is_current bool NOT NULL, + event_public_url text NOT NULL, + event_names text NULL, + CONSTRAINT events_pkey PRIMARY KEY (event_slug) ); -CREATE TABLE IF NOT EXISTS "groups" ( - group_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - group_name varchar(255) NOT NULL, - CONSTRAINT groups_pkey PRIMARY KEY (group_id) +CREATE TABLE IF NOT EXISTS "groups" +( + group_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + group_name varchar(255) NOT NULL, + CONSTRAINT groups_pkey PRIMARY KEY (group_id) ); -CREATE TABLE IF NOT EXISTS media ( - media_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - media_path text NULL, - media_type varchar(255) NULL, - CONSTRAINT media_pkey PRIMARY KEY (media_id) +CREATE TABLE IF NOT EXISTS media +( + media_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + media_path text NULL, + media_type varchar(255) NULL, + CONSTRAINT media_pkey PRIMARY KEY (media_id) ); -CREATE TABLE IF NOT EXISTS group_permissions ( - group_id int8 NOT NULL, - permission_code text NOT NULL, - CONSTRAINT group_permissions_pk PRIMARY KEY (permission_code, group_id) +CREATE TABLE IF NOT EXISTS group_permissions +( + group_id int8 NOT NULL, + permission_code text NOT NULL, + CONSTRAINT group_permissions_pk PRIMARY KEY (permission_code, group_id) ); -CREATE TABLE IF NOT EXISTS users ( - user_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - user_fursona_name varchar(64) NULL, - user_locale varchar(8) DEFAULT 'en-us'::character varying NULL, - user_secret varchar(70) NOT NULL, - media_id_propic int8 NULL, - CONSTRAINT users_pkey PRIMARY KEY (user_id), - CONSTRAINT users_unique_secret UNIQUE (user_secret), - CONSTRAINT user_media_fk FOREIGN KEY (media_id_propic) REFERENCES media(media_id) +CREATE TABLE IF NOT EXISTS users +( + user_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + user_fursona_name varchar(64) NULL, + user_locale varchar(8) DEFAULT 'en-us'::character varying NULL, + user_secret varchar(70) NOT NULL, + media_id_propic int8 NULL, + CONSTRAINT users_pkey PRIMARY KEY (user_id), + CONSTRAINT users_unique_secret UNIQUE (user_secret), + CONSTRAINT user_media_fk FOREIGN KEY (media_id_propic) REFERENCES media (media_id) ); -CREATE TABLE IF NOT EXISTS authentications ( - authentication_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - authentication_email varchar(255) NOT NULL, - authentication_email_verified bool NULL, - authentication_2fa_enabled bool NULL, - authentication_disabled bool NULL, - authentication_expired bool NULL, - authentication_from_oauth bool NULL, - authentication_password text NOT NULL, - authentication_token varchar(255) NULL, - user_id int8 NULL, - CONSTRAINT authentications_pkey PRIMARY KEY (authentication_id), - CONSTRAINT authentications_unique_email UNIQUE (authentication_email), - CONSTRAINT authentications_unique_user_id UNIQUE (user_id), - CONSTRAINT authentications_users_fk FOREIGN KEY (user_id) REFERENCES users(user_id) +CREATE TABLE IF NOT EXISTS authentications +( + authentication_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + authentication_email varchar(255) NOT NULL, + authentication_email_verified bool NULL, + authentication_2fa_enabled bool NULL, + authentication_disabled bool NULL, + authentication_expired bool NULL, + authentication_from_oauth bool NULL, + authentication_password text NOT NULL, + authentication_token varchar(255) NULL, + user_id int8 NULL, + CONSTRAINT authentications_pkey PRIMARY KEY (authentication_id), + CONSTRAINT authentications_unique_email UNIQUE (authentication_email), + CONSTRAINT authentications_unique_user_id UNIQUE (user_id), + CONSTRAINT authentications_users_fk FOREIGN KEY (user_id) REFERENCES users (user_id) ); -CREATE TABLE IF NOT EXISTS membership_info ( - user_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - info_first_name text NULL, - info_last_name text NULL, - info_address text NULL, - info_zip varchar(16) NULL, - info_city text NULL, - info_country text NULL, - info_tax_id varchar(16) NULL, - info_birth_city text NULL, - info_birth_region text NULL, - info_birth_country text NULL, - info_region text NULL, - info_phone text NULL, - CONSTRAINT membership_info_id_pkey PRIMARY KEY (user_id), - CONSTRAINT membership_info_users_fk FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE +CREATE TABLE IF NOT EXISTS membership_info +( + user_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + info_first_name text NULL, + info_last_name text NULL, + info_address text NULL, + info_zip varchar(16) NULL, + info_city text NULL, + info_country text NULL, + info_tax_id varchar(16) NULL, + info_birth_city text NULL, + info_birth_region text NULL, + info_birth_country text NULL, + info_region text NULL, + info_phone text NULL, + CONSTRAINT membership_info_id_pkey PRIMARY KEY (user_id), + CONSTRAINT membership_info_users_fk FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE ); -CREATE TABLE IF NOT EXISTS fursuits ( - fursuit_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - fursuit_name varchar(255) NULL, - fursuit_species varchar(255) NULL, - user_id int8 NULL, - media_id_propic int8 NULL, - CONSTRAINT fursuits_pkey PRIMARY KEY (fursuit_id), - CONSTRAINT fursuits_media_fk FOREIGN KEY (media_id_propic) REFERENCES media(media_id), - CONSTRAINT fursuits_users_fk FOREIGN KEY (user_id) REFERENCES users(user_id) +CREATE TABLE IF NOT EXISTS fursuits +( + fursuit_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + fursuit_name varchar(255) NULL, + fursuit_species varchar(255) NULL, + user_id int8 NULL, + media_id_propic int8 NULL, + CONSTRAINT fursuits_pkey PRIMARY KEY (fursuit_id), + CONSTRAINT fursuits_media_fk FOREIGN KEY (media_id_propic) REFERENCES media (media_id), + CONSTRAINT fursuits_users_fk FOREIGN KEY (user_id) REFERENCES users (user_id) ); -CREATE TABLE IF NOT EXISTS fursuits_events ( - event_id int8 NOT NULL, - fursuit_id int8 NOT NULL, - CONSTRAINT fursuits_events_pk PRIMARY KEY (event_id, fursuit_id), - CONSTRAINT fursuits_events_event_fk FOREIGN KEY (event_id) REFERENCES media(media_id), - CONSTRAINT fursuits_events_fursuit_fk FOREIGN KEY (fursuit_id) REFERENCES fursuits(fursuit_id) +CREATE TABLE IF NOT EXISTS fursuits_events +( + event_id int8 NOT NULL, + fursuit_id int8 NOT NULL, + CONSTRAINT fursuits_events_pk PRIMARY KEY (event_id, fursuit_id), + CONSTRAINT fursuits_events_event_fk FOREIGN KEY (event_id) REFERENCES media (media_id), + CONSTRAINT fursuits_events_fursuit_fk FOREIGN KEY (fursuit_id) REFERENCES fursuits (fursuit_id) ); -CREATE TABLE IF NOT EXISTS membership_cards ( - card_db_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - card_year int2 NOT NULL, - user_id int8 NOT NULL, - CONSTRAINT cards_pkey PRIMARY KEY (card_db_id), - CONSTRAINT card_user_fk FOREIGN KEY (user_id) REFERENCES users(user_id) +CREATE TABLE IF NOT EXISTS membership_cards +( + card_db_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + card_year int2 NOT NULL, + user_id int8 NOT NULL, + CONSTRAINT cards_pkey PRIMARY KEY (card_db_id), + CONSTRAINT card_user_fk FOREIGN KEY (user_id) REFERENCES users (user_id) ); -CREATE TABLE IF NOT EXISTS orders ( - order_code varchar(64) NOT NULL, - order_answers text NULL, - order_status int2 DEFAULT 0 NOT NULL, - order_answers_main_position_id int4 NOT NULL, - order_daily_days int8 NOT NULL, - order_extra_days_type int2 NULL, - has_membership bool NOT NULL, - order_secret varchar(32) NULL, - order_sponsorship_type int2 NULL, - event_id varchar(255) NULL, - user_id int8 NULL, - CONSTRAINT orders_extra_days_check CHECK (((order_extra_days_type >= 0) AND (order_extra_days_type <= 3))), - CONSTRAINT orders_pkey PRIMARY KEY (order_code), - CONSTRAINT orders_sponsorship_check CHECK (((order_sponsorship_type >= 0) AND (order_sponsorship_type <= 2))), - CONSTRAINT orders_status_check CHECK (((order_status >= 0) AND (order_status <= 3))), - CONSTRAINT orders_events_id FOREIGN KEY (event_id) REFERENCES events(event_slug), - CONSTRAINT orders_users_id FOREIGN KEY (user_id) REFERENCES users(user_id) +CREATE TABLE IF NOT EXISTS orders +( + order_code varchar(64) NOT NULL, + order_answers_json json NULL, + order_status int2 DEFAULT 0 NOT NULL, + order_answers_main_position_id int4 NOT NULL, + order_daily_days int8 NOT NULL, + order_extra_days_type int2 NULL, + order_room_capacity int2 NULL, + order_hotel_location varchar(255), + has_membership bool NOT NULL, + order_secret varchar(32) NULL, + order_sponsorship_type int2 NULL, + event_id varchar(255) NULL, + user_id int8 NULL, + CONSTRAINT orders_extra_days_check CHECK (((order_extra_days_type >= 0) AND (order_extra_days_type <= 3))), + CONSTRAINT orders_pkey PRIMARY KEY (order_code), + CONSTRAINT orders_sponsorship_check CHECK (((order_sponsorship_type >= 0) AND (order_sponsorship_type <= 2))), + CONSTRAINT orders_status_check CHECK (((order_status >= 0) AND (order_status <= 3))), + CONSTRAINT orders_events_id FOREIGN KEY (event_id) REFERENCES events (event_slug), + CONSTRAINT orders_users_id FOREIGN KEY (user_id) REFERENCES users (user_id) ); -CREATE TABLE IF NOT EXISTS rooms ( - room_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - room_confirmed bool NULL, - room_name varchar(255) NULL, - order_id varchar(64) NULL, - CONSTRAINT rooms_pkey PRIMARY KEY (room_id), - CONSTRAINT rooms_orders_id FOREIGN KEY (order_id) REFERENCES orders(order_code) +CREATE TABLE IF NOT EXISTS rooms +( + room_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + room_confirmed bool NULL, + room_name varchar(255) NULL, + order_id varchar(64) NULL, + CONSTRAINT rooms_pkey PRIMARY KEY (room_id), + CONSTRAINT rooms_orders_id FOREIGN KEY (order_id) REFERENCES orders (order_code) ); -CREATE TABLE IF NOT EXISTS user_group ( - group_id int8 NULL, - user_id int8 NULL, - CONSTRAINT user_group_groups_fk FOREIGN KEY (group_id) REFERENCES "groups"(group_id), - CONSTRAINT user_group_users_fk FOREIGN KEY (user_id) REFERENCES users(user_id) +CREATE TABLE IF NOT EXISTS user_group +( + group_id int8 NULL, + user_id int8 NULL, + CONSTRAINT user_group_groups_fk FOREIGN KEY (group_id) REFERENCES "groups" (group_id), + CONSTRAINT user_group_users_fk FOREIGN KEY (user_id) REFERENCES users (user_id) ); -CREATE TABLE IF NOT EXISTS room_guests ( - room_guest_id int8 GENERATED BY DEFAULT AS IDENTITY( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, - user_id int8 NULL, - room_id int8 NULL, - CONSTRAINT room_guests_pkey PRIMARY KEY (room_guest_id), - CONSTRAINT room_guests_rooms_fk FOREIGN KEY (room_id) REFERENCES rooms(room_id), - CONSTRAINT room_guests_users_fk FOREIGN KEY (user_id) REFERENCES users(user_id) +CREATE TABLE IF NOT EXISTS room_guests +( + room_guest_id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL, + user_id int8 NULL, + room_id int8 NULL, + CONSTRAINT room_guests_pkey PRIMARY KEY (room_guest_id), + CONSTRAINT room_guests_rooms_fk FOREIGN KEY (room_id) REFERENCES rooms (room_id), + CONSTRAINT room_guests_users_fk FOREIGN KEY (user_id) REFERENCES users (user_id) ); \ No newline at end of file diff --git a/jooq-common/pom.xml b/jooq-common/pom.xml index 9cb6e7d..10c58bb 100644 --- a/jooq-common/pom.xml +++ b/jooq-common/pom.xml @@ -16,6 +16,7 @@ jdbc:postgresql://localhost:5433/postgres postgres postgres + false @@ -65,7 +66,7 @@ ${jooq.codegen.username} ${jooq.codegen.password} - + ${jooq.codegen.skip} org.jooq.codegen.JavaGenerator diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/Keys.java b/jooq-common/src/main/java/net/furizon/jooq/generated/Keys.java index cd4f71f..62e8668 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/Keys.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/Keys.java @@ -13,14 +13,12 @@ import net.furizon.jooq.generated.tables.GroupPermissions; import net.furizon.jooq.generated.tables.Groups; import net.furizon.jooq.generated.tables.Media; -import net.furizon.jooq.generated.tables.MediaTags; import net.furizon.jooq.generated.tables.MembershipCards; import net.furizon.jooq.generated.tables.MembershipInfo; import net.furizon.jooq.generated.tables.Orders; import net.furizon.jooq.generated.tables.RoomGuests; import net.furizon.jooq.generated.tables.Rooms; import net.furizon.jooq.generated.tables.SchemaMigrations; -import net.furizon.jooq.generated.tables.Tags; import net.furizon.jooq.generated.tables.UserGroup; import net.furizon.jooq.generated.tables.Users; @@ -55,20 +53,16 @@ public class Keys { public static final UniqueKey AUTHENTICATIONS_UNIQUE_USER_ID = Internal.createUniqueKey(Authentications.AUTHENTICATIONS, DSL.name("authentications_unique_user_id"), new TableField[] { Authentications.AUTHENTICATIONS.USER_ID }, true); public static final UniqueKey EVENTS_PKEY = Internal.createUniqueKey(Events.EVENTS, DSL.name("events_pkey"), new TableField[] { Events.EVENTS.EVENT_SLUG }, true); public static final UniqueKey FURSUITS_PKEY = Internal.createUniqueKey(Fursuits.FURSUITS, DSL.name("fursuits_pkey"), new TableField[] { Fursuits.FURSUITS.FURSUIT_ID }, true); - public static final UniqueKey UK47Y138Q5E9DQWRWTJWI5OVLMW = Internal.createUniqueKey(Fursuits.FURSUITS, DSL.name("uk47y138q5e9dqwrwtjwi5ovlmw"), new TableField[] { Fursuits.FURSUITS.MEDIA_ID }, true); public static final UniqueKey FURSUITS_EVENTS_PK = Internal.createUniqueKey(FursuitsEvents.FURSUITS_EVENTS, DSL.name("fursuits_events_pk"), new TableField[] { FursuitsEvents.FURSUITS_EVENTS.EVENT_ID, FursuitsEvents.FURSUITS_EVENTS.FURSUIT_ID }, true); public static final UniqueKey GROUP_PERMISSIONS_PK = Internal.createUniqueKey(GroupPermissions.GROUP_PERMISSIONS, DSL.name("group_permissions_pk"), new TableField[] { GroupPermissions.GROUP_PERMISSIONS.PERMISSION_CODE, GroupPermissions.GROUP_PERMISSIONS.GROUP_ID }, true); public static final UniqueKey GROUPS_PKEY = Internal.createUniqueKey(Groups.GROUPS, DSL.name("groups_pkey"), new TableField[] { Groups.GROUPS.GROUP_ID }, true); public static final UniqueKey MEDIA_PKEY = Internal.createUniqueKey(Media.MEDIA, DSL.name("media_pkey"), new TableField[] { Media.MEDIA.MEDIA_ID }, true); - public static final UniqueKey MEDIA_TAGS_PKEY = Internal.createUniqueKey(MediaTags.MEDIA_TAGS, DSL.name("media_tags_pkey"), new TableField[] { MediaTags.MEDIA_TAGS.MEDIA_TAG_ID }, true); public static final UniqueKey CARDS_PKEY = Internal.createUniqueKey(MembershipCards.MEMBERSHIP_CARDS, DSL.name("cards_pkey"), new TableField[] { MembershipCards.MEMBERSHIP_CARDS.CARD_DB_ID }, true); public static final UniqueKey MEMBERSHIP_INFO_ID_PKEY = Internal.createUniqueKey(MembershipInfo.MEMBERSHIP_INFO, DSL.name("membership_info_id_pkey"), new TableField[] { MembershipInfo.MEMBERSHIP_INFO.USER_ID }, true); public static final UniqueKey ORDERS_PKEY = Internal.createUniqueKey(Orders.ORDERS, DSL.name("orders_pkey"), new TableField[] { Orders.ORDERS.ORDER_CODE }, true); public static final UniqueKey ROOM_GUESTS_PKEY = Internal.createUniqueKey(RoomGuests.ROOM_GUESTS, DSL.name("room_guests_pkey"), new TableField[] { RoomGuests.ROOM_GUESTS.ROOM_GUEST_ID }, true); public static final UniqueKey ROOMS_PKEY = Internal.createUniqueKey(Rooms.ROOMS, DSL.name("rooms_pkey"), new TableField[] { Rooms.ROOMS.ROOM_ID }, true); public static final UniqueKey SCHEMA_MIGRATIONS_PKEY = Internal.createUniqueKey(SchemaMigrations.SCHEMA_MIGRATIONS, DSL.name("schema_migrations_pkey"), new TableField[] { SchemaMigrations.SCHEMA_MIGRATIONS.VERSION }, true); - public static final UniqueKey TAGS_PKEY = Internal.createUniqueKey(Tags.TAGS, DSL.name("tags_pkey"), new TableField[] { Tags.TAGS.TAG_ID }, true); - public static final UniqueKey UKRLLOBBOR6YGDSIT4DSVACBD90 = Internal.createUniqueKey(Tags.TAGS, DSL.name("ukrllobbor6ygdsit4dsvacbd90"), new TableField[] { Tags.TAGS.TAG_CODE }, true); public static final UniqueKey USERS_PKEY = Internal.createUniqueKey(Users.USERS, DSL.name("users_pkey"), new TableField[] { Users.USERS.USER_ID }, true); public static final UniqueKey USERS_UNIQUE_SECRET = Internal.createUniqueKey(Users.USERS, DSL.name("users_unique_secret"), new TableField[] { Users.USERS.USER_SECRET }, true); @@ -77,14 +71,10 @@ public class Keys { // ------------------------------------------------------------------------- public static final ForeignKey AUTHENTICATIONS__AUTHENTICATIONS_USERS_FK = Internal.createForeignKey(Authentications.AUTHENTICATIONS, DSL.name("authentications_users_fk"), new TableField[] { Authentications.AUTHENTICATIONS.USER_ID }, Keys.USERS_PKEY, new TableField[] { Users.USERS.USER_ID }, true); - public static final ForeignKey FURSUITS__FKOM4XAJCQUVF8OUNSRELSW3A2O = Internal.createForeignKey(Fursuits.FURSUITS, DSL.name("fkom4xajcquvf8ounsrelsw3a2o"), new TableField[] { Fursuits.FURSUITS.MEDIA_ID }, Keys.MEDIA_PKEY, new TableField[] { Media.MEDIA.MEDIA_ID }, true); public static final ForeignKey FURSUITS__FURSUITS_MEDIA_FK = Internal.createForeignKey(Fursuits.FURSUITS, DSL.name("fursuits_media_fk"), new TableField[] { Fursuits.FURSUITS.MEDIA_ID_PROPIC }, Keys.MEDIA_PKEY, new TableField[] { Media.MEDIA.MEDIA_ID }, true); public static final ForeignKey FURSUITS__FURSUITS_USERS_FK = Internal.createForeignKey(Fursuits.FURSUITS, DSL.name("fursuits_users_fk"), new TableField[] { Fursuits.FURSUITS.USER_ID }, Keys.USERS_PKEY, new TableField[] { Users.USERS.USER_ID }, true); public static final ForeignKey FURSUITS_EVENTS__FURSUITS_EVENTS_EVENT_FK = Internal.createForeignKey(FursuitsEvents.FURSUITS_EVENTS, DSL.name("fursuits_events_event_fk"), new TableField[] { FursuitsEvents.FURSUITS_EVENTS.EVENT_ID }, Keys.MEDIA_PKEY, new TableField[] { Media.MEDIA.MEDIA_ID }, true); public static final ForeignKey FURSUITS_EVENTS__FURSUITS_EVENTS_FURSUIT_FK = Internal.createForeignKey(FursuitsEvents.FURSUITS_EVENTS, DSL.name("fursuits_events_fursuit_fk"), new TableField[] { FursuitsEvents.FURSUITS_EVENTS.FURSUIT_ID }, Keys.FURSUITS_PKEY, new TableField[] { Fursuits.FURSUITS.FURSUIT_ID }, true); - public static final ForeignKey MEDIA__FKND8HH0YN7QVV4PQYK8MG7L1OX = Internal.createForeignKey(Media.MEDIA, DSL.name("fknd8hh0yn7qvv4pqyk8mg7l1ox"), new TableField[] { Media.MEDIA.USER_ID }, Keys.USERS_PKEY, new TableField[] { Users.USERS.USER_ID }, true); - public static final ForeignKey MEDIA_TAGS__FK88C8WCOPLIS4O99Y53CCN21GT = Internal.createForeignKey(MediaTags.MEDIA_TAGS, DSL.name("fk88c8wcoplis4o99y53ccn21gt"), new TableField[] { MediaTags.MEDIA_TAGS.MEDIA_ID }, Keys.MEDIA_PKEY, new TableField[] { Media.MEDIA.MEDIA_ID }, true); - public static final ForeignKey MEDIA_TAGS__FKFGINODY5NX4QLTQEY6C6S16LT = Internal.createForeignKey(MediaTags.MEDIA_TAGS, DSL.name("fkfginody5nx4qltqey6c6s16lt"), new TableField[] { MediaTags.MEDIA_TAGS.TAG_ID }, Keys.TAGS_PKEY, new TableField[] { Tags.TAGS.TAG_ID }, true); public static final ForeignKey MEMBERSHIP_CARDS__CARD_USER_FK = Internal.createForeignKey(MembershipCards.MEMBERSHIP_CARDS, DSL.name("card_user_fk"), new TableField[] { MembershipCards.MEMBERSHIP_CARDS.USER_ID }, Keys.USERS_PKEY, new TableField[] { Users.USERS.USER_ID }, true); public static final ForeignKey MEMBERSHIP_INFO__MEMBERSHIP_INFO_USERS_FK = Internal.createForeignKey(MembershipInfo.MEMBERSHIP_INFO, DSL.name("membership_info_users_fk"), new TableField[] { MembershipInfo.MEMBERSHIP_INFO.USER_ID }, Keys.USERS_PKEY, new TableField[] { Users.USERS.USER_ID }, true); public static final ForeignKey ORDERS__ORDERS_EVENTS_ID = Internal.createForeignKey(Orders.ORDERS, DSL.name("orders_events_id"), new TableField[] { Orders.ORDERS.EVENT_ID }, Keys.EVENTS_PKEY, new TableField[] { Events.EVENTS.EVENT_SLUG }, true); diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/Public.java b/jooq-common/src/main/java/net/furizon/jooq/generated/Public.java index 35c636e..0e8d94b 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/Public.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/Public.java @@ -16,14 +16,12 @@ import net.furizon.jooq.generated.tables.GroupPermissions; import net.furizon.jooq.generated.tables.Groups; import net.furizon.jooq.generated.tables.Media; -import net.furizon.jooq.generated.tables.MediaTags; import net.furizon.jooq.generated.tables.MembershipCards; import net.furizon.jooq.generated.tables.MembershipInfo; import net.furizon.jooq.generated.tables.Orders; import net.furizon.jooq.generated.tables.RoomGuests; import net.furizon.jooq.generated.tables.Rooms; import net.furizon.jooq.generated.tables.SchemaMigrations; -import net.furizon.jooq.generated.tables.Tags; import net.furizon.jooq.generated.tables.UserGroup; import net.furizon.jooq.generated.tables.Users; @@ -87,11 +85,6 @@ public class Public extends SchemaImpl { */ public final Media MEDIA = Media.MEDIA; - /** - * The table public.media_tags. - */ - public final MediaTags MEDIA_TAGS = MediaTags.MEDIA_TAGS; - /** * The table public.membership_cards. */ @@ -122,11 +115,6 @@ public class Public extends SchemaImpl { */ public final SchemaMigrations SCHEMA_MIGRATIONS = SchemaMigrations.SCHEMA_MIGRATIONS; - /** - * The table public.tags. - */ - public final Tags TAGS = Tags.TAGS; - /** * The table public.user_group. */ @@ -160,14 +148,12 @@ public final List> getTables() { GroupPermissions.GROUP_PERMISSIONS, Groups.GROUPS, Media.MEDIA, - MediaTags.MEDIA_TAGS, MembershipCards.MEMBERSHIP_CARDS, MembershipInfo.MEMBERSHIP_INFO, Orders.ORDERS, RoomGuests.ROOM_GUESTS, Rooms.ROOMS, SchemaMigrations.SCHEMA_MIGRATIONS, - Tags.TAGS, UserGroup.USER_GROUP, Users.USERS ); diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/Tables.java b/jooq-common/src/main/java/net/furizon/jooq/generated/Tables.java index a369428..be98976 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/Tables.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/Tables.java @@ -13,14 +13,12 @@ import net.furizon.jooq.generated.tables.GroupPermissions; import net.furizon.jooq.generated.tables.Groups; import net.furizon.jooq.generated.tables.Media; -import net.furizon.jooq.generated.tables.MediaTags; import net.furizon.jooq.generated.tables.MembershipCards; import net.furizon.jooq.generated.tables.MembershipInfo; import net.furizon.jooq.generated.tables.Orders; import net.furizon.jooq.generated.tables.RoomGuests; import net.furizon.jooq.generated.tables.Rooms; import net.furizon.jooq.generated.tables.SchemaMigrations; -import net.furizon.jooq.generated.tables.Tags; import net.furizon.jooq.generated.tables.UserGroup; import net.furizon.jooq.generated.tables.Users; @@ -73,11 +71,6 @@ public class Tables { */ public static final Media MEDIA = Media.MEDIA; - /** - * The table public.media_tags. - */ - public static final MediaTags MEDIA_TAGS = MediaTags.MEDIA_TAGS; - /** * The table public.membership_cards. */ @@ -108,11 +101,6 @@ public class Tables { */ public static final SchemaMigrations SCHEMA_MIGRATIONS = SchemaMigrations.SCHEMA_MIGRATIONS; - /** - * The table public.tags. - */ - public static final Tags TAGS = Tags.TAGS; - /** * The table public.user_group. */ diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Authentications.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Authentications.java index 2714e6c..b715784 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Authentications.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Authentications.java @@ -106,7 +106,7 @@ public Class getRecordType() { /** * The column public.authentications.authentication_password. */ - public final TableField AUTHENTICATION_PASSWORD = createField(DSL.name("authentication_password"), SQLDataType.VARCHAR(255).nullable(false), this, ""); + public final TableField AUTHENTICATION_PASSWORD = createField(DSL.name("authentication_password"), SQLDataType.CLOB.nullable(false), this, ""); /** * The column public.authentications.authentication_token. diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Events.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Events.java index 218b21a..87e7606 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Events.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Events.java @@ -69,9 +69,9 @@ public Class getRecordType() { public final TableField EVENT_SLUG = createField(DSL.name("event_slug"), SQLDataType.VARCHAR(255).nullable(false), this, ""); /** - * The column public.events.event_date_end. + * The column public.events.event_date_to. */ - public final TableField EVENT_DATE_END = createField(DSL.name("event_date_end"), SQLDataType.VARCHAR(32), this, ""); + public final TableField EVENT_DATE_TO = createField(DSL.name("event_date_to"), SQLDataType.VARCHAR(32), this, ""); /** * The column public.events.event_date_from. @@ -81,23 +81,18 @@ public Class getRecordType() { /** * The column public.events.event_is_current. */ - public final TableField EVENT_IS_CURRENT = createField(DSL.name("event_is_current"), SQLDataType.BOOLEAN, this, ""); + public final TableField EVENT_IS_CURRENT = createField(DSL.name("event_is_current"), SQLDataType.BOOLEAN.nullable(false), this, ""); /** * The column public.events.event_public_url. */ - public final TableField EVENT_PUBLIC_URL = createField(DSL.name("event_public_url"), SQLDataType.VARCHAR(255), this, ""); + public final TableField EVENT_PUBLIC_URL = createField(DSL.name("event_public_url"), SQLDataType.CLOB.nullable(false), this, ""); /** * The column public.events.event_names. */ public final TableField EVENT_NAMES = createField(DSL.name("event_names"), SQLDataType.CLOB, this, ""); - /** - * The column public.events.event_names_raw. - */ - public final TableField EVENT_NAMES_RAW = createField(DSL.name("event_names_raw"), SQLDataType.VARCHAR(255), this, ""); - private Events(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Fursuits.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Fursuits.java index ccf563b..42c8b02 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Fursuits.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Fursuits.java @@ -93,11 +93,6 @@ public Class getRecordType() { */ public final TableField MEDIA_ID_PROPIC = createField(DSL.name("media_id_propic"), SQLDataType.BIGINT, this, ""); - /** - * The column public.fursuits.media_id. - */ - public final TableField MEDIA_ID = createField(DSL.name("media_id"), SQLDataType.BIGINT, this, ""); - private Fursuits(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } @@ -176,40 +171,21 @@ public UniqueKey getPrimaryKey() { return Keys.FURSUITS_PKEY; } - @Override - public List> getUniqueKeys() { - return Arrays.asList(Keys.UK47Y138Q5E9DQWRWTJWI5OVLMW); - } - @Override public List> getReferences() { - return Arrays.asList(Keys.FURSUITS__FKOM4XAJCQUVF8OUNSRELSW3A2O, Keys.FURSUITS__FURSUITS_MEDIA_FK, Keys.FURSUITS__FURSUITS_USERS_FK); - } - - private transient MediaPath _fkom4xajcquvf8ounsrelsw3a2o; - - /** - * Get the implicit join path to the public.media table, via - * the fkom4xajcquvf8ounsrelsw3a2o key. - */ - public MediaPath fkom4xajcquvf8ounsrelsw3a2o() { - if (_fkom4xajcquvf8ounsrelsw3a2o == null) - _fkom4xajcquvf8ounsrelsw3a2o = new MediaPath(this, Keys.FURSUITS__FKOM4XAJCQUVF8OUNSRELSW3A2O, null); - - return _fkom4xajcquvf8ounsrelsw3a2o; + return Arrays.asList(Keys.FURSUITS__FURSUITS_MEDIA_FK, Keys.FURSUITS__FURSUITS_USERS_FK); } - private transient MediaPath _fursuitsMediaFk; + private transient MediaPath _media; /** - * Get the implicit join path to the public.media table, via - * the fursuits_media_fk key. + * Get the implicit join path to the public.media table. */ - public MediaPath fursuitsMediaFk() { - if (_fursuitsMediaFk == null) - _fursuitsMediaFk = new MediaPath(this, Keys.FURSUITS__FURSUITS_MEDIA_FK, null); + public MediaPath media() { + if (_media == null) + _media = new MediaPath(this, Keys.FURSUITS__FURSUITS_MEDIA_FK, null); - return _fursuitsMediaFk; + return _media; } private transient UsersPath _users; @@ -237,14 +213,6 @@ public FursuitsEventsPath fursuitsEvents() { return _fursuitsEvents; } - /** - * Get the implicit many-to-many join path to the public.media - * table - */ - public MediaPath media() { - return fursuitsEvents().media(); - } - @Override public Fursuits as(String alias) { return new Fursuits(DSL.name(alias), this); diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Media.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Media.java index 26f27e9..26f3261 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Media.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Media.java @@ -4,9 +4,7 @@ package net.furizon.jooq.generated.tables; -import java.util.Arrays; import java.util.Collection; -import java.util.List; import javax.annotation.processing.Generated; @@ -14,7 +12,6 @@ import net.furizon.jooq.generated.Public; import net.furizon.jooq.generated.tables.Fursuits.FursuitsPath; import net.furizon.jooq.generated.tables.FursuitsEvents.FursuitsEventsPath; -import net.furizon.jooq.generated.tables.MediaTags.MediaTagsPath; import net.furizon.jooq.generated.tables.Users.UsersPath; import org.jetbrains.annotations.Nullable; @@ -77,18 +74,13 @@ public Class getRecordType() { /** * The column public.media.media_path. */ - public final TableField MEDIA_PATH = createField(DSL.name("media_path"), SQLDataType.VARCHAR(255), this, ""); + public final TableField MEDIA_PATH = createField(DSL.name("media_path"), SQLDataType.CLOB, this, ""); /** * The column public.media.media_type. */ public final TableField MEDIA_TYPE = createField(DSL.name("media_type"), SQLDataType.VARCHAR(255), this, ""); - /** - * The column public.media.user_id. - */ - public final TableField USER_ID = createField(DSL.name("user_id"), SQLDataType.BIGINT, this, ""); - private Media(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } @@ -167,49 +159,6 @@ public UniqueKey getPrimaryKey() { return Keys.MEDIA_PKEY; } - @Override - public List> getReferences() { - return Arrays.asList(Keys.MEDIA__FKND8HH0YN7QVV4PQYK8MG7L1OX); - } - - private transient UsersPath _users; - - /** - * Get the implicit join path to the public.users table. - */ - public UsersPath users() { - if (_users == null) - _users = new UsersPath(this, Keys.MEDIA__FKND8HH0YN7QVV4PQYK8MG7L1OX, null); - - return _users; - } - - private transient MediaTagsPath _mediaTags; - - /** - * Get the implicit to-many join path to the public.media_tags - * table - */ - public MediaTagsPath mediaTags() { - if (_mediaTags == null) - _mediaTags = new MediaTagsPath(this, null, Keys.MEDIA_TAGS__FK88C8WCOPLIS4O99Y53CCN21GT.getInverseKey()); - - return _mediaTags; - } - - private transient FursuitsPath _fkom4xajcquvf8ounsrelsw3a2o; - - /** - * Get the implicit to-many join path to the public.fursuits - * table, via the fkom4xajcquvf8ounsrelsw3a2o key - */ - public FursuitsPath fkom4xajcquvf8ounsrelsw3a2o() { - if (_fkom4xajcquvf8ounsrelsw3a2o == null) - _fkom4xajcquvf8ounsrelsw3a2o = new FursuitsPath(this, null, Keys.FURSUITS__FKOM4XAJCQUVF8OUNSRELSW3A2O.getInverseKey()); - - return _fkom4xajcquvf8ounsrelsw3a2o; - } - private transient FursuitsEventsPath _fursuitsEvents; /** @@ -223,25 +172,29 @@ public FursuitsEventsPath fursuitsEvents() { return _fursuitsEvents; } - private transient FursuitsPath _fursuitsMediaFk; + private transient FursuitsPath _fursuits; /** * Get the implicit to-many join path to the public.fursuits - * table, via the fursuits_media_fk key + * table */ - public FursuitsPath fursuitsMediaFk() { - if (_fursuitsMediaFk == null) - _fursuitsMediaFk = new FursuitsPath(this, null, Keys.FURSUITS__FURSUITS_MEDIA_FK.getInverseKey()); + public FursuitsPath fursuits() { + if (_fursuits == null) + _fursuits = new FursuitsPath(this, null, Keys.FURSUITS__FURSUITS_MEDIA_FK.getInverseKey()); - return _fursuitsMediaFk; + return _fursuits; } + private transient UsersPath _users; + /** - * Get the implicit many-to-many join path to the - * public.fursuits table + * Get the implicit to-many join path to the public.users table */ - public FursuitsPath fursuits() { - return fursuitsEvents().fursuits(); + public UsersPath users() { + if (_users == null) + _users = new UsersPath(this, null, Keys.USERS__USER_MEDIA_FK.getInverseKey()); + + return _users; } @Override diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/MediaTags.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/MediaTags.java deleted file mode 100644 index be09b61..0000000 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/MediaTags.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * This file is generated by jOOQ. - */ -package net.furizon.jooq.generated.tables; - - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import javax.annotation.processing.Generated; - -import net.furizon.jooq.generated.Keys; -import net.furizon.jooq.generated.Public; -import net.furizon.jooq.generated.tables.Media.MediaPath; -import net.furizon.jooq.generated.tables.Tags.TagsPath; - -import org.jetbrains.annotations.Nullable; -import org.jooq.Condition; -import org.jooq.Field; -import org.jooq.ForeignKey; -import org.jooq.Identity; -import org.jooq.InverseForeignKey; -import org.jooq.Name; -import org.jooq.Path; -import org.jooq.PlainSQL; -import org.jooq.QueryPart; -import org.jooq.Record; -import org.jooq.SQL; -import org.jooq.Schema; -import org.jooq.Select; -import org.jooq.Stringly; -import org.jooq.Table; -import org.jooq.TableField; -import org.jooq.TableOptions; -import org.jooq.UniqueKey; -import org.jooq.impl.DSL; -import org.jooq.impl.SQLDataType; -import org.jooq.impl.TableImpl; - - -/** - * This class is generated by jOOQ. - */ -@Generated( - value = { - "https://www.jooq.org", - "jOOQ version:3.19.13" - }, - comments = "This class is generated by jOOQ" -) -@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) -public class MediaTags extends TableImpl { - - private static final long serialVersionUID = 1L; - - /** - * The reference instance of public.media_tags - */ - public static final MediaTags MEDIA_TAGS = new MediaTags(); - - /** - * The class holding records for this type - */ - @Override - public Class getRecordType() { - return Record.class; - } - - /** - * The column public.media_tags.media_tag_id. - */ - public final TableField MEDIA_TAG_ID = createField(DSL.name("media_tag_id"), SQLDataType.BIGINT.nullable(false).identity(true), this, ""); - - /** - * The column public.media_tags.media_id. - */ - public final TableField MEDIA_ID = createField(DSL.name("media_id"), SQLDataType.BIGINT, this, ""); - - /** - * The column public.media_tags.tag_id. - */ - public final TableField TAG_ID = createField(DSL.name("tag_id"), SQLDataType.BIGINT, this, ""); - - private MediaTags(Name alias, Table aliased) { - this(alias, aliased, (Field[]) null, null); - } - - private MediaTags(Name alias, Table aliased, Field[] parameters, Condition where) { - super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where); - } - - /** - * Create an aliased public.media_tags table reference - */ - public MediaTags(String alias) { - this(DSL.name(alias), MEDIA_TAGS); - } - - /** - * Create an aliased public.media_tags table reference - */ - public MediaTags(Name alias) { - this(alias, MEDIA_TAGS); - } - - /** - * Create a public.media_tags table reference - */ - public MediaTags() { - this(DSL.name("media_tags"), null); - } - - public MediaTags(Table path, ForeignKey childPath, InverseForeignKey parentPath) { - super(path, childPath, parentPath, MEDIA_TAGS); - } - - /** - * A subtype implementing {@link Path} for simplified path-based joins. - */ - public static class MediaTagsPath extends MediaTags implements Path { - - private static final long serialVersionUID = 1L; - public MediaTagsPath(Table path, ForeignKey childPath, InverseForeignKey parentPath) { - super(path, childPath, parentPath); - } - private MediaTagsPath(Name alias, Table aliased) { - super(alias, aliased); - } - - @Override - public MediaTagsPath as(String alias) { - return new MediaTagsPath(DSL.name(alias), this); - } - - @Override - public MediaTagsPath as(Name alias) { - return new MediaTagsPath(alias, this); - } - - @Override - public MediaTagsPath as(Table alias) { - return new MediaTagsPath(alias.getQualifiedName(), this); - } - } - - @Override - @Nullable - public Schema getSchema() { - return aliased() ? null : Public.PUBLIC; - } - - @Override - public Identity getIdentity() { - return (Identity) super.getIdentity(); - } - - @Override - public UniqueKey getPrimaryKey() { - return Keys.MEDIA_TAGS_PKEY; - } - - @Override - public List> getReferences() { - return Arrays.asList(Keys.MEDIA_TAGS__FK88C8WCOPLIS4O99Y53CCN21GT, Keys.MEDIA_TAGS__FKFGINODY5NX4QLTQEY6C6S16LT); - } - - private transient MediaPath _media; - - /** - * Get the implicit join path to the public.media table. - */ - public MediaPath media() { - if (_media == null) - _media = new MediaPath(this, Keys.MEDIA_TAGS__FK88C8WCOPLIS4O99Y53CCN21GT, null); - - return _media; - } - - private transient TagsPath _tags; - - /** - * Get the implicit join path to the public.tags table. - */ - public TagsPath tags() { - if (_tags == null) - _tags = new TagsPath(this, Keys.MEDIA_TAGS__FKFGINODY5NX4QLTQEY6C6S16LT, null); - - return _tags; - } - - @Override - public MediaTags as(String alias) { - return new MediaTags(DSL.name(alias), this); - } - - @Override - public MediaTags as(Name alias) { - return new MediaTags(alias, this); - } - - @Override - public MediaTags as(Table alias) { - return new MediaTags(alias.getQualifiedName(), this); - } - - /** - * Rename this table - */ - @Override - public MediaTags rename(String name) { - return new MediaTags(DSL.name(name), null); - } - - /** - * Rename this table - */ - @Override - public MediaTags rename(Name name) { - return new MediaTags(name, null); - } - - /** - * Rename this table - */ - @Override - public MediaTags rename(Table name) { - return new MediaTags(name.getQualifiedName(), null); - } - - /** - * Create an inline derived table from this table - */ - @Override - public MediaTags where(Condition condition) { - return new MediaTags(getQualifiedName(), aliased() ? this : null, null, condition); - } - - /** - * Create an inline derived table from this table - */ - @Override - public MediaTags where(Collection conditions) { - return where(DSL.and(conditions)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public MediaTags where(Condition... conditions) { - return where(DSL.and(conditions)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public MediaTags where(Field condition) { - return where(DSL.condition(condition)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public MediaTags where(SQL condition) { - return where(DSL.condition(condition)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public MediaTags where(@Stringly.SQL String condition) { - return where(DSL.condition(condition)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public MediaTags where(@Stringly.SQL String condition, Object... binds) { - return where(DSL.condition(condition, binds)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public MediaTags where(@Stringly.SQL String condition, QueryPart... parts) { - return where(DSL.condition(condition, parts)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public MediaTags whereExists(Select select) { - return where(DSL.exists(select)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public MediaTags whereNotExists(Select select) { - return where(DSL.notExists(select)); - } -} diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Orders.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Orders.java index 10289d9..406b364 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Orders.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Orders.java @@ -22,6 +22,7 @@ import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.InverseForeignKey; +import org.jooq.JSON; import org.jooq.Name; import org.jooq.Path; import org.jooq.PlainSQL; @@ -75,9 +76,9 @@ public Class getRecordType() { public final TableField ORDER_CODE = createField(DSL.name("order_code"), SQLDataType.VARCHAR(64).nullable(false), this, ""); /** - * The column public.orders.order_answers. + * The column public.orders.order_answers_json. */ - public final TableField ORDER_ANSWERS = createField(DSL.name("order_answers"), SQLDataType.CLOB, this, ""); + public final TableField ORDER_ANSWERS_JSON = createField(DSL.name("order_answers_json"), SQLDataType.JSON, this, ""); /** * The column public.orders.order_status. @@ -99,6 +100,16 @@ public Class getRecordType() { */ public final TableField ORDER_EXTRA_DAYS_TYPE = createField(DSL.name("order_extra_days_type"), SQLDataType.SMALLINT, this, ""); + /** + * The column public.orders.order_room_capacity. + */ + public final TableField ORDER_ROOM_CAPACITY = createField(DSL.name("order_room_capacity"), SQLDataType.SMALLINT, this, ""); + + /** + * The column public.orders.order_hotel_location. + */ + public final TableField ORDER_HOTEL_LOCATION = createField(DSL.name("order_hotel_location"), SQLDataType.VARCHAR(255), this, ""); + /** * The column public.orders.has_membership. */ @@ -124,51 +135,6 @@ public Class getRecordType() { */ public final TableField USER_ID = createField(DSL.name("user_id"), SQLDataType.BIGINT, this, ""); - /** - * The column public.orders.code. - */ - public final TableField CODE = createField(DSL.name("code"), SQLDataType.VARCHAR(255).nullable(false), this, ""); - - /** - * The column public.orders.answers. - */ - public final TableField ANSWERS = createField(DSL.name("answers"), SQLDataType.VARCHAR(255), this, ""); - - /** - * The column public.orders.answers_main_position_id. - */ - public final TableField ANSWERS_MAIN_POSITION_ID = createField(DSL.name("answers_main_position_id"), SQLDataType.INTEGER.nullable(false), this, ""); - - /** - * The column public.orders.daily_days. - */ - public final TableField DAILY_DAYS = createField(DSL.name("daily_days"), SQLDataType.BIGINT.nullable(false), this, ""); - - /** - * The column public.orders.extra_days. - */ - public final TableField EXTRA_DAYS = createField(DSL.name("extra_days"), SQLDataType.SMALLINT, this, ""); - - /** - * The column public.orders.hotel_location. - */ - public final TableField HOTEL_LOCATION = createField(DSL.name("hotel_location"), SQLDataType.VARCHAR(255), this, ""); - - /** - * The column public.orders.pretix_order_secret. - */ - public final TableField PRETIX_ORDER_SECRET = createField(DSL.name("pretix_order_secret"), SQLDataType.VARCHAR(255), this, ""); - - /** - * The column public.orders.room_capacity. - */ - public final TableField ROOM_CAPACITY = createField(DSL.name("room_capacity"), SQLDataType.INTEGER.nullable(false), this, ""); - - /** - * The column public.orders.sponsorship. - */ - public final TableField SPONSORSHIP = createField(DSL.name("sponsorship"), SQLDataType.SMALLINT, this, ""); - private Orders(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } @@ -287,9 +253,7 @@ public RoomsPath rooms() { public List> getChecks() { return Arrays.asList( Internal.createCheck(this, DSL.name("orders_extra_days_check"), "(((order_extra_days_type >= 0) AND (order_extra_days_type <= 3)))", true), - Internal.createCheck(this, DSL.name("orders_extra_days_check1"), "(((extra_days >= 0) AND (extra_days <= 3)))", true), Internal.createCheck(this, DSL.name("orders_sponsorship_check"), "(((order_sponsorship_type >= 0) AND (order_sponsorship_type <= 2)))", true), - Internal.createCheck(this, DSL.name("orders_sponsorship_check1"), "(((sponsorship >= 0) AND (sponsorship <= 2)))", true), Internal.createCheck(this, DSL.name("orders_status_check"), "(((order_status >= 0) AND (order_status <= 3)))", true) ); } diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Rooms.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Rooms.java index 742ff02..e7efa00 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Rooms.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Rooms.java @@ -85,7 +85,7 @@ public Class getRecordType() { /** * The column public.rooms.order_id. */ - public final TableField ORDER_ID = createField(DSL.name("order_id"), SQLDataType.VARCHAR(255), this, ""); + public final TableField ORDER_ID = createField(DSL.name("order_id"), SQLDataType.VARCHAR(64), this, ""); private Rooms(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Tags.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Tags.java deleted file mode 100644 index 8053b93..0000000 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Tags.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * This file is generated by jOOQ. - */ -package net.furizon.jooq.generated.tables; - - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import javax.annotation.processing.Generated; - -import net.furizon.jooq.generated.Keys; -import net.furizon.jooq.generated.Public; -import net.furizon.jooq.generated.tables.MediaTags.MediaTagsPath; - -import org.jetbrains.annotations.Nullable; -import org.jooq.Condition; -import org.jooq.Field; -import org.jooq.ForeignKey; -import org.jooq.Identity; -import org.jooq.InverseForeignKey; -import org.jooq.Name; -import org.jooq.Path; -import org.jooq.PlainSQL; -import org.jooq.QueryPart; -import org.jooq.Record; -import org.jooq.SQL; -import org.jooq.Schema; -import org.jooq.Select; -import org.jooq.Stringly; -import org.jooq.Table; -import org.jooq.TableField; -import org.jooq.TableOptions; -import org.jooq.UniqueKey; -import org.jooq.impl.DSL; -import org.jooq.impl.SQLDataType; -import org.jooq.impl.TableImpl; - - -/** - * This class is generated by jOOQ. - */ -@Generated( - value = { - "https://www.jooq.org", - "jOOQ version:3.19.13" - }, - comments = "This class is generated by jOOQ" -) -@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) -public class Tags extends TableImpl { - - private static final long serialVersionUID = 1L; - - /** - * The reference instance of public.tags - */ - public static final Tags TAGS = new Tags(); - - /** - * The class holding records for this type - */ - @Override - public Class getRecordType() { - return Record.class; - } - - /** - * The column public.tags.tag_id. - */ - public final TableField TAG_ID = createField(DSL.name("tag_id"), SQLDataType.BIGINT.nullable(false).identity(true), this, ""); - - /** - * The column public.tags.tag_code. - */ - public final TableField TAG_CODE = createField(DSL.name("tag_code"), SQLDataType.VARCHAR(255), this, ""); - - private Tags(Name alias, Table aliased) { - this(alias, aliased, (Field[]) null, null); - } - - private Tags(Name alias, Table aliased, Field[] parameters, Condition where) { - super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where); - } - - /** - * Create an aliased public.tags table reference - */ - public Tags(String alias) { - this(DSL.name(alias), TAGS); - } - - /** - * Create an aliased public.tags table reference - */ - public Tags(Name alias) { - this(alias, TAGS); - } - - /** - * Create a public.tags table reference - */ - public Tags() { - this(DSL.name("tags"), null); - } - - public Tags(Table path, ForeignKey childPath, InverseForeignKey parentPath) { - super(path, childPath, parentPath, TAGS); - } - - /** - * A subtype implementing {@link Path} for simplified path-based joins. - */ - public static class TagsPath extends Tags implements Path { - - private static final long serialVersionUID = 1L; - public TagsPath(Table path, ForeignKey childPath, InverseForeignKey parentPath) { - super(path, childPath, parentPath); - } - private TagsPath(Name alias, Table aliased) { - super(alias, aliased); - } - - @Override - public TagsPath as(String alias) { - return new TagsPath(DSL.name(alias), this); - } - - @Override - public TagsPath as(Name alias) { - return new TagsPath(alias, this); - } - - @Override - public TagsPath as(Table alias) { - return new TagsPath(alias.getQualifiedName(), this); - } - } - - @Override - @Nullable - public Schema getSchema() { - return aliased() ? null : Public.PUBLIC; - } - - @Override - public Identity getIdentity() { - return (Identity) super.getIdentity(); - } - - @Override - public UniqueKey getPrimaryKey() { - return Keys.TAGS_PKEY; - } - - @Override - public List> getUniqueKeys() { - return Arrays.asList(Keys.UKRLLOBBOR6YGDSIT4DSVACBD90); - } - - private transient MediaTagsPath _mediaTags; - - /** - * Get the implicit to-many join path to the public.media_tags - * table - */ - public MediaTagsPath mediaTags() { - if (_mediaTags == null) - _mediaTags = new MediaTagsPath(this, null, Keys.MEDIA_TAGS__FKFGINODY5NX4QLTQEY6C6S16LT.getInverseKey()); - - return _mediaTags; - } - - @Override - public Tags as(String alias) { - return new Tags(DSL.name(alias), this); - } - - @Override - public Tags as(Name alias) { - return new Tags(alias, this); - } - - @Override - public Tags as(Table alias) { - return new Tags(alias.getQualifiedName(), this); - } - - /** - * Rename this table - */ - @Override - public Tags rename(String name) { - return new Tags(DSL.name(name), null); - } - - /** - * Rename this table - */ - @Override - public Tags rename(Name name) { - return new Tags(name, null); - } - - /** - * Rename this table - */ - @Override - public Tags rename(Table name) { - return new Tags(name.getQualifiedName(), null); - } - - /** - * Create an inline derived table from this table - */ - @Override - public Tags where(Condition condition) { - return new Tags(getQualifiedName(), aliased() ? this : null, null, condition); - } - - /** - * Create an inline derived table from this table - */ - @Override - public Tags where(Collection conditions) { - return where(DSL.and(conditions)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public Tags where(Condition... conditions) { - return where(DSL.and(conditions)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public Tags where(Field condition) { - return where(DSL.condition(condition)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public Tags where(SQL condition) { - return where(DSL.condition(condition)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public Tags where(@Stringly.SQL String condition) { - return where(DSL.condition(condition)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public Tags where(@Stringly.SQL String condition, Object... binds) { - return where(DSL.condition(condition, binds)); - } - - /** - * Create an inline derived table from this table - */ - @Override - @PlainSQL - public Tags where(@Stringly.SQL String condition, QueryPart... parts) { - return where(DSL.condition(condition, parts)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public Tags whereExists(Select select) { - return where(DSL.exists(select)); - } - - /** - * Create an inline derived table from this table - */ - @Override - public Tags whereNotExists(Select select) { - return where(DSL.notExists(select)); - } -} diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/UserGroup.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/UserGroup.java index 75224d6..7746ec2 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/UserGroup.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/UserGroup.java @@ -19,7 +19,6 @@ import org.jooq.Condition; import org.jooq.Field; import org.jooq.ForeignKey; -import org.jooq.Identity; import org.jooq.InverseForeignKey; import org.jooq.Name; import org.jooq.Path; @@ -76,11 +75,6 @@ public Class getRecordType() { */ public final TableField USER_ID = createField(DSL.name("user_id"), SQLDataType.BIGINT, this, ""); - /** - * The column public.user_group.user_group_id. - */ - public final TableField USER_GROUP_ID = createField(DSL.name("user_group_id"), SQLDataType.BIGINT.nullable(false).identity(true), this, ""); - private UserGroup(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } @@ -149,11 +143,6 @@ public Schema getSchema() { return aliased() ? null : Public.PUBLIC; } - @Override - public Identity getIdentity() { - return (Identity) super.getIdentity(); - } - @Override public List> getReferences() { return Arrays.asList(Keys.USER_GROUP__USER_GROUP_GROUPS_FK, Keys.USER_GROUP__USER_GROUP_USERS_FK); diff --git a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Users.java b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Users.java index bbc4504..4a8d020 100644 --- a/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Users.java +++ b/jooq-common/src/main/java/net/furizon/jooq/generated/tables/Users.java @@ -86,28 +86,18 @@ public Class getRecordType() { /** * The column public.users.user_locale. */ - public final TableField USER_LOCALE = createField(DSL.name("user_locale"), SQLDataType.VARCHAR(255).defaultValue(DSL.field(DSL.raw("'en-us'::character varying"), SQLDataType.VARCHAR)), this, ""); + public final TableField USER_LOCALE = createField(DSL.name("user_locale"), SQLDataType.VARCHAR(8).defaultValue(DSL.field(DSL.raw("'en-us'::character varying"), SQLDataType.VARCHAR)), this, ""); /** * The column public.users.user_secret. */ - public final TableField USER_SECRET = createField(DSL.name("user_secret"), SQLDataType.VARCHAR(255).nullable(false), this, ""); + public final TableField USER_SECRET = createField(DSL.name("user_secret"), SQLDataType.VARCHAR(70).nullable(false), this, ""); /** * The column public.users.media_id_propic. */ public final TableField MEDIA_ID_PROPIC = createField(DSL.name("media_id_propic"), SQLDataType.BIGINT, this, ""); - /** - * The column public.users.user_first_name. - */ - public final TableField USER_FIRST_NAME = createField(DSL.name("user_first_name"), SQLDataType.VARCHAR(255), this, ""); - - /** - * The column public.users.user_last_name. - */ - public final TableField USER_LAST_NAME = createField(DSL.name("user_last_name"), SQLDataType.VARCHAR(255), this, ""); - private Users(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } diff --git a/lombok.config b/lombok.config index 2bfd25b..9c51310 100644 --- a/lombok.config +++ b/lombok.config @@ -1,2 +1,3 @@ lombok.anyConstructor.addConstructorProperties=true lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.copyableAnnotations += org.springframework.context.annotation.Lazy diff --git a/pom.xml b/pom.xml index fc3385f..5b3c112 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ 3.3.4 42.7.4 3.19.13 + 3.17.0 @@ -41,6 +42,11 @@ ${lombok.version} provided + + org.apache.commons + commons-lang3 + ${commons.lang.version} +