diff --git a/Plugins/mineplex-google-sheets/pom.xml b/Plugins/mineplex-google-sheets/pom.xml index 864b42200..9a70533c8 100644 --- a/Plugins/mineplex-google-sheets/pom.xml +++ b/Plugins/mineplex-google-sheets/pom.xml @@ -13,6 +13,12 @@ mineplex-google-sheets + + com.googlecode.json-simple + json-simple + 1.1.1 + compile + org.json json diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java index 0c96d03b8..2d5e6becd 100644 --- a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/GoogleSheetController.java @@ -1,74 +1,28 @@ package mineplex.googlesheets; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.awt.*; -import org.json.JSONObject; +import mineplex.googlesheets.sheetparser.SheetProviderImpl; +import mineplex.googlesheets.skinhelper.SkinHelperUI; public class GoogleSheetController { - private static final int SLEEP_TIME = 1000; - private static final String DATA_STORE_DIR = ".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + "files"; - - public static void main(String[] args) throws InterruptedException + public static void main(String[] args) { - String sheetToRead = System.getProperty("sheet"); - SpreadsheetType[] types; + String module = System.getProperty("module"); - if (sheetToRead == null) + if (module == null || module.equalsIgnoreCase("sheetparser")) { - types = SpreadsheetType.values(); + new SheetProviderImpl(); } - else + else if (module.equalsIgnoreCase("skinhelper")) { - types = new SpreadsheetType[]{SpreadsheetType.valueOf(sheetToRead)}; - } - - System.out.println("Loading Sheet Provider"); - SheetProvider provider = new SheetProvider(); - System.out.println("Loaded Sheet Provider"); - - for (SpreadsheetType type : types) - { - System.out.println("Sleeping..."); - Thread.sleep(SLEEP_TIME); - System.out.println("Getting data for " + type.name() + " (" + type.getID() + ")"); - - JSONObject object = provider.asJSONObject(type); - - System.out.println("Done"); - System.out.println("Saving to file..."); - - File dir = new File(DATA_STORE_DIR); - File file = new File(dir + File.separator + type.name() + ".json"); - - if (!dir.exists()) + EventQueue.invokeLater(() -> { - System.out.println("mkdir"); - dir.mkdirs(); - } - - try - { - System.out.println("Deleting"); - file.delete(); - System.out.println("new File"); - file.createNewFile(); - - FileWriter writer = new FileWriter(file); - - System.out.println("Writing"); - writer.write(object.toString()); - - System.out.println("Closing..."); - writer.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } + SkinHelperUI frame = new SkinHelperUI(); + frame.setVisible(true); + }); } } diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java index 665bf33fd..2b26b1815 100644 --- a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java @@ -19,7 +19,7 @@ public enum SpreadsheetType _id = id; } - public String getID() + public String getId() { return _id; } diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SheetProvider.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/sheetparser/SheetProvider.java similarity index 69% rename from Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SheetProvider.java rename to Plugins/mineplex-google-sheets/src/mineplex/googlesheets/sheetparser/SheetProvider.java index 7d7859c49..bc2e3a811 100644 --- a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SheetProvider.java +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/sheetparser/SheetProvider.java @@ -1,11 +1,11 @@ -package mineplex.googlesheets; +package mineplex.googlesheets.sheetparser; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,13 +28,19 @@ import com.google.api.services.sheets.v4.SheetsScopes; import com.google.api.services.sheets.v4.model.Sheet; import com.google.api.services.sheets.v4.model.Spreadsheet; +import mineplex.googlesheets.SpreadsheetType; + +/** + * A provider class designed with the functionality to get data from a Google Spreadsheet.
+ * Then proceed to return this data within the context of a {@link JSONObject}. + */ public class SheetProvider { - /** Application name. */ + /** Service name. */ private static final String APPLICATION_NAME = "Mineplex Google Sheets"; - /** Directory to store user credentials for this application. */ + /** Directory to store user credentials for the service. */ private static final File DATA_STORE_DIR = new File(".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + "files"); /** Global instance of the {@link FileDataStoreFactory}. */ @@ -46,7 +52,8 @@ public class SheetProvider /** Global instance of the HTTP transport. */ private static HttpTransport HTTP_TRANSPORT; - private static final List SCOPES = Arrays.asList(SheetsScopes.SPREADSHEETS); + /** List of all permissions that the service requires */ + private static final List SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS); private Sheets _service; private Credential _credential; @@ -81,9 +88,9 @@ public class SheetProvider * Creates an authorized Credential object. * * @return an authorized Credential object. - * @throws IOException + * @throws IOException If the Credential fails to authorise. */ - public Credential authorize() throws IOException + private Credential authorize() throws IOException { // Load client secrets. InputStream in = new FileInputStream(DATA_STORE_DIR + File.separator + "client_secret.json"); @@ -91,28 +98,37 @@ public class SheetProvider // Build flow and trigger user authorization request. GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES).setDataStoreFactory(DATA_STORE_FACTORY).setAccessType("offline").build(); - Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); - return credential; + return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); } /** * Build and return an authorized Sheets API client service. * * @return an authorized Sheets API client service - * @throws IOException */ - public Sheets getSheetsService() + private Sheets getSheetsService() { return new Sheets.Builder(HTTP_TRANSPORT, JSON_FACTORY, _credential).setApplicationName(APPLICATION_NAME).build(); } + /** + * Returns the data comprised inside a Google Spreadsheet in the context of a {@link JSONObject}. + * + * @param spreadsheet The {@link SpreadsheetType} that you need to get the data from. + * @return A {@link JSONObject} containing all the data about a spreadsheet mapped by sheet -> rows -> columns. + */ public JSONObject asJSONObject(SpreadsheetType spreadsheet) { JSONObject parent = new JSONObject(); JSONArray array = new JSONArray(); Map>> valuesMap = get(spreadsheet); - - for (String sheetName : valuesMap.keySet()) + + if (valuesMap == null) + { + return null; + } + + valuesMap.forEach((sheetName, lists) -> { List> values = valuesMap.get(sheetName); @@ -122,20 +138,21 @@ public class SheetProvider object.put("values", values); array.put(object); - } + }); parent.put("data", array); return parent; } - - public Map>> get(SpreadsheetType spreadsheet) + + private Map>> get(SpreadsheetType spreadsheet) { try { - Spreadsheet googleSpreadsheet = _service.spreadsheets().get(spreadsheet.getID()).execute(); - Map>> valuesMap = new HashMap<>(googleSpreadsheet.getSheets().size() - 1); + Spreadsheet googleSpreadsheet = _service.spreadsheets().get(spreadsheet.getId()).execute(); + List sheets = googleSpreadsheet.getSheets(); + Map>> valuesMap = new HashMap<>(sheets.size()); - for (Sheet sheet : googleSpreadsheet.getSheets()) + for (Sheet sheet : sheets) { String name = sheet.getProperties().getTitle(); @@ -152,9 +169,9 @@ public class SheetProvider return null; } - public List> get(SpreadsheetType spreadsheet, String sheetName) throws IOException + private List> get(SpreadsheetType spreadsheet, String sheetName) throws IOException { - return _service.spreadsheets().values().get(spreadsheet.getID(), sheetName).execute().getValues(); + return _service.spreadsheets().values().get(spreadsheet.getId(), sheetName).execute().getValues(); } } diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/sheetparser/SheetProviderImpl.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/sheetparser/SheetProviderImpl.java new file mode 100644 index 000000000..36618657a --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/sheetparser/SheetProviderImpl.java @@ -0,0 +1,82 @@ +package mineplex.googlesheets.sheetparser; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.json.JSONObject; + +import mineplex.googlesheets.SpreadsheetType; + +public class SheetProviderImpl +{ + + private static final int SLEEP_TIME = 1000; + private static final String DATA_STORE_DIR = ".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + "files"; + + public SheetProviderImpl() + { + String sheetToRead = System.getProperty("sheet"); + SpreadsheetType[] types; + + if (sheetToRead == null) + { + types = SpreadsheetType.values(); + } + else + { + types = new SpreadsheetType[]{SpreadsheetType.valueOf(sheetToRead)}; + } + + System.out.println("Loading Sheet Provider"); + SheetProvider provider = new SheetProvider(); + System.out.println("Loaded Sheet Provider"); + + for (SpreadsheetType type : types) + { + System.out.println("Sleeping..."); + try + { + Thread.sleep(SLEEP_TIME); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + System.out.println("Getting data for " + type.name() + " (" + type.getId() + ")"); + + JSONObject object = provider.asJSONObject(type); + + System.out.println("Done"); + System.out.println("Saving to file..."); + + File dir = new File(DATA_STORE_DIR); + File file = new File(dir + File.separator + type.name() + ".json"); + + if (!dir.exists()) + { + dir.mkdirs(); + } + + try + { + System.out.println("Deleting"); + file.delete(); + System.out.println("Creating a new file"); + file.createNewFile(); + + FileWriter writer = new FileWriter(file); + + System.out.println("Writing"); + writer.write(object.toString()); + + System.out.println("Closing..."); + writer.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } +} diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/skinhelper/SkinHelperUI.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/skinhelper/SkinHelperUI.java new file mode 100644 index 000000000..5994e634c --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/skinhelper/SkinHelperUI.java @@ -0,0 +1,115 @@ +package mineplex.googlesheets.skinhelper; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.TimeUnit; + +import mineplex.googlesheets.util.SkinFetcher; +import mineplex.googlesheets.util.UUIDFetcher; + +public class SkinHelperUI extends JFrame +{ + + private static final Font FONT = new Font("Verdana", Font.PLAIN, 12); + private static final long FETCH_WAIT_TIME = 30; + private static final long FETCH_WAIT_MILLISECONDS = TimeUnit.SECONDS.toMillis(FETCH_WAIT_TIME); + + private long _lastFetch; + + public SkinHelperUI() + { + setTitle("Skin Helper"); + setResizable(false); + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + setBounds(100, 100, 150, 300); + JPanel contentPane = new JPanel(); + contentPane.setBackground(Color.DARK_GRAY); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(null); + + JTextField txtMinecraftName = new JTextField(); + txtMinecraftName.setFont(FONT); + txtMinecraftName.setForeground(Color.WHITE); + txtMinecraftName.setBackground(Color.GRAY); + txtMinecraftName.setBounds(10, 55, 124, 20); + txtMinecraftName.setColumns(10); + contentPane.add(txtMinecraftName); + + JLabel lblMinecraftName = new JLabel("Minecraft Name"); + lblMinecraftName.setForeground(Color.WHITE); + lblMinecraftName.setFont(FONT); + lblMinecraftName.setBounds(10, 30, 100, 14); + contentPane.add(lblMinecraftName); + + JButton btnOk = new JButton("OK"); + btnOk.setForeground(Color.WHITE); + btnOk.setBackground(Color.DARK_GRAY); + btnOk.setBounds(10, 86, 124, 23); + contentPane.add(btnOk); + + JLabel lblSkinValue = new JLabel("Skin Value"); + lblSkinValue.setForeground(Color.WHITE); + lblSkinValue.setFont(FONT); + lblSkinValue.setBounds(10, 120, 100, 14); + contentPane.add(lblSkinValue); + + JTextField txtSkinValue = new JTextField(); + txtSkinValue.setEditable(false); + txtSkinValue.setForeground(Color.WHITE); + txtSkinValue.setBackground(Color.GRAY); + txtSkinValue.setFont(FONT); + txtSkinValue.setColumns(10); + txtSkinValue.setBounds(10, 145, 124, 20); + contentPane.add(txtSkinValue); + + JLabel lblSkinSignature = new JLabel("Skin Signature"); + lblSkinSignature.setForeground(Color.WHITE); + lblSkinSignature.setFont(FONT); + lblSkinSignature.setBounds(10, 176, 100, 14); + contentPane.add(lblSkinSignature); + + JTextField txtSkinSignature = new JTextField(); + txtSkinSignature.setEditable(false); + txtSkinSignature.setForeground(Color.WHITE); + txtSkinSignature.setBackground(Color.GRAY); + txtSkinSignature.setFont(FONT); + txtSkinSignature.setColumns(10); + txtSkinSignature.setBounds(10, 201, 124, 20); + contentPane.add(txtSkinSignature); + + btnOk.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent event) + { + if (System.currentTimeMillis() - _lastFetch < FETCH_WAIT_MILLISECONDS) + { + JOptionPane.showMessageDialog(SkinHelperUI.this, "You must wait a minimum of " + FETCH_WAIT_TIME + " seconds between each skin fetch to prevent you from being blocked from using the Mojang API."); + return; + } + + txtSkinValue.setText("Fetching..."); + txtSkinSignature.setText(txtSkinValue.getText()); + + try + { + String[] skinData = SkinFetcher.getSkinData(UUIDFetcher.getPlayerUUIDNoDashes(txtMinecraftName.getText())); + + txtSkinValue.setText(skinData[0]); + txtSkinSignature.setText(skinData[1]); + + _lastFetch = System.currentTimeMillis(); + } + catch (Exception e) + { + e.printStackTrace(); + JOptionPane.showMessageDialog(SkinHelperUI.this, "Please check the Minecraft Name you have entered. If it is correct please wait a minute and try again."); + } + } + }); + } +} diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/SkinFetcher.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/SkinFetcher.java new file mode 100644 index 000000000..a8bdf6666 --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/SkinFetcher.java @@ -0,0 +1,42 @@ +package mineplex.googlesheets.util; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +public class SkinFetcher +{ + + private static final String SKIN_URL = "https://sessionserver.mojang.com/session/minecraft/profile/UUID?unsigned=false"; + + public static String[] getSkinData(String uuid) throws Exception + { + String[] skinData = new String[2]; + JSONObject object = UtilJSON.getFromURL(SKIN_URL.replaceFirst("UUID", uuid)); + JSONArray properties = (JSONArray) object.get("properties"); + + System.out.println(properties.size()); + + for (Object o : properties) + { + System.out.println(o.toString()); + } + + JSONObject innerObject = (JSONObject) properties.get(0); + + System.out.println(innerObject.size()); + + for (Object o : innerObject.entrySet()) + { + System.out.println(o.toString()); + } + + skinData[1] = (String) innerObject.get("signature"); + skinData[0] = (String) innerObject.get("value"); + + System.out.println(skinData[0]); + System.out.println(skinData[1]); + + return skinData; + } + +} diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/UUIDFetcher.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/UUIDFetcher.java new file mode 100644 index 000000000..92c50787b --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/UUIDFetcher.java @@ -0,0 +1,62 @@ +package mineplex.googlesheets.util; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Collections; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +/** + * A utility to fetch UUIDs based on a player's name. + * Adapted from UUIDFetcher inside Core.Common. + */ +public class UUIDFetcher +{ + + private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; + private static final JSONParser PARSER = new JSONParser(); + + public static String getPlayerUUIDNoDashes(String name) throws Exception + { + String uuid = null; + List nameList = Collections.singletonList(name); + + HttpURLConnection connection = createConnection(); + String body = JSONArray.toJSONString(nameList); + writeBody(connection, body); + JSONArray array = (JSONArray) PARSER.parse(new InputStreamReader(connection.getInputStream())); + + for (Object profile : array) + { + JSONObject jsonProfile = (JSONObject) profile; + uuid = (String) jsonProfile.get("id"); + } + + return uuid; + } + + private static void writeBody(HttpURLConnection connection, String body) throws Exception + { + OutputStream stream = connection.getOutputStream(); + stream.write(body.getBytes()); + stream.flush(); + stream.close(); + } + + private static HttpURLConnection createConnection() throws Exception + { + URL url = new URL(PROFILE_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + return connection; + } +} \ No newline at end of file diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/UtilJSON.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/UtilJSON.java new file mode 100644 index 000000000..5488d3217 --- /dev/null +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/util/UtilJSON.java @@ -0,0 +1,41 @@ +package mineplex.googlesheets.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.nio.charset.Charset; + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +public class UtilJSON +{ + + private static final JSONParser PARSER = new JSONParser(); + + private static String readAll(Reader rd) throws IOException + { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) + { + sb.append((char) cp); + } + return sb.toString(); + } + + public static JSONObject getFromURL(String url) throws IOException, ParseException + { + try (InputStream is = new URL(url).openStream()) + { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + return (JSONObject) PARSER.parse(jsonText); + } + } + +}