diff --git a/src/main/java/net/locusworks/discord/eighttrack/database/entities/DiscordGuild.java b/src/main/java/net/locusworks/discord/eighttrack/database/entities/DiscordGuild.java index fce27fd..2d85e1c 100644 --- a/src/main/java/net/locusworks/discord/eighttrack/database/entities/DiscordGuild.java +++ b/src/main/java/net/locusworks/discord/eighttrack/database/entities/DiscordGuild.java @@ -50,6 +50,8 @@ public class DiscordGuild implements Serializable { @OneToMany(cascade = CascadeType.ALL, mappedBy = "guild") private List guildSongList; @OneToMany(cascade = CascadeType.ALL, mappedBy = "guild") + private List logList; + @OneToMany(cascade = CascadeType.ALL, mappedBy = "guild") private List guildPlaylistList; public DiscordGuild() { @@ -105,6 +107,14 @@ public class DiscordGuild implements Serializable { this.guildSongList = guildSongList; } + public List getLogList() { + return logList; + } + + public void setLogList(List logList) { + this.logList = logList; + } + public List getGuildPlaylistList() { return guildPlaylistList; } diff --git a/src/main/java/net/locusworks/discord/eighttrack/database/entities/Log.java b/src/main/java/net/locusworks/discord/eighttrack/database/entities/Log.java new file mode 100644 index 0000000..b9b76b1 --- /dev/null +++ b/src/main/java/net/locusworks/discord/eighttrack/database/entities/Log.java @@ -0,0 +1,135 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package net.locusworks.discord.eighttrack.database.entities; + +import java.io.Serializable; +import java.util.Date; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +/** + * + * @author isaac + */ +@Entity +@Table(name = "log", catalog = "eighttrack", schema = "") +@NamedQueries({ + @NamedQuery(name = "Log.findAll", query = "SELECT l FROM Log l")}) +public class Log implements Serializable { + + private static final long serialVersionUID = 1L; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Basic(optional = false) + @Column(name = "id") + private Long id; + @Basic(optional = false) + @Lob + @Column(name = "log") + private String log; + @Basic(optional = false) + @Column(name = "is_exception") + private boolean isException; + @Basic(optional = false) + @Column(name = "date_added") + @Temporal(TemporalType.TIMESTAMP) + private Date dateAdded; + @JoinColumn(name = "guild", referencedColumnName = "id") + @ManyToOne(optional = false) + private DiscordGuild guild; + + public Log() { + } + + public Log(Long id) { + this.id = id; + } + + public Log(Long id, String log, boolean isException, Date dateAdded) { + this.id = id; + this.log = log; + this.isException = isException; + this.dateAdded = dateAdded; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLog() { + return log; + } + + public void setLog(String log) { + this.log = log; + } + + public boolean getIsException() { + return isException; + } + + public void setIsException(boolean isException) { + this.isException = isException; + } + + public Date getDateAdded() { + return dateAdded; + } + + public void setDateAdded(Date dateAdded) { + this.dateAdded = dateAdded; + } + + public DiscordGuild getGuild() { + return guild; + } + + public void setGuild(DiscordGuild guild) { + this.guild = guild; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (id != null ? id.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof Log)) { + return false; + } + Log other = (Log) object; + if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "net.locusworks.discord.eighttrack.database.entities.Log[ id=" + id + " ]"; + } + +} diff --git a/src/main/java/net/locusworks/discord/eighttrack/database/repos/GuildLogRepository.java b/src/main/java/net/locusworks/discord/eighttrack/database/repos/GuildLogRepository.java new file mode 100644 index 0000000..453cf72 --- /dev/null +++ b/src/main/java/net/locusworks/discord/eighttrack/database/repos/GuildLogRepository.java @@ -0,0 +1,39 @@ +/** + * + * Project: Eight Track, File: GuildRepository.java + * + * Copyright 2019-2019 Locusworks LLC. + * All rights reserved. Federal copyright law prohibits unauthorized reproduction by + * any means and imposes fines up to $25,000 for violation. No part of this material + * may be reproduced, transmitted, transcribed, stored in a retrieval system, copied, + * modified, duplicated, adapted or translated into another program language in any + * form or by any means, electronic, mechanical, photocopying, recording, or + * otherwise, without the prior written permission from Locusworks. Locusworks + * affirms that Eight-Track(R) software and data is subject to United States + * Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive + * Forney TX 75126, (802) 488-0438, for commercial licensing opportunities. + * + * IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, + * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY + * LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF + * THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND + * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS + * IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + */ +package net.locusworks.discord.eighttrack.database.repos; + +import java.util.List; +import org.springframework.data.repository.CrudRepository; +import net.locusworks.discord.eighttrack.database.entities.DiscordGuild; +import net.locusworks.discord.eighttrack.database.entities.Log; + +public interface GuildLogRepository extends CrudRepository { + + List findByGuild(DiscordGuild guild); + +} diff --git a/src/main/java/net/locusworks/discord/eighttrack/handlers/DiscordEventHandler.java b/src/main/java/net/locusworks/discord/eighttrack/handlers/DiscordEventHandler.java index 3559ac5..4930330 100644 --- a/src/main/java/net/locusworks/discord/eighttrack/handlers/DiscordEventHandler.java +++ b/src/main/java/net/locusworks/discord/eighttrack/handlers/DiscordEventHandler.java @@ -43,6 +43,7 @@ import org.springframework.stereotype.Service; import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.events.ExceptionEvent; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; @@ -51,7 +52,7 @@ import net.locusworks.discord.eighttrack.audio.Mp3UploadHandler; import net.locusworks.discord.eighttrack.database.entities.DiscordGuild; import net.locusworks.discord.eighttrack.services.ConfigurationService; import net.locusworks.discord.eighttrack.services.GuildMusicService; -import net.locusworks.discord.eighttrack.services.GuildSongRepoService; +import net.locusworks.discord.eighttrack.services.RepositoryService; import net.locusworks.logger.ApplicationLogger; import net.locusworks.logger.ApplicationLoggerFactory; @@ -69,7 +70,7 @@ public class DiscordEventHandler extends ListenerAdapter { private Mp3UploadHandler uploadHandler; @Autowired - private GuildSongRepoService guildSongRepoService; + private RepositoryService guildSongRepoService; @Autowired private ReactionHandler reactionHandler; @@ -107,7 +108,10 @@ public class DiscordEventHandler extends ListenerAdapter { try { long guildId = event.getGuild().getIdLong(); DiscordGuild discordGuild = guildSongRepoService.getGuildRepo().findByGuildId(guildId); - if (discordGuild != null) return; + if (discordGuild != null) { + guildSongRepoService.logEntry(guildId, "Eight Track joined guild %s", discordGuild.getGuildName()); + return; + } logger.debug("Joining Server: " + event.getGuild().getName()); @@ -117,8 +121,12 @@ public class DiscordEventHandler extends ListenerAdapter { discordGuild.setDateJoined(new Date()); guildSongRepoService.getGuildRepo().save(discordGuild); + + guildSongRepoService.logEntry(guildId, "Eight Track joined guild %s", discordGuild.getGuildName()); + } catch (Exception ex) { logger.error("Unable to persist server information to database: " + ex.getMessage(), ex); + guildSongRepoService.logEntry(event.getGuild().getIdLong(), ex, "Unable to persist guild server info to database: %s", ex.getMessage()); } } @@ -128,9 +136,16 @@ public class DiscordEventHandler extends ListenerAdapter { try { onGuildMessageReceivedHelper(event); } catch (Throwable t) { + guildSongRepoService.logEntry(event.getGuild().getIdLong(), t, "An error occured: %s", t.getMessage()); logger.error(t); } } + + @Override + public void onException(ExceptionEvent event) { + logger.error("A general exception occured: " + event.getCause().getMessage()); + logger.error(event.getCause()); + } private void onGuildMessageReceivedHelper(GuildMessageReceivedEvent event) throws Exception { diff --git a/src/main/java/net/locusworks/discord/eighttrack/handlers/GuildMusicHandler.java b/src/main/java/net/locusworks/discord/eighttrack/handlers/GuildMusicHandler.java index d60cd99..27586ab 100644 --- a/src/main/java/net/locusworks/discord/eighttrack/handlers/GuildMusicHandler.java +++ b/src/main/java/net/locusworks/discord/eighttrack/handlers/GuildMusicHandler.java @@ -71,7 +71,7 @@ import net.locusworks.discord.eighttrack.database.entities.GuildPlaylistSong; import net.locusworks.discord.eighttrack.database.entities.GuildSong; import net.locusworks.discord.eighttrack.database.entities.Song; import net.locusworks.discord.eighttrack.listeners.ReactionListener; -import net.locusworks.discord.eighttrack.services.GuildSongRepoService; +import net.locusworks.discord.eighttrack.services.RepositoryService; import net.locusworks.discord.eighttrack.utils.Reactions; import net.locusworks.logger.ApplicationLogger; import net.locusworks.logger.ApplicationLoggerFactory; @@ -87,7 +87,7 @@ public class GuildMusicHandler { private Consumer callback; private Mp3UploadHandler uploadHandler; - private GuildSongRepoService guildSongRepoService; + private RepositoryService guildSongRepoService; private ReactionHandler reactionHandler; private long guildId; @@ -95,7 +95,7 @@ public class GuildMusicHandler { private TrackManager trackManager; - public GuildMusicHandler(Path musicDir, long guildId, Mp3UploadHandler uploadHandler, ReactionHandler reactionHandler, GuildSongRepoService guildSongRepoService) throws IOException { + public GuildMusicHandler(Path musicDir, long guildId, Mp3UploadHandler uploadHandler, ReactionHandler reactionHandler, RepositoryService guildSongRepoService) throws IOException { this.logger = ApplicationLoggerFactory.getLogger(GuildMusicHandler.class); this.playing = new AtomicBoolean(false); this.musicDir = musicDir; @@ -515,6 +515,10 @@ public class GuildMusicHandler { builder.addField("ID", gs.getUuid(), true); MessageEmbed embed = builder.build(); + + try { + guildSongRepoService.logEntry(event.getGuild().getIdLong(), "%s uploaded", result); + } catch (Exception ex) {} return embed; } @@ -581,8 +585,7 @@ public class GuildMusicHandler { } sb.append("```"); event.getChannel().sendMessage("**" + "Current songs in playlists " + playlist + " for " + event.getMember().getAsMention() + "**").queue((succcess)-> - event.getChannel().sendMessage(sb.toString()).queue() - ); + event.getChannel().sendMessage(sb.toString()).queue()); } diff --git a/src/main/java/net/locusworks/discord/eighttrack/services/GuildSongRepoService.java b/src/main/java/net/locusworks/discord/eighttrack/services/RepositoryService.java similarity index 68% rename from src/main/java/net/locusworks/discord/eighttrack/services/GuildSongRepoService.java rename to src/main/java/net/locusworks/discord/eighttrack/services/RepositoryService.java index e38be4a..24cf15d 100644 --- a/src/main/java/net/locusworks/discord/eighttrack/services/GuildSongRepoService.java +++ b/src/main/java/net/locusworks/discord/eighttrack/services/RepositoryService.java @@ -27,9 +27,14 @@ */ package net.locusworks.discord.eighttrack.services; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - +import net.locusworks.discord.eighttrack.database.entities.DiscordGuild; +import net.locusworks.discord.eighttrack.database.entities.Log; +import net.locusworks.discord.eighttrack.database.repos.GuildLogRepository; import net.locusworks.discord.eighttrack.database.repos.GuildPlaylistRepository; import net.locusworks.discord.eighttrack.database.repos.GuildPlaylistSongRepository; import net.locusworks.discord.eighttrack.database.repos.GuildRepository; @@ -37,7 +42,7 @@ import net.locusworks.discord.eighttrack.database.repos.GuildSongRepository; import net.locusworks.discord.eighttrack.database.repos.SongRepository; @Service -public class GuildSongRepoService { +public class RepositoryService { @Autowired private GuildRepository guildRepo; @@ -53,6 +58,42 @@ public class GuildSongRepoService { @Autowired private SongRepository songRepo; + + @Autowired + private GuildLogRepository guildLogRepo; + + public void logEntry(long guildId, String msg) { + logEntry(guildId, null, "%s", new Object[] {msg}); + } + + public void logEntry(long guildId, String msgFmt, Object... args) { + logEntry(guildId, null, msgFmt, args); + } + + public void logEntry(long guildId, Throwable ex, String msgFmt, Object... args) { + DiscordGuild dg = guildRepo.findByGuildId(guildId); + if (dg == null) return; + + String msg = String.format(msgFmt, args); + if (ex != null) { + msg += "\n" + printTrace(ex); + } + + Log log = new Log(); + log.setDateAdded(new Date()); + log.setGuild(dg); + log.setIsException(ex != null); + log.setLog(msg); + + guildLogRepo.save(log); + } + + private String printTrace(Throwable ex) { + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + return sw.toString(); + } + /** * @return the guildRepo @@ -88,5 +129,9 @@ public class GuildSongRepoService { public final SongRepository getSongRepo() { return songRepo; } + + public final GuildLogRepository getGuildLogRepo() { + return guildLogRepo; + } } diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index d7ae59a..62c45f4 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -7,6 +7,7 @@ net.locusworks.discord.eighttrack.database.entities.DiscordGuild net.locusworks.discord.eighttrack.database.entities.Song net.locusworks.discord.eighttrack.database.entities.GuildPlaylistSong + net.locusworks.discord.eighttrack.database.entities.Log diff --git a/src/main/resources/database/migration/mariadb/Tables/V01_000_001__logtable.sql b/src/main/resources/database/migration/mariadb/Tables/V01_000_001__logtable.sql new file mode 100644 index 0000000..1483563 --- /dev/null +++ b/src/main/resources/database/migration/mariadb/Tables/V01_000_001__logtable.sql @@ -0,0 +1,10 @@ +CREATE TABLE eighttrack.log ( + id bigint(20) NOT NULL AUTO_INCREMENT, + guild bigint(20) NOT NULL, + log longtext NOT NULL, + is_exception tinyint(1) NOT NULL, + date_added timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + PRIMARY KEY (id), + KEY log_fk (guild), + CONSTRAINT log_fk FOREIGN KEY (guild) REFERENCES eighttrack.discord_guild (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file