diff --git a/.env.example b/.env.example index b6db56c..0489c09 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,8 @@ BOT_TOKEN= GUILD_ID= DEFAULT_ROLE_ID= -ROLE_ID= \ No newline at end of file +ROLE_ID= +LOG_CHANNEL_ID= +DB_URL=jdbc:postgresql://localhost:5434/kiss_shot_acerola +DB_USER=postgres +DB_PASSWORD=kiss_shot_acerola \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 6902bdc..3fce07d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,10 +17,14 @@ repositories { } dependencies { + implementation("org.hibernate:hibernate-core:6.6.2.Final") + implementation("org.hibernate:hibernate-hikaricp:6.6.2.Final") + implementation("org.postgresql:postgresql:42.7.4") implementation("io.github.cdimascio:dotenv-kotlin:6.4.2") implementation("net.dv8tion:JDA:5.2.1") implementation("ch.qos.logback:logback-classic:1.5.12") implementation ("dev.arbjerg:lavaplayer:2.2.2") + implementation("jakarta.annotation:jakarta.annotation-api:3.0.0") } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..587b925 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +services: + postgres: + image: postgres:17 + environment: + POSTGRES_PASSWORD: kiss_shot_acerola + POSTGRES_DB: kiss_shot_acerola + ports: + - "5434:5432" + volumes: + - postgres_kiss_shot_acerola_data:/var/lib/postgresql/data + +volumes: + postgres_kiss_shot_acerola_data: \ No newline at end of file diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/KissShotAcerola.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/KissShotAcerola.java index 93c6baa..edbcc90 100644 --- a/src/main/java/org/camelia/studio/kiss/shot/acerola/KissShotAcerola.java +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/KissShotAcerola.java @@ -1,11 +1,14 @@ package org.camelia.studio.kiss.shot.acerola; +import org.camelia.studio.kiss.shot.acerola.db.HibernateConfig; import org.camelia.studio.kiss.shot.acerola.listeners.bot.ReadyListener; import org.camelia.studio.kiss.shot.acerola.managers.ListenerManager; import org.camelia.studio.kiss.shot.acerola.utils.Configuration; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.utils.MemberCachePolicy; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,13 +23,14 @@ public class KissShotAcerola { jda = JDABuilder.createDefault(Configuration.getInstance().getDotenv().get("BOT_TOKEN")) .addEventListeners(new ReadyListener()) .enableIntents(GatewayIntent.getIntents(GatewayIntent.ALL_INTENTS)) + .setMemberCachePolicy(MemberCachePolicy.ALL) .build() - .awaitReady() - ; + .awaitReady(); new ListenerManager().registerListeners(jda); Runtime.getRuntime().addShutdownHook(new Thread(() -> { + HibernateConfig.shutdown(); jda.shutdown(); })); } catch (Exception e) { diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/commands/moderation/AvertoCommand.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/commands/moderation/AvertoCommand.java new file mode 100644 index 0000000..dc8f163 --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/commands/moderation/AvertoCommand.java @@ -0,0 +1,126 @@ +package org.camelia.studio.kiss.shot.acerola.commands.moderation; + +import java.io.File; +import java.util.List; + +import org.camelia.studio.kiss.shot.acerola.interfaces.ISlashCommand; +import org.camelia.studio.kiss.shot.acerola.models.Averto; +import org.camelia.studio.kiss.shot.acerola.models.User; +import org.camelia.studio.kiss.shot.acerola.repositories.AvertoRepository; +import org.camelia.studio.kiss.shot.acerola.services.UserService; +import org.camelia.studio.kiss.shot.acerola.utils.Configuration; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.Message.Attachment; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.utils.FileUpload; + +public class AvertoCommand implements ISlashCommand { + + @Override + public String getName() { + return "averto"; + } + + @Override + public String getDescription() { + return "Permet d'avertir un utilisateur"; + } + + @Override + public List getOptions() { + return List.of( + new OptionData(OptionType.USER, "utilisateur", "L'utilisateur à avertir", true), + new OptionData(OptionType.STRING, "raison", "La raison de l'avertissement", false), + new OptionData(OptionType.ATTACHMENT, "file", "Une preuve de l'avertissement", false)); + } + + @Override + public DefaultMemberPermissions defaultPermissions() { + return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_MANAGE); + } + + @Override + public void execute(SlashCommandInteractionEvent event) { + event.deferReply().setEphemeral(true).queue(); + try { + Member moderator = event.getMember(); + Member member = event.getOption("utilisateur").getAsMember(); + + OptionMapping raisonOptionMapping = event.getOption("raison"); + String reason = raisonOptionMapping == null ? "Aucune raison spécifiée" : raisonOptionMapping.getAsString(); + + OptionMapping fileOptionMapping = event.getOption("file"); + Attachment file = null; + String fileUrl = null; + TextChannel logChannel = event.getGuild() + .getTextChannelById(Configuration.getInstance().getDotenv().get("LOG_CHANNEL_ID")); + + if (fileOptionMapping != null) { + file = fileOptionMapping.getAsAttachment(); + } + + if (logChannel != null) { + File fileTemp = null; + if (file != null) { + fileTemp = File.createTempFile("proof_" + member.getId() + "_", "." + file.getFileExtension()); + fileTemp = file.getProxy().downloadToFile(fileTemp).get(); + } + + Message message = this.sendLogMessage(logChannel, member, fileTemp, reason); + + if (fileTemp != null) { + fileUrl = message.getAttachments().get(0).getUrl(); + fileTemp.delete(); + } + } + + User memberUser = UserService.getInstance().getOrCreateUser(member.getId()); + User moderatorUser = UserService.getInstance().getOrCreateUser(moderator.getId()); + + Averto averto = new Averto(memberUser, moderatorUser); + averto.setReason(reason); + averto.setFile(fileUrl); + + AvertoRepository.getInstance().save(averto); + + // On tente d'envoyer un message privé à l'utilisateur averti + member.getUser().openPrivateChannel().queue(privateChannel -> { + privateChannel + .sendMessage("Bonjour, Vous avez été averti sur %s pour la raison suivante : %s".formatted( + event.getGuild().getName(), reason != null ? reason : "Aucune raison spécifiée")) + .queue(); + }); + + event.getHook().editOriginal("L'utilisateur %s a bien été averti !".formatted(member.getAsMention())) + .queue(); + } catch (Exception e) { + event.getHook().editOriginal("Une erreur est survenue lors de l'avertissement, " + e.getMessage()).queue(); + } + } + + private Message sendLogMessage(TextChannel logChannel, Member member, File fileTemp, String reason) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setTitle("Avertissement - Règlement enfreint"); + embedBuilder.setDescription("Un utilisateur a été averti pour non respect du règlement"); + embedBuilder.addField("Utilisateur", member.getAsMention(), false); + embedBuilder.addField("Raison", reason != null ? reason : "Aucune raison spécifié", false); + + Message msg = logChannel.sendMessageEmbeds(embedBuilder.build()).complete(); + + if (fileTemp != null) { + msg = logChannel + .sendFiles(FileUpload.fromData(fileTemp)).complete(); + } + + return msg; + } +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/commands/moderation/AvertoListCommand.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/commands/moderation/AvertoListCommand.java new file mode 100644 index 0000000..03666c3 --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/commands/moderation/AvertoListCommand.java @@ -0,0 +1,99 @@ +package org.camelia.studio.kiss.shot.acerola.commands.moderation; + +import java.time.format.DateTimeFormatter; +import java.util.List; + +import org.camelia.studio.kiss.shot.acerola.interfaces.ISlashCommand; +import org.camelia.studio.kiss.shot.acerola.models.Averto; +import org.camelia.studio.kiss.shot.acerola.models.User; +import org.camelia.studio.kiss.shot.acerola.services.AvertoService; +import org.camelia.studio.kiss.shot.acerola.services.UserService; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; + +public class AvertoListCommand implements ISlashCommand { + + @Override + public String getName() { + return "avertolist"; + } + + @Override + public String getDescription() { + return "Liste les avertissements d'un utilisateur"; + } + + @Override + public DefaultMemberPermissions defaultPermissions() { + return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_MANAGE); + } + + @Override + public List getOptions() { + return List.of( + new OptionData( + OptionType.USER, + "utilisateur", + "L'utilisateur dont vous voulez voir les avertissements", + false)); + } + + @Override + public void execute(SlashCommandInteractionEvent event) { + event.deferReply().setEphemeral(true).queue(); + OptionMapping option = event.getOption("utilisateur"); + + Member member = null; + List avertos = null; + User user = null; + + if (option != null) { + member = option.getAsMember(); + user = UserService.getInstance().getOrCreateUser(member.getId()); + avertos = user.getAvertos(); + } else { + avertos = AvertoService.getInstance().getLatestAvertos(10); + } + /* + * 2 possibilités : + * - Aucun utilisateur : On affiche les 10 derniers avertissements du serveur + * - Un utilisateur : On affiche les avertissements de cet utilisateur + */ + + EmbedBuilder embedBuilder = new EmbedBuilder() + .setTitle("Avertissements de " + (member == null ? "tous les utilisateurs" : member.getEffectiveName())) + .setColor(0xFF0000); + + int count = 0; + + for (Averto averto : avertos) { + count++; + if (count > 10) { + break; + } + // On récupère le membre Discord de l'utilisateur + Member discordUser = event.getGuild().getMemberById(averto.getUser().getDiscordId()); + Member moderator = event.getGuild().getMemberById(averto.getModerator().getDiscordId()); + embedBuilder.addField( + "Avertissement #" + averto.getId(), + (discordUser != null ? "Utilisateur : " + discordUser.getAsMention() + "\n" : "") + + "Raison : " + averto.getReason() + "\n" + + (moderator != null ? "Modérateur : " + moderator.getAsMention() : "") + "\n" + + "Date : " + + averto.getCreatedAt().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")) + + "\n" + + "Preuve : " + (averto.getFile() != null ? averto.getFile() : "Aucune"), + false); + } + + event.getHook().editOriginalEmbeds(embedBuilder.build()).queue(); + } + +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/db/HibernateConfig.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/db/HibernateConfig.java new file mode 100644 index 0000000..87360db --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/db/HibernateConfig.java @@ -0,0 +1,83 @@ +package org.camelia.studio.kiss.shot.acerola.db; + +import io.github.cdimascio.dotenv.Dotenv; +import org.camelia.studio.kiss.shot.acerola.interfaces.IEntity; +import org.camelia.studio.kiss.shot.acerola.utils.ReflectionUtils; +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.service.ServiceRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Properties; + +public class HibernateConfig { + private static final Logger logger = LoggerFactory.getLogger(HibernateConfig.class); + private static SessionFactory sessionFactory; + + public static SessionFactory getSessionFactory() { + if (sessionFactory == null) { + try { + logger.info("Initializing Hibernate SessionFactory"); + Dotenv dotenv = org.camelia.studio.kiss.shot.acerola.utils.Configuration.getInstance().getDotenv(); + + Properties props = new Properties(); + + // Configuration Hibernate + props.put(Environment.HBM2DDL_AUTO, "update"); // On utilise validate au lieu de update + + props.put(Environment.GLOBALLY_QUOTED_IDENTIFIERS, "true"); + + // Configuration HikariCP + props.put("hibernate.connection.provider_class", + "org.hibernate.hikaricp.internal.HikariCPConnectionProvider"); + props.put("hibernate.hikari.minimumIdle", "5"); + props.put("hibernate.hikari.maximumPoolSize", "10"); + props.put("hibernate.hikari.idleTimeout", "300000"); + props.put("hibernate.hikari.dataSourceClassName", + "org.postgresql.ds.PGSimpleDataSource"); + props.put("hibernate.hikari.dataSource.url", dotenv.get("DB_URL")); + props.put("hibernate.hikari.dataSource.user", dotenv.get("DB_USER")); + props.put("hibernate.hikari.dataSource.password", dotenv.get("DB_PASSWORD")); + + Configuration configuration = new Configuration(); + configuration.setProperties(props); + + List entities = ReflectionUtils.loadClasses( + "org.camelia.studio.kiss.shot.acerola.models", + IEntity.class); + + for (IEntity entity : entities) { + configuration.addAnnotatedClass(entity.getClass()); + } + + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()) + .build(); + + sessionFactory = configuration.buildSessionFactory(serviceRegistry); + logger.info("Hibernate SessionFactory initialized successfully"); + + } catch (Exception e) { + logger.error("Failed to initialize Hibernate SessionFactory", e); + throw new RuntimeException("Failed to initialize Hibernate SessionFactory", e); + } + } + return sessionFactory; + } + + public static void shutdown() { + logger.info("Shutting down database connections"); + if (sessionFactory != null && !sessionFactory.isClosed()) { + try { + sessionFactory.close(); + logger.info("SessionFactory closed successfully"); + } catch (Exception e) { + logger.error("Error closing SessionFactory", e); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/IEntity.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/IEntity.java new file mode 100644 index 0000000..f4c440a --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/IEntity.java @@ -0,0 +1,4 @@ +package org.camelia.studio.kiss.shot.acerola.interfaces; + +public interface IEntity { +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/ISlashCommand.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/ISlashCommand.java index da9b3ce..56f4fb5 100644 --- a/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/ISlashCommand.java +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/interfaces/ISlashCommand.java @@ -1,16 +1,23 @@ package org.camelia.studio.kiss.shot.acerola.interfaces; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import java.util.List; public interface ISlashCommand { String getName(); + String getDescription(); + void execute(SlashCommandInteractionEvent event); + default List getOptions() { return List.of(); } -} + default DefaultMemberPermissions defaultPermissions() { + return DefaultMemberPermissions.ENABLED; + } +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/models/Averto.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/models/Averto.java new file mode 100644 index 0000000..97d8132 --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/models/Averto.java @@ -0,0 +1,81 @@ +package org.camelia.studio.kiss.shot.acerola.models; + +import jakarta.persistence.*; + +import org.camelia.studio.kiss.shot.acerola.interfaces.IEntity; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "avertos") +public class Averto implements IEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.EAGER) + private User user; + + @ManyToOne(fetch = FetchType.EAGER) + private User moderator; + + @Column(name = "reason", nullable = true, unique = false) + private String reason; + + @Column(name = "file", nullable = true, unique = false) + private String file; + + @CreationTimestamp + @Column(name = "createdAt") + private LocalDateTime createdAt; + + @UpdateTimestamp + @Column(name = "updatedAt") + private LocalDateTime updatedAt; + + public Averto() { + } + + public Averto(User user, User moderator) { + this.user = user; + this.moderator = moderator; + } + + public Long getId() { + return id; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public String getReason() { + return reason; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public User getModerator() { + return moderator; + } + + public User getUser() { + return user; + } +} \ No newline at end of file diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/models/User.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/models/User.java new file mode 100644 index 0000000..839f6ca --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/models/User.java @@ -0,0 +1,70 @@ +package org.camelia.studio.kiss.shot.acerola.models; + +import jakarta.persistence.*; + +import org.camelia.studio.kiss.shot.acerola.interfaces.IEntity; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Table(name = "users") +public class User implements IEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToMany(mappedBy = "user", fetch = FetchType.EAGER) + private List avertos; + + @OneToMany(mappedBy = "moderator", fetch = FetchType.EAGER) + private List moderatedAvertos; + + @Column(name = "discordId", nullable = false, unique = true) + private String discordId; + + @CreationTimestamp + @Column(name = "createdAt") + private LocalDateTime createdAt; + + @UpdateTimestamp + @Column(name = "updatedAt") + private LocalDateTime updatedAt; + + public User() { + } + + public User(String discordId) { + this.discordId = discordId; + } + + public Long getId() { + return id; + } + + public String getDiscordId() { + return discordId; + } + + public void setDiscordId(String discordId) { + this.discordId = discordId; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public List getAvertos() { + return avertos; + } + + public List getModeratedAvertos() { + return moderatedAvertos; + } +} \ No newline at end of file diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/repositories/AvertoRepository.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/repositories/AvertoRepository.java new file mode 100644 index 0000000..ec6b76e --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/repositories/AvertoRepository.java @@ -0,0 +1,53 @@ +package org.camelia.studio.kiss.shot.acerola.repositories; + +import org.camelia.studio.kiss.shot.acerola.db.HibernateConfig; +import org.camelia.studio.kiss.shot.acerola.models.Averto; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.query.Order; +import org.hibernate.query.SortDirection; + +import java.util.List; + +public class AvertoRepository { + private final SessionFactory sessionFactory; + private static AvertoRepository instance; + + public static AvertoRepository getInstance() { + if (instance == null) { + instance = new AvertoRepository(); + } + + return instance; + } + + public AvertoRepository() { + this.sessionFactory = HibernateConfig.getSessionFactory(); + } + + public List findAll() { + try (Session session = sessionFactory.openSession()) { + return session.createQuery("FROM User", Averto.class) + .setOrder(Order.by(Averto.class, "createdAt", SortDirection.DESCENDING)) + .list(); + } + } + + public List findCount(int count) { + try (Session session = sessionFactory.openSession()) { + return session.createQuery("FROM Averto", Averto.class) + .setOrder(Order.by(Averto.class, "createdAt", SortDirection.DESCENDING)) + .setMaxResults(count) + .list(); + } + } + + public Averto save(Averto averto) { + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.persist(averto); + session.getTransaction().commit(); + return averto; + } + } +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/repositories/UserRepository.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/repositories/UserRepository.java new file mode 100644 index 0000000..c0b9364 --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/repositories/UserRepository.java @@ -0,0 +1,56 @@ +package org.camelia.studio.kiss.shot.acerola.repositories; + +import org.camelia.studio.kiss.shot.acerola.db.HibernateConfig; +import org.camelia.studio.kiss.shot.acerola.models.User; +import org.hibernate.Session; +import org.hibernate.SessionFactory; + +import java.util.List; + +public class UserRepository { + private final SessionFactory sessionFactory; + private static UserRepository instance; + + public static UserRepository getInstance() { + if (instance == null) { + instance = new UserRepository(); + } + + return instance; + } + + public UserRepository() { + this.sessionFactory = HibernateConfig.getSessionFactory(); + } + + public List findAll() { + try (Session session = sessionFactory.openSession()) { + return session.createQuery("FROM User", User.class).list(); + } + } + + public User findByDiscordId(String discordId) { + try (Session session = sessionFactory.openSession()) { + return session.createQuery("FROM User WHERE discordId = :discordId", User.class) + .setParameter("discordId", discordId) + .uniqueResult(); + } + } + + public User save(User user) { + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.persist(user); + session.getTransaction().commit(); + return user; + } + } + + public void update(User user) { + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.merge(user); + session.getTransaction().commit(); + } + } +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/services/AvertoService.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/services/AvertoService.java new file mode 100644 index 0000000..ed0174d --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/services/AvertoService.java @@ -0,0 +1,23 @@ +package org.camelia.studio.kiss.shot.acerola.services; + +import java.util.List; + +import org.camelia.studio.kiss.shot.acerola.models.Averto; +import org.camelia.studio.kiss.shot.acerola.repositories.AvertoRepository; + +public class AvertoService { + private static AvertoService instance; + + public static AvertoService getInstance() { + if (instance == null) { + instance = new AvertoService(); + } + + return instance; + } + + public List getLatestAvertos(int amount) { + return AvertoRepository.getInstance().findCount(amount); + } + +} diff --git a/src/main/java/org/camelia/studio/kiss/shot/acerola/services/UserService.java b/src/main/java/org/camelia/studio/kiss/shot/acerola/services/UserService.java new file mode 100644 index 0000000..8036e6b --- /dev/null +++ b/src/main/java/org/camelia/studio/kiss/shot/acerola/services/UserService.java @@ -0,0 +1,37 @@ +package org.camelia.studio.kiss.shot.acerola.services; + +import org.camelia.studio.kiss.shot.acerola.models.*; +import org.camelia.studio.kiss.shot.acerola.repositories.UserRepository; + +import java.util.List; + +public class UserService { + private static UserService instance; + + public static UserService getInstance() { + if (instance == null) { + instance = new UserService(); + } + + return instance; + } + + public User getOrCreateUser(String discordId) { + User user = UserRepository.getInstance().findByDiscordId(discordId); + + if (user == null) { + user = new User(discordId); + UserRepository.getInstance().save(user); + } + + return user; + } + + public List getAllUsers() { + return UserRepository.getInstance().findAll(); + } + + public void updateUser(User user) { + UserRepository.getInstance().update(user); + } +}