Adds a migrate command for fixing book names and text -> yml
This commit is contained in:
@@ -15,6 +15,7 @@ import net.knarcraft.bookswithoutborders.command.CommandGivePublic;
|
|||||||
import net.knarcraft.bookswithoutborders.command.CommandGroupEncrypt;
|
import net.knarcraft.bookswithoutborders.command.CommandGroupEncrypt;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandLoad;
|
import net.knarcraft.bookswithoutborders.command.CommandLoad;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandLoadPublic;
|
import net.knarcraft.bookswithoutborders.command.CommandLoadPublic;
|
||||||
|
import net.knarcraft.bookswithoutborders.command.CommandMigrate;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandReload;
|
import net.knarcraft.bookswithoutborders.command.CommandReload;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandSave;
|
import net.knarcraft.bookswithoutborders.command.CommandSave;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandSavePublic;
|
import net.knarcraft.bookswithoutborders.command.CommandSavePublic;
|
||||||
@@ -260,6 +261,7 @@ public class BooksWithoutBorders extends JavaPlugin {
|
|||||||
registerCommand(BwBCommand.SET_BOOKSHELF_DATA.toString(), new CommandSetBookshelfData());
|
registerCommand(BwBCommand.SET_BOOKSHELF_DATA.toString(), new CommandSetBookshelfData());
|
||||||
registerCommand(BwBCommand.ADD_TITLE_PAGE.toString(), new CommandAddTitlePage());
|
registerCommand(BwBCommand.ADD_TITLE_PAGE.toString(), new CommandAddTitlePage());
|
||||||
registerCommand(BwBCommand.DELETE_PAGE.toString(), new CommandDeletePage());
|
registerCommand(BwBCommand.DELETE_PAGE.toString(), new CommandDeletePage());
|
||||||
|
registerCommand(BwBCommand.MIGRATE.toString(), new CommandMigrate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,149 @@
|
|||||||
|
package net.knarcraft.bookswithoutborders.command;
|
||||||
|
|
||||||
|
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||||
|
import net.knarcraft.bookswithoutborders.config.Translatable;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.BookFileHelper;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.BookHelper;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.BookToFromTextHelper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.meta.BookMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command executor for the migrate command
|
||||||
|
*/
|
||||||
|
public class CommandMigrate implements TabExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s,
|
||||||
|
@NotNull String[] arguments) {
|
||||||
|
if (!(sender instanceof Player player)) {
|
||||||
|
BooksWithoutBorders.getStringFormatter().displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File bookDirectory = new File(BooksWithoutBorders.getConfiguration().getBookFolder());
|
||||||
|
boolean success = migrateFiles(bookDirectory, player);
|
||||||
|
if (success) {
|
||||||
|
BooksWithoutBorders.sendSuccessMessage(player, "Successfully migrated all books!");
|
||||||
|
} else {
|
||||||
|
BooksWithoutBorders.sendErrorMessage(player, "Failed to migrate all books!");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
|
||||||
|
@NotNull String[] arguments) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrates the given folder recursively
|
||||||
|
*
|
||||||
|
* @param folder <p>The folder to migrate files for</p>
|
||||||
|
* @param player <p>The player causing this code to be executed</p>
|
||||||
|
* @return <p>If all migrations were successful</p>
|
||||||
|
*/
|
||||||
|
private boolean migrateFiles(@NotNull File folder, @NotNull Player player) {
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
BooksWithoutBorders.log(Level.WARNING, "Unable to access directory " + folder.getName() + " !");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean success = true;
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
success = success & migrateFiles(file, player);
|
||||||
|
} else if (file.isFile()) {
|
||||||
|
success = success & migrateFile(file, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrates a single book file
|
||||||
|
*
|
||||||
|
* @param file <p>The file to migrate</p>
|
||||||
|
* @param player <p>The player causing this code to be executed</p>
|
||||||
|
* @return <p>True if the migration completed successfully</p>
|
||||||
|
*/
|
||||||
|
private boolean migrateFile(@NotNull File file, @NotNull Player player) {
|
||||||
|
BookMeta bookMeta = (BookMeta) BooksWithoutBorders.getItemFactory().getItemMeta(Material.WRITTEN_BOOK);
|
||||||
|
if (bookMeta == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BookMeta loadedBook;
|
||||||
|
String extension = BookFileHelper.getExtensionFromPath(file.getName());
|
||||||
|
if (extension.equalsIgnoreCase("yml")) {
|
||||||
|
loadedBook = BookToFromTextHelper.encryptedBookFromYml(file, bookMeta, "", true);
|
||||||
|
} else if (extension.equalsIgnoreCase("txt")) {
|
||||||
|
loadedBook = BookToFromTextHelper.bookFromFile(file, bookMeta);
|
||||||
|
} else {
|
||||||
|
BooksWithoutBorders.log(Level.WARNING, "File with unexpected extension " + extension + " encountered!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadedBook == null) {
|
||||||
|
BooksWithoutBorders.log(Level.SEVERE, "Unable to load book: " + file.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to retain UUID naming
|
||||||
|
boolean isPublic = true;
|
||||||
|
OfflinePlayer author = player;
|
||||||
|
try {
|
||||||
|
UUID authorId = UUID.fromString(file.getParentFile().getName());
|
||||||
|
author = Bukkit.getOfflinePlayer(authorId);
|
||||||
|
isPublic = false;
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String newName = BookHelper.getBookFile(loadedBook, author, isPublic);
|
||||||
|
return saveBook(file.getParentFile(), newName, loadedBook, file);
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
BooksWithoutBorders.sendErrorMessage(player, "Failed to migrate book: " + file.getName() + " Cause:");
|
||||||
|
BooksWithoutBorders.sendErrorMessage(player, exception.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a migrated book
|
||||||
|
*
|
||||||
|
* @param parent <p>The parent folder the file belongs to</p>
|
||||||
|
* @param newName <p>The new name of the file</p>
|
||||||
|
* @param bookMeta <p>The metadata of the book to migrate</p>
|
||||||
|
* @param oldFile <p>The old file path, in case it should be deleted</p>
|
||||||
|
* @return <p>True if successfully saved</p>
|
||||||
|
*/
|
||||||
|
private boolean saveBook(@NotNull File parent, @NotNull String newName, @NotNull BookMeta bookMeta,
|
||||||
|
@NotNull File oldFile) {
|
||||||
|
try {
|
||||||
|
BookToFromTextHelper.bookToYml(parent.getAbsolutePath(), newName, bookMeta);
|
||||||
|
if (!oldFile.getAbsolutePath().equalsIgnoreCase(new File(parent, newName + ".yml").getAbsolutePath())) {
|
||||||
|
return oldFile.delete();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException exception) {
|
||||||
|
BooksWithoutBorders.log(Level.SEVERE, "Failed to save migrated book: " + newName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -26,7 +26,7 @@ public class BooksWithoutBordersConfig {
|
|||||||
private final ChatColor commandColor = ChatColor.YELLOW;
|
private final ChatColor commandColor = ChatColor.YELLOW;
|
||||||
private final String SLASH = FileSystems.getDefault().getSeparator();
|
private final String SLASH = FileSystems.getDefault().getSeparator();
|
||||||
private boolean isInitialized;
|
private boolean isInitialized;
|
||||||
public String bookFolder;
|
private final String bookFolder;
|
||||||
|
|
||||||
private int bookDuplicateLimit;
|
private int bookDuplicateLimit;
|
||||||
private String titleAuthorSeparator;
|
private String titleAuthorSeparator;
|
||||||
|
@@ -138,6 +138,11 @@ public enum BwBCommand {
|
|||||||
* Deletes a page from the held book
|
* Deletes a page from the held book
|
||||||
*/
|
*/
|
||||||
DELETE_PAGE("deleteBookPage", true),
|
DELETE_PAGE("deleteBookPage", true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrates all books, fixing any problems with their names, and converts txt books to yml
|
||||||
|
*/
|
||||||
|
MIGRATE("migrateBooks", true),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final @NotNull String commandName;
|
private final @NotNull String commandName;
|
||||||
|
@@ -276,7 +276,7 @@ public class SignEventListener implements Listener {
|
|||||||
if (file == null) {
|
if (file == null) {
|
||||||
file = BookFileHelper.findBookFile(encryptedFolder, oldBook);
|
file = BookFileHelper.findBookFile(encryptedFolder, oldBook);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
file = BookFileHelper.findBookFile(config.bookFolder, oldBook);
|
file = BookFileHelper.findBookFile(config.getBookFolder(), oldBook);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
BooksWithoutBorders.sendErrorMessage(player, "Unable to find encrypted book");
|
BooksWithoutBorders.sendErrorMessage(player, "Unable to find encrypted book");
|
||||||
return;
|
return;
|
||||||
|
@@ -220,6 +220,24 @@ public final class BookFileHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips the extension from the given path
|
||||||
|
*
|
||||||
|
* @param path <p>The path to strip the extension from</p>
|
||||||
|
* @return <p>The input with the extension stripped</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String getExtensionFromPath(@NotNull String path) {
|
||||||
|
int dotIndex = path.lastIndexOf(".");
|
||||||
|
if (dotIndex > 0) {
|
||||||
|
String separator = BooksWithoutBorders.getConfiguration().getTitleAuthorSeparator();
|
||||||
|
if (path.lastIndexOf(separator) < dotIndex && (path.length() - dotIndex == 4)) {
|
||||||
|
return path.substring(dotIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strips the extension from the given path
|
* Strips the extension from the given path
|
||||||
*
|
*
|
||||||
|
@@ -6,6 +6,7 @@ import net.knarcraft.bookswithoutborders.config.Translatable;
|
|||||||
import net.knarcraft.bookswithoutborders.state.BookDirectory;
|
import net.knarcraft.bookswithoutborders.state.BookDirectory;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
@@ -159,8 +160,8 @@ public final class BookHelper {
|
|||||||
* @throws IllegalArgumentException <p>If the book title or author contains the title author separator</p>
|
* @throws IllegalArgumentException <p>If the book title or author contains the title author separator</p>
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String getBookFile(@NotNull BookMeta book, @NotNull Player player, boolean isPublic) throws IllegalArgumentException {
|
public static String getBookFile(@NotNull BookMeta book, @NotNull OfflinePlayer player, boolean isPublic) throws IllegalArgumentException {
|
||||||
String titleAuthorSeparator = BooksWithoutBorders.getConfiguration().getTitleAuthorSeparator();
|
String separator = BooksWithoutBorders.getConfiguration().getTitleAuthorSeparator();
|
||||||
String bookName;
|
String bookName;
|
||||||
if (book.hasTitle()) {
|
if (book.hasTitle()) {
|
||||||
bookName = book.getTitle();
|
bookName = book.getTitle();
|
||||||
@@ -171,8 +172,9 @@ public final class BookHelper {
|
|||||||
bookName = "Untitled";
|
bookName = "Untitled";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String playerName = player.getName() == null ? player.getUniqueId().toString() : player.getName();
|
||||||
String authorName;
|
String authorName;
|
||||||
if ((!book.hasAuthor() || isAuthor(player.getName(), book.getAuthor())) && !isPublic) {
|
if ((!book.hasAuthor() || isAuthor(playerName, book.getAuthor())) && !isPublic) {
|
||||||
//Store as unique id to account for name changes
|
//Store as unique id to account for name changes
|
||||||
authorName = player.getUniqueId().toString();
|
authorName = player.getUniqueId().toString();
|
||||||
} else if (!book.hasAuthor()) {
|
} else if (!book.hasAuthor()) {
|
||||||
@@ -184,12 +186,14 @@ public final class BookHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bookName.contains(titleAuthorSeparator) || authorName.contains(titleAuthorSeparator)) {
|
if (InputCleaningHelper.cleanString(bookName).contains(separator) ||
|
||||||
throw new IllegalArgumentException("The author or title contains the title author separator. Saving this " +
|
InputCleaningHelper.cleanString(authorName).contains(separator)) {
|
||||||
|
throw new IllegalArgumentException("The author; " + authorName + " or title; " + bookName +
|
||||||
|
" contains the title author separator (" + separator + "). Saving this " +
|
||||||
"book would lead to unexpected problems.");
|
"book would lead to unexpected problems.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return InputCleaningHelper.cleanString(bookName + titleAuthorSeparator + authorName);
|
return InputCleaningHelper.cleanString(bookName + separator + authorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -39,7 +39,7 @@ public final class BookToFromTextHelper {
|
|||||||
*/
|
*/
|
||||||
public static void bookToYml(@NotNull String path, @NotNull String fileName, @NotNull BookMeta bookMetadata) throws IOException {
|
public static void bookToYml(@NotNull String path, @NotNull String fileName, @NotNull BookMeta bookMetadata) throws IOException {
|
||||||
FileConfiguration bookYml = getBookConfiguration(bookMetadata);
|
FileConfiguration bookYml = getBookConfiguration(bookMetadata);
|
||||||
bookYml.save(path + fileName + ".yml");
|
bookYml.save(new File(path, fileName + ".yml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -109,6 +109,10 @@ commands:
|
|||||||
description: Deletes one page from a book
|
description: Deletes one page from a book
|
||||||
usage: /<command> <page>
|
usage: /<command> <page>
|
||||||
permission: bookswithoutborders.deletepage
|
permission: bookswithoutborders.deletepage
|
||||||
|
migrateBooks:
|
||||||
|
description: Migrates all txt books to yml, and fixes any incorrect filenames
|
||||||
|
usage: /<command>
|
||||||
|
permission: bookswithoutborders.admin
|
||||||
permissions:
|
permissions:
|
||||||
bookswithoutborders.*:
|
bookswithoutborders.*:
|
||||||
description: Grants all permissions
|
description: Grants all permissions
|
||||||
|
Reference in New Issue
Block a user