diff --git a/GESI.gs b/GESI.gs
index 2ce1f48..ae464e3 100644
--- a/GESI.gs
+++ b/GESI.gs
@@ -1,1334 +1,1057 @@
- // Google ESI (GESI)
- // Modified version of https://github.com/googlesamples/apps-script-oauth2 to work with EVE SSO/ESI endpoints
- //
- // /u/blacksmoke16 @ Reddit
- // @Blacksmoke16#1684 @ Discord
- app_version = '0.3.7.0';
-
- // Setup variables used throughout script
- CLIENT_ID = '7c382c66a6c8487d8b64e50daad86f9b';
- CLIENT_SECRET = 'CwcYrVs05AtIbqZkJH8OrBPYps6MAH72qQ1Gf68t';
- BASE_URL = 'https://esi.tech.ccp.is/v'
-
- // Setup endpoint and version list
- endpoints = {
- "skills": {
- "version": 4,
- "url": "/characters/{character_id}/skills/",
- "name": "skills",
- "description": "Default: LIST, LIST for list of skills, TOTAL for total skill points.",
- "parameters": [
- {
- "name": "option",
- "description": "LIST for list of skills, TOTAL for total skill points."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "skillQueue": {
- "version": 2,
- "url": "/characters/{character_id}/skillqueue/",
- "name": "skillQueue",
- "description": "Returns the user\"s current skill queue.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "marketPrices": {
- "version": 1,
- "url": "/markets/prices/",
- "name": "marketPrices",
- "description": "Returns the avgerage and adjusted prices for various itemIDs.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "structureMarketOrders": {
- "version": 1,
- "url": "/markets/structures/{structure_id}/",
- "name": "structureMarketOrders",
- "description": "Returns all market orders in a given structure.",
- "parameters": [
- {
- "name": "structure_id",
- "description": "StructureID of the structure to get market orders."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "itemTypes": {
- "version": 3,
- "url": "/universe/types/{type_id}/",
- "name": "itemTypes",
- "description": "Returns information about a type.",
- "parameters": [
- {
- "name": "ids",
- "description": "Single typeID or list of typeIDs to lookup."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterAssets": {
- "version": 1,
- "url": "/characters/{character_id}/assets/",
- "name": "characterAssets",
- "description": "Returns a list of the character\"s assets",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterWallet": {
- "version": 1,
- "url": "/characters/{character_id}/wallet/",
- "name": "characterWallet",
- "description": "Returns the balance of your wallet.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterLoyalty": {
- "version": 1,
- "url": "/characters/{character_id}/loyalty/points/",
- "name": "characterLoyalty",
- "description": "Returns a list of loyalty points for all corporations the character has worked for.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "corporationLoyalty": {
- "version": 1,
- "url": "/loyalty/stores/{corporation_id}/offers/",
- "name": "corporationLoyalty",
- "description": "Returns a list of offers from a specific corporation\"s loyalty store.",
- "parameters": [
- {
- "name": "corporation_id",
- "description": "Corporation ID to get the loyalty point store for."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterPlanets": {
- "version": 1,
- "url": "/characters/{character_id}/planets/",
- "name": "characterPlanets",
- "description": "Returns a list of all planetary colonies owned by a character.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterPlanetDetails": {
- "version": 2,
- "url": "/characters/{character_id}/planets/{planet_id}/",
- "name": "characterPlanetDetails",
- "description": "Returns full details on the layout of a single planetary colony, including links, pins and routes. ",
- "parameters": [
- {
- "name": "planet_id",
- "description": "ID of the planet to get details on."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "planetSchematic": {
- "version": 1,
- "url": "/universe/schematics/{schematic_id}/",
- "name": "planetSchematic",
- "description": "Returns information on a planetary factory schematic.",
- "parameters": [
- {
- "name": "schematic_id",
- "description": "ID of the schematic to get information on."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterBlueprints": {
- "version": 1,
- "url": "/characters/{character_id}/blueprints/",
- "name": "characterBlueprints",
- "description": "Returns a list of blueprints the character has.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterIndustryJobs": {
- "version": 1,
- "url": "/characters/{character_id}/industry/jobs/",
- "name": "characterIndustryJobs",
- "description": "Returns a list of industry jobs placed by a character.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterMarketOrders": {
- "version": 1,
- "url": "/characters/{character_id}/orders/",
- "name": "characterMarketOrders",
- "description": "Returns a list of market orders placed by a character.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterWalletJournal": {
- "version": 1,
- "url": "/characters/{character_id}/wallet/journal/",
- "name": "characterWalletJournal",
- "description": "Returns a character\"s wallet journal.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterContracts": {
- "version": 1,
- "url": "/characters/{character_id}/contracts/",
- "name": "characterContracts",
- "description": "Returns a list of a character\"s contracts.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterContractBids": {
- "version": 1,
- "url": "/characters/{character_id}/contracts/{contract_id}/bids/",
- "name": "characterContractBids",
- "description": "Returns bids on a particular auction contract.",
- "parameters": [
- {
- "name": "contract_id",
- "description": "ID of the contract to get bids for."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterContractItems": {
- "version": 1,
- "url": "/characters/{character_id}/contracts/{contract_id}/items/",
- "name": "characterContractItems",
- "description": "Returns Items and details of a particular contract.",
- "parameters": [
- {
- "name": "contract_id",
- "description": "ID of the contract to get information on."
- },
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "characterWalletTransactions": {
- "version": 1,
- "url": "/characters/{character_id}/wallet/transactions/",
- "name": "characterWalletTransactions",
- "description": "Returns a character\"s wallet transactions.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "industryFacilities": {
- "version": 1,
- "url": "/industry/facilities/",
- "name": "industryFacilities",
- "description": "Return a list of industry facilities.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- },
- "industrySystems": {
- "version": 1,
- "url": "/industry/systems/",
- "name": "industrySystems",
- "description": "Return cost indices for solar systems.",
- "parameters": [
- {
- "name": "opt_headers",
- "description": "Default: True, Boolean if column headings should be listed or not."
- }
- ]
- }
- };
-
- function onOpen() {
- SpreadsheetApp.getUi().createMenu('GESI')
- .addItem('Authorize Sheet', 'showSidebar')
- .addSeparator()
- .addItem('Reset Auth', 'clearService')
- .addToUi();
- }
-
-
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Skills
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
-
- /**
- * Returns a list of Skill names, current points in skill and current level or total skill points.
- * @param {string} option Default: LIST, LIST for list of skills, TOTAL for total skill points.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of Skill names, current points in skill and current level or total skill points.
- * @customfunction
- */
- function skills(option, opt_headers) {
- var skill_list = new Array();
- var ids = new Array();
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- if (option === undefined) { option = "LIST"; };
- option = option.toLowerCase();
-
- if (option == 'list') {
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { skill_list.push(['Name', 'Active Level', 'Trained Level', 'SP In Skill']); };
-
- for (var i = 0; i < response.skills.length; i++) {
- ids.push(response.skills[i].skill_id);
- skill_list.push([
- response.skills[i].skill_id,
- response.skills[i].active_skill_level,
- response.skills[i].trained_skill_level,
- response.skills[i].skillpoints_in_skill
- ]);
- }
-
- var skill_names = id2name_(ids);
-
- for (var i = 0; i < skill_list.length; i++) {
- for (var n = 0; n < skill_names.length; n++) {
- if (skill_list[i][0] == skill_names[n].id) {
- skill_list[i][0] = skill_names[n].name
- }
- }
- }
- } else if (option == 'total') {
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { skill_list.push('Total SP'); };
- skill_list.push(response.total_sp);
- }
- return skill_list;
- }
-
- /**
- * Returns the user's current skill queue.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns the users' current skill queue.
- * @customfunction
- */
- function skillQueue(opt_headers) {
- var skills = new Array();
- var ids = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { skills.push(['Name', 'Finished Level', 'Start Date', 'Finish Date', 'Position']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- ids.push(response[i].skill_id);
- skills.push([
- response[i].skill_id,
- response[i].finished_level,
- response[i].start_date,
- response[i].finish_date,
- response[i].queue_position
- ]);
- }
-
- var skill_names = id2name_(ids);
-
- for (var i = 0; i < skills.length; i++) {
- for (var n = 0; n < skill_names.length; n++) {
- if (skills[i][0] == skill_names[n].id) {
- skills[i][0] = skill_names[n].name
- }
- }
- }
-
- return skills;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Market
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns the avgerage and adjusted prices for various itemIDs.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns the avgerage and adjusted prices for various itemIDs.
- * @customfunction
- */
- function marketPrices(opt_headers) {
- var items = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { items.push(['typeID', 'Adjusted Price', 'Average Price']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- items.push([
- response[i].type_id,
- response[i].adjusted_price,
- response[i].average_price
- ]);
- }
-
- return items;
- }
-
- /**
- * Returns all market orders in a given structure.
- * @param {number} structure_id ID of the structure to get market orders for.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns all market orders in a given structure.
- * @customfunction
- */
- function structureMarketOrders(structure_id, opt_headers) {
- var items = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { items.push(['Order ID', 'Buy Order?', 'Type ID', 'Location ID', 'Price', 'issued', 'Range', 'Duration', 'Min Volume', 'Remaining Volume', 'Total Volume']); };
-
- var response = JSON.parse(getData_(arguments.callee.name,structure_id));
-
- for (var i = 0; i < response.length; i++) {
- items.push([
- response[i].order_id,
- response[i].is_buy_order,
- response[i].type_id,
- response[i].location_id,
- response[i].price,
- response[i].issued,
- response[i].range,
- response[i].duration,
- response[i].min_volume,
- response[i].volume_remain,
- response[i].volume_total
- ]);
- }
-
- return items;
- }
-
- /**
- * List of market orders placed by a character.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a ist of market orders placed by a character.
- * @customfunction
- */
- function characterMarketOrders(opt_headers) {
- var orders_list = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { orders_list.push(['Order ID', 'Buy Order?', 'Type ID', 'State', 'Location ID', 'Station ID', 'Price', 'issued', 'Range', 'Escrow', 'Region ID', 'Duration', 'Is Corp?', 'Min Volume', 'Remaining Volume', 'Total Volume']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- orders_list.push([
- response[i].order_id,
- response[i].is_buy_order,
- response[i].type_id,
- response[i].state,
- response[i].location_id,
- response[i].station_id,
- response[i].price,
- response[i].issued,
- response[i].range,
- response[i].escrow,
- response[i].region_id,
- response[i].duration,
- response[i].is_corp,
- response[i].min_volume,
- response[i].volume_remain,
- response[i].volume_total
- ]);
- }
- return orders_list;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Universe
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns information about a type.
- * @param {number/array} ids Single typeID or list of typeIDs to lookup.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns information about a type.
- * @customfunction
- */
- function itemTypes(ids, opt_headers) {
- var items = new Array();
- var typeIDs = new Array();
- var array_length = ids.length;
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { items.push(['Type ID', 'Type Name', 'Volume', 'Group ID', 'Market Group ID', 'Published?']); };
- if (!Array.isArray(ids)) { typeIDs.push(ids);
- array_length = 1; } else { typeIDs = ids; };
-
- for (var i = 0; i < array_length; i++) {
- var response = JSON.parse(getData_(arguments.callee.name, typeIDs[i]));
- items.push([
- response.type_id,
- response.name,
- response.volume,
- response.group_id,
- response.market_group_id,
- response.published
- ]);
- }
-
- return items;;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Assets
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns a list of the character's assets.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of the characters assets.
- * @customfunction
- */
- function characterAssets(opt_headers) {
- var items = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { items.push(['ItemID', 'TypeID', 'Quantity', 'LocationID', 'Location Type', 'Location Flag']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- var quantity = 1;
- if (!response[i].is_singleton) { quantity = response[i].quantity };
- items.push([
- response[i].item_id,
- response[i].type_id,
- quantity,
- response[i].location_id,
- response[i].location_type,
- response[i].location_flag
- ]);
- }
- return items;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Loyalty
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns Returns a list of loyalty points for all corporations the character has worked for.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of loyalty points for all corporations the character has worked for.
- * @customfunction
- */
- function characterLoyalty(opt_headers) {
- var points = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { points.push(['Corporation ID', 'Loyalty Points']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
- for (var i = 0; i < response.length; i++) {
- points.push([
- response[i].corporation_id,
- response[i].loyalty_points
- ]);
- }
- return points;
- }
-
- /**
- * Returns a list of offers from a specific corporation's loyalty store.
- * @param {number} corporation_id ID of the corporation to get the loyalty point store for.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of offers from a specific corporation's loyalty store.
- * @customfunction
- */
- function corporationLoyalty(corporation_id, opt_headers) {
- var items = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { items.push(['Type ID', 'Quantity', 'ISK Cost', 'LP Cost', 'Offer ID', 'Required Item', 'Required Quantity']); };
-
- var response = JSON.parse(getData_(arguments.callee.name, corporation_id));
-
- for (var i = 0; i < response.length; i++) {
- for (var r = 0; r < response[i].required_items.length; r++) {
-
- items.push([
- response[i].type_id,
- response[i].quantity,
- response[i].isk_cost,
- response[i].lp_cost,
- response[i].offer_id,
- response[i].required_items[r].type_id,
- response[i].required_items[r].quantity
- ]);
- };
- };
- return items;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Wallet
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns the balance of your wallet.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns the balance of your wallet.
- * @customfunction
- */
- function characterWallet(opt_headers) {
- var wallet_data = new Array();
-
- if (opt_headers === undefined) opt_headers = true;
- if (opt_headers) { wallet_data.push(['Balance']); };
-
- var response = getData_(arguments.callee.name);
-
- wallet_data.push([parseFloat(response)]);
-
- return wallet_data;
- }
-
- /**
- * Retrieve character wallet journal.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Retrieve character wallet journal.
- * @customfunction
- */
- function characterWalletJournal(opt_headers) {
- var entries = new Array();
-
- if (opt_headers === undefined) opt_headers = true;
- if (opt_headers) entries.push(['Ref ID', 'Date', 'Ref Type', 'Amount', 'Balance', 'Description', 'Tax Reciver ID', 'First Party Type', 'First Party ID', 'Second Party Type', 'Second Party ID', 'Extra Info:']);
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- entries.push([
- response[i].ref_id,
- response[i].date,
- response[i].ref_type,
- response[i].amount,
- response[i].balance,
- response[i].reason,
- response[i].tax_reciever_id,
- response[i].first_party_type,
- response[i].first_party_id,
- response[i].second_party_type,
- response[i].second_party_id
- ]);
- if (!(response[i].hasOwnProperty('extra_info'))) continue;
- if (i === 0) entries[i].push('Alliance ID', 'Character ID', 'Corporation ID', 'Contract ID', 'Destroyed Ship Type ID', 'Job ID', 'Location ID', 'NPC ID', 'NPC Name', 'Planet ID', 'System ID', 'Transaction ID');
- entries[i].push(
- '',
- response[i].extra_info.alliance_id,
- response[i].extra_info.character_id,
- response[i].extra_info.corporation_id,
- response[i].extra_info.contract_id,
- response[i].extra_info.destroyed_ship_type_id,
- response[i].extra_info.job_id,
- response[i].extra_info.location_id,
- response[i].extra_info.npc_id,
- response[i].extra_info.npc_name,
- response[i].extra_info.planet_id,
- response[i].extra_info.system_id,
- response[i].extra_info.transaction_id
- );
- }
- return entries;
- }
-
- /**
- * Retrieve character wallet transactions.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Retrieve character wallet transactions.
- * @customfunction
- */
- function characterWalletTransactions(opt_headers) {
- var transactions = new Array();
-
- if (opt_headers === undefined) opt_headers = true;
- if (opt_headers) transactions.push(['Transaction ID', 'Client ID', 'Date', 'Type ID', 'Quantity', 'Unit Price', 'Location ID', 'Is Buy?', 'Is Personal?', 'Journal Ref ID']);
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- transactions.push([
- response[i].transaction_id,
- response[i].client_id,
- response[i].date,
- response[i].type_id,
- response[i].quantity,
- response[i].unit_price,
- response[i].location_id,
- response[i].is_buy,
- response[i].is_personal,
- response[i].journal_ref_id
- ]);
- }
- return transactions;
- }
-
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Planets
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns a list of all planetary colonies owned by a character.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of all planetary colonies owned by a character.
- * @customfunction
- */
- function characterPlanets(opt_headers) {
- var planets = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { planets.push(['Planet ID', 'Type', 'System ID', 'Owner ID', 'Upgrade Level', 'Last Updated', '# Pins']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- planets.push([
- response[i].planet_id,
- capitalize_(response[i].planet_type),
- response[i].solar_system_id,
- response[i].owner_id,
- response[i].upgrade_level,
- response[i].last_update,
- response[i].num_pins
- ]);
- }
- return planets;
- }
-
-
- /**
- * Returns full details on the layout of a single planetary colony, including links, pins and routes.
- * @param {number} planet_id ID of the planet to get details on.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns full details on the layout of a single planetary colony, including links, pins and routes.
- * @customfunction
- */
- function characterPlanetDetails(planet_id, opt_headers) {
- var planets = new Array();
-
- if (planet_id === undefined) {throw new Error("No planet ID specified." )};
-
- var response = JSON.parse(getData_(arguments.callee.name, planet_id));
-
- // Inserting header for Links
- planets.push(['Links']);
-
- // Insert data values for links
- planets.push(['', 'Source Pin ID', 'Dest Pin ID', 'Link Level']);
-
- for(var i = 0; i < response.links.length;i++){
- planets.push([
- '',
- response.links[i].source_pin_id,
- response.links[i].destination_pin_id,
- response.links[i].link_level
- ]);
- }
-
- // Inserting header for Pins
- planets.push(['Pins']);
-
- // Insert data values for Pins
- planets.push(['', 'Pin ID', 'Type ID', 'Latitude', 'Longitude', 'Schematic ID', 'Last Cycle Start']);
-
- var schematic = null;
- var last_start_time = null;
-
- for(var i = 0; i < response.pins.length;i++){
- if(!(response.pins[i].hasOwnProperty("schematic_id"))){schematic = "N/A"} else {schematic = response.pins[i].schematic_id}
- if(!(response.pins[i].hasOwnProperty("last_cycle_start"))){last_start_time = "N/A"} else {last_start_time = response.pins[i].last_cycle_start}
-
- planets.push([
- '',
- response.pins[i].pin_id,
- response.pins[i].type_id,
- response.pins[i].latitude,
- response.pins[i].longitude,
- schematic,
- last_start_time
- ]);
- }
-
- // Inserting header for Pins
- planets.push(['Extractors']);
-
- // Insert data values for Pins
- planets.push(['', 'Pin ID','Product Type ID', 'Cycle Time', 'Head Radius', 'Quantity Per Cycle']);
-
- for(var i = 0; i < response.pins.length;i++){
- if( !("extractor_details" in response.pins[i])){ continue;}
- planets.push(['',
- response.pins[i].pin_id,
- response.pins[i].extractor_details.product_type_id,
- response.pins[i].extractor_details.cycle_time,
- response.pins[i].extractor_details.head_radius,
- response.pins[i].extractor_details.qty_per_cycle
- ]);
- }
-
- // Inserting header for Routes
- planets.push(['Routes']);
-
- // Insert data values for Routes
- planets.push(['', 'Route ID', 'Source Pin ID', 'Dest Pin ID', 'Content Type ID', 'Quantity']);
-
- for(var i = 0; i < response.routes.length;i++){
- planets.push(['',
- response.routes[i].route_id,
- response.routes[i].source_pin_id,
- response.routes[i].destination_pin_id,
- response.routes[i].content_type_id,
- response.routes[i].quantity
- ]);
- }
-
-
- return planets;
- }
-
- /**
- * Returns information on a planetary factory schematic.
- * @param {number} schematic_id ID of the schematic to get information on.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns information on a planetary factory schematic.
- * @customfunction
- */
- function planetSchematic(schematic_id, opt_headers) {
- var schematic_data = new Array();
-
- if (schematic_id === undefined) {throw new Error("No schematic ID specified." )};
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { schematic_data.push(['Name', 'Cycle Time']); };
-
- var response = JSON.parse(getData_(arguments.callee.name, schematic_id));
-
- schematic_data.push([response.schematic_name, response.cycle_time]);
-
- return schematic_data;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Character
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * List of blueprints the character has.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of blueprints the character has.
- * @customfunction
- */
- function characterBlueprints(opt_headers) {
- var blueprint_list = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { blueprint_list.push(['Item ID', 'Type ID', 'Runs', 'ME', 'TE', 'Quantity', 'Location ID', 'Location Flag']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- blueprint_list.push([
- response[i].item_id,
- response[i].type_id,
- response[i].runs,
- response[i].material_efficiency,
- response[i].time_efficiency,
- response[i].quantity,
- response[i].location_id,
- response[i].location_flag
- ]);
- }
- return blueprint_list;
- }
-
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Industry
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * List of industry jobs placed by a character.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of industry jobs placed by a character.
- * @customfunction
- */
- function characterIndustryJobs(opt_headers) {
- var job_list = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { job_list.push(['Job ID','Type ID', 'Activity ID', 'Runs', 'Cost', 'Status', 'Duration', 'Licensed Runs', 'Installer ID', 'Facility ID', 'Start Date', 'End Date', 'Blueprint ID', 'Blueprint Location ID', 'Output Location ID', 'Station ID']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- job_list.push([
- response[i].job_id,
- response[i].blueprint_type_id,
- response[i].activity_id,
- response[i].runs,
- response[i].cost,
- response[i].status,
- response[i].duration,
- response[i].licensed_runs,
- response[i].installer_id,
- response[i].facility_id,
- response[i].start_date,
- response[i].end_date,
- response[i].blueprint_id,
- response[i].blueprint_location_id,
- response[i].output_location_id,
- response[i].station_id
- ]);
- }
- return job_list;
- }
-
- /**
- * Return a list of industry facilities.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns a list of industry facilities.
- * @customfunction
- */
- function industryFacilities(opt_headers) {
- var facilities = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { facilities.push(['Facility ID', 'Owner ID', 'Region ID', 'Solar System ID', 'Tax', 'Type ID']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- facilities.push([
- response[i].facility_id ,
- response[i].owner_id ,
- response[i].region_id,
- response[i].solar_system_id,
- response[i].tax,
- response[i].type_id
- ]);
- }
- return facilities;
- }
-
- /**
- * Return cost indices for solar systems.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Return cost indices for solar systems.
- * @customfunction
- */
- function industrySystems(opt_headers) {
- var cost_indices = new Array();
-
- if (opt_headers === undefined) { opt_headers = true; };
- if (opt_headers) { cost_indices.push(['Solar System ID']); };
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- cost_indices.push([ response[i].solar_system_id ]);
-
- cost_indices.push([
- '',
- response[i].cost_indices[0].activity,
- response[i].cost_indices[1].activity,
- response[i].cost_indices[2].activity,
- response[i].cost_indices[3].activity,
- response[i].cost_indices[4].activity
- ]);
-
- cost_indices.push([
- '',
- response[i].cost_indices[0].cost_index,
- response[i].cost_indices[1].cost_index,
- response[i].cost_indices[2].cost_index,
- response[i].cost_indices[3].cost_index,
- response[i].cost_indices[4].cost_index
- ]);
-
- }
- return cost_indices;
- }
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Contracts
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- /**
- * Returns contracts available to a character.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns contracts available to a character, only if the character is issuer, acceptor or assignee. Only returns contracts no older than 30 days, or if the status is "in_progress."
- * @customfunction
- */
- function characterContracts(opt_headers) {
- var contracts = new Array();
-
- if (opt_headers === undefined) opt_headers = true;
- if (opt_headers) contracts.push(['Contract ID','Availability','Issuer ID','Status','Title','Type','Volume','Price','Buyout','Reward','Collateral','Start Location ID','End Location ID','Acceptor ID','Assignee ID','Date Issued','Date Accepted','Date Completed','Date Expired','Days To Complete','For Corporation','Issuer Corporation ID']);
-
- var response = JSON.parse(getData_(arguments.callee.name));
-
- for (var i = 0; i < response.length; i++) {
- contracts.push([
- response[i].contract_id,
- response[i].availability,
- response[i].issuer_id,
- response[i].status,
- response[i].title,
- response[i].type,
- response[i].volume,
- response[i].price,
- response[i].buyout,
- response[i].reward,
- response[i].collateral,
- response[i].start_location_id,
- response[i].end_location_id,
- response[i].acceptor_id,
- response[i].assignee_id,
- response[i].date_issued,
- response[i].date_accepted,
- response[i].date_completed,
- response[i].date_expired,
- response[i].days_to_complete,
- response[i].for_corporation,
- response[i].issuer_corporation_id
- ]);
- }
- return contracts;
-
- }
-
- /**
- * Returns bids on a particular auction contract.
- * @param {integer} contract_id Contract ID to get bids for.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns bids on a particular auction contract.
- * @customfunction
- */
- function characterContractBids(contract_id, opt_headers) {
- var bids = new Array();
-
- if (opt_headers === undefined) opt_headers = true;
- if (opt_headers) bids.push(['Bid ID', 'Date Bid', 'Bidder ID', 'Amount']);
-
- var response = JSON.parse(getData_(arguments.callee.name,contract_id));
-
- for (var i = 0; i < response.length; i++) {
- bids.push([
- response[i].bid_id,
- response[i].date_bid,
- response[i].bidder_id,
- response[i].amount
- ]);
- }
- return bids;
-
- }
-
-
- /**
- * Returns items and details of a particular contract.
- * @param {integer} contract_id Contract ID to get items for.
- * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
- * @return Returns items and details of a particular contract.
- * @customfunction
- */
- function characterContractItems(contract_id, opt_headers) {
- var items = new Array();
-
- if (opt_headers === undefined) opt_headers = true;
- if (opt_headers) items.push(['Record ID', 'Type ID', 'Quantity', 'Is Included?', 'Is Singleton?', 'Raw Quantity']);
-
- var response = JSON.parse(getData_(arguments.callee.name,contract_id));
-
- for (var i = 0; i < response.length; i++) {
- items.push([
- response[i].record_id,
- response[i].type_id,
- response[i].quantity,
- response[i].is_included,
- response[i].is_singleton,
- response[i].raw_quantity
- ]);
- }
- return items;
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+// Google ESI (GESI)
+// Modified version of https://github.com/googlesamples/apps-script-oauth2 to work with EVE SSO/ESI endpoints
+//
+// /u/blacksmoke16 @ Reddit
+// @Blacksmoke16#1684 @ Discord
+app_version = '2.0.0';
+
+// Setup variables used throughout script
+CLIENT_ID = '7c382c66a6c8487d8b64e50daad86f9b';
+CLIENT_SECRET = 'CwcYrVs05AtIbqZkJH8OrBPYps6MAH72qQ1Gf68t';
+BASE_URL = 'https://esi.tech.ccp.is/v'
+
+CHARACTERS = ['Blacksmoke16'];
+
+AUTHING_CHARACTER = CHARACTERS[0];
+
+URL_PARAMS = ['{event_id}', '{alliance_id}', '{schematic_id}', '{corporation_id}', '{division}', '{war_id}', '{planet_id}', '{type_id}', '{contract_id}', '{structure_id}'];
+
+ENDPOINTS = {
+ // Alliances
+
+ "allianceIds": {
+ "version": 1,
+ "url": "/alliances/",
+ "headers": ['alliance_ids']
+ },
+ "allianceNames": {
+ "version": 1,
+ "url": "/alliances/names/",
+ "headers": ['alliance_id', 'alliance_name']
+ },
+ "allianceId": {
+ "version": 2,
+ "url": "/alliances/{alliance_id}/",
+ "headers": ['alliance_name', 'ticker', 'executor_corp', 'date_founded']
+ },
+ "allianceCorporations": {
+ "version": 1,
+ "url": "/alliances/{alliance_id}/corporations/",
+ "headers": ['corporation_ids']
+ },
+ "allianceIcons": {
+ "version": 1,
+ "url": "/alliances/{alliance_id}/icons/",
+ "headers": ['px128x128', 'px64x64']
+ },
+
+ // Assets
+
+ "characterAssets": {
+ "version": 1,
+ "url": "/characters/{character_id}/assets/",
+ "headers": ['item_id', 'type_id', 'quantity', 'location_id', 'location_type', 'location_flag']
+ },
+
+ // Bookmarks
+
+ "characterBookmarks": {
+ "version": 1,
+ "url": "/characters/{character_id}/bookmarks/",
+ "headers": ['bookmark_id', 'target-location_id', 'memo', 'create_date', 'creator_id', 'note', 'owner_id', 'folder_id', 'target-item-item_id', 'target-item-type_id']
+ },
+ "characterBookmarkFolders": {
+ "version": 1,
+ "url": "/characters/{character_id}/bookmarks/folders",
+ "headers": ['folder_id', 'name', 'owner_id']
+ },
+
+ // Calendar
+
+ "calenderEvents": {
+ "version": 1,
+ "url": "/characters/{character_id}/calendar/",
+ "headers": ['event_id', 'title', 'event_date', 'event_response', 'importance']
+ },
+ "calenderEvent": {
+ "version": 3,
+ "url": "/characters/{character_id}/calendar/{event_id}/",
+ "headers": ['event_id', 'date', 'title', 'text', 'duration', 'owner_id', 'owner_name', 'owner_type', 'response', 'importance']
+ },
+
+ // Characters
+
+ "characterBlueprints": {
+ "version": 1,
+ "url": "/characters/{character_id}/blueprints/",
+ "headers": ['item_id', 'type_id', 'location_id', 'location_flag', 'material_efficiency', 'time_efficiency', 'runs', 'quantity']
+ },
+
+ // Contracts
+
+ "characterContracts": {
+ "version": 1,
+ "url": "/characters/{character_id}/contracts/",
+ "headers": ['contract_id', 'issuer_id', 'assignee_id', 'acceptor_id', 'availability', 'type', 'title', 'status', 'issuer_corporation_id', 'for_corporation', 'date_issued', 'date_accepted', 'date_completed', 'date_expired', 'price', 'buyout', 'reward', 'collateral', 'volume', 'days_to_complete', 'start_location_id', 'end_location_id']
+ },
+ "characterContractsBids": {
+ "version": 1,
+ "url": "/characters/{character_id}/contracts/{contract_id}/bids/",
+ "headers": ['bid_id', 'date_bid', 'bidder_id', 'amount']
+ },
+ "characterContractItems": {
+ "version": 1,
+ "url": "/characters/{character_id}/contracts/{contract_id}/items/",
+ "headers": ['record_id', 'type_id', 'quantity', 'raw_quantity', 'is_included', 'is_singleton']
+ },
+
+ // Industry
+
+ "characterIndustryJobs": {
+ "version": 1,
+ "url": "/characters/{character_id}/industry/jobs/",
+ "headers": ['job_id', 'activity_id', 'blueprint_id', 'blueprint_location_id', 'blueprint_type_id', 'completed_character_id', 'completed_date', 'cost', 'duration', 'end_date', 'facility_id', 'installer_id', 'licensed_runs', 'output_location_id', 'pause_date', 'probability', 'product_type_id', 'runs', 'start_date', 'station_id', 'status', 'successful_runs']
+ },
+ "industryFacilities": {
+ "version": 1,
+ "url": "/industry/facilities/",
+ "headers": ['facility_id', 'type_id', 'solar_system_id', 'region_id', 'tax', 'owner_id']
+ },
+ "industrySystems": {
+ "version": 1,
+ "url": "/industry/systems/",
+ "headers": ['solar_system_id', 'manufacturing', 'researching_material_efficiency', 'researching_time_efficiency', 'copying', 'invention']
+ },
+
+ // Loyalty
+
+ "characterLoyalty": {
+ "version": 1,
+ "url": "/characters/{character_id}/loyalty/points/",
+ "headers": ['corporation_id', 'loyalty_points']
+ },
+ "corporationLoyalty": {
+ "version": 1,
+ "url": "/loyalty/stores/{corporation_id}/offers/",
+ "headers": ['offer_id', 'type_id', 'lp_cost', 'isk_cost', 'quantity']
+ },
+
+ // Market
+
+ "characterOrders": {
+ "version": 1,
+ "url": "/characters/{character_id}/orders/",
+ "headers": ['order_id', 'type_id', 'state', 'location_id', 'issued', 'is_buy_order', 'is_corp', 'account_id', 'price', 'escrow', 'range', 'volume_remain', 'volume_total', 'min_volume', 'duration']
+ },
+ "marketPrices": {
+ "version": 1,
+ "url": "/markets/prices/",
+ "headers": ['type_id', 'average_price', 'adjusted_price']
+ },
+ "structureOrders": {
+ "version": 1,
+ "url": "/markets/structures/{structure_id}/",
+ "headers": ['order_id', 'type_id', 'location_id', 'issued', 'is_buy_order', 'price', 'range', 'volume_remain', 'volume_total', 'min_volume', 'duration']
+ },
+
+ // Planets
+
+ "characterPlanets": {
+ "version": 1,
+ "url": "/characters/{character_id}/planets/",
+ "headers": ['planet_id', 'planet_type', 'solar_system_id', 'owner_id', 'upgrade_level', 'last_update', 'num_pins']
+ },
+ "characterPlanetDetails": {
+ "version": 3,
+ "url": "/characters/{character_id}/planets/{planet_id}/"
+ },
+ "planetSchematic": {
+ "version": 1,
+ "url": "/universe/schematics/{schematic_id}/",
+ "headers": ['schematic_name', 'cycle_time']
+ },
+
+ // Skills
+
+ "characterAttributes": {
+ "version": 1,
+ "url": "/characters/{character_id}/attributes/",
+ "headers": ['charisma', 'intelligence', 'perception', 'memory', 'willpower']
+ },
+ "skillQueue": {
+ "version": 2,
+ "url": "/characters/{character_id}/skillqueue/",
+ "headers": ['skill_id', 'queue_position', 'finished_level', 'start_date', 'finish_date']
+ },
+ "characterSkills": {
+ "version": 4,
+ "url": "/characters/{character_id}/skills/",
+ "headers": ['skill_id', 'active_skill_level', 'trained_skill_level', 'skillpoints_in_skill']
+ },
+
+ // Universe
+ "typeId": {
+ "version": 3,
+ "url": "/universe/types/{type_id}/",
+ "headers": ['type_id', 'name', 'group_id', 'description', 'capacity', 'volume', 'packaged_volume', 'portion_size', 'radius', 'mass', 'market_group_id', 'icon_id', 'graphic_id', 'published']
+ },
+
+ // Wallet
+
+ "characterWallet": {
+ "version": 1,
+ "url": "/characters/{character_id}/wallet/",
+ "headers": ['balance']
+ },
+ "characterWalletJournal": {
+ "version": 1,
+ "url": "/characters/{character_id}/wallet/journal",
+ "headers": ['ref_id', 'date', 'amount', 'balance', 'first_party_id', 'first_party_type', 'reason', 'ref_type', 'second_party_id ', 'second_party_type', 'tax', 'tax_reciever_id', 'extra_info-alliance_id', 'extra_info-character_id', 'extra_info-contract_id', 'extra_info-destroyed_ship_type_id', 'extra_info-job_id', 'extra_info-location_id', 'extra_info-npc_id', 'extra_info-npc_name', 'extra_info-planet_id', 'extra_info-system_id', 'extra_info-transaction_id']
+ },
+ "characterWalletTransactions": {
+ "version": 1,
+ "url": "/characters/{character_id}/wallet/transactions/",
+ "headers": ['transaction_id', 'date', 'quantity', 'type_id', 'unit_price', 'location_id', 'journal_ref_id', 'client_id', 'is_buy', 'is_personal']
+ },
+ "corporationWallets": {
+ "version": 1,
+ "url": "/corporations/{corporation_id}/wallets/",
+ "headers": ['division', 'balance']
+ },
+ "corporationWalletJournal": {
+ "version": 1,
+ "url": "/corporations/{corporation_id}/wallets/{division}/journal/",
+ "headers": ['ref_id', 'date', 'amount', 'balance', 'first_party_id', 'first_party_type', 'reason', 'ref_type', 'second_party_id ', 'second_party_type', 'tax', 'tax_reciever_id', 'extra_info-alliance_id', 'extra_info-character_id', 'extra_info-contract_id', 'extra_info-destroyed_ship_type_id', 'extra_info-job_id', 'extra_info-location_id', 'extra_info-npc_id', 'extra_info-npc_name', 'extra_info-planet_id', 'extra_info-system_id', 'extra_info-transaction_id']
+ },
+
+ // Wars
+
+ "wars": {
+ "version": 1,
+ "url": "/wars",
+ "headers": ['war_ids']
+ },
+ "war": {
+ "version": 1,
+ "url": "/wars/{war_id}/",
+ "headers": ['id', 'mutual', 'open_for_allies', 'declared', 'started', 'finished', 'aggressor-corporation_id', 'aggressor-alliance_id', 'aggressor-isk_destroyed', 'aggressor-ships_killed', 'defender-corporation_id', 'defender-alliance_id', 'defender-isk_destroyed', 'defender-ships_killed', 'ally-alliance_id', 'ally-corporation_id']
+ },
+ "warKillmails": {
+ "version": 1,
+ "url": "/wars/{war_id}/killmails",
+ "headers": ['killmail_id', 'killmail_hash']
+ }
+};
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Alliances
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Returns a list of Alliance IDs
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Returns a list of Alliance IDs.
+ * @customfunction
+ */
+function allianceIds(opt_headers) {
+ return getArrayResponse_(arguments.callee.name, '', opt_headers);
+}
+
+/**
+ * Resolve a set of alliance IDs to alliance names
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Returns a list of id/name associations.
+ * @customfunction
+ */
+function allianceNames(alliance_ids, opt_headers) {
+ if (!alliance_ids) throw 'A range of alliance ids is required';
+ return getArrayObjectResponse_(arguments.callee.name, '', opt_headers, {alliance_ids: alliance_ids});
+}
+
+/**
+ * Public information about an alliance
+ * @param {number} alliance_id ID of the alliance to get information on
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Public data about an alliance
+ * @customfunction
+ */
+function allianceId(alliance_id, opt_headers) {
+ if (!alliance_id) throw 'alliance_id is required';
+ return getObjectResponse_(arguments.callee.name, '', opt_headers, {alliance_id: alliance_id});
+}
+
+/**
+ * List all current member corporations of an alliance
+ * @param {number} alliance_id ID of the alliance to get corporations for
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return List of corporation IDs
+ * @customfunction
+ */
+function allianceCorporations(alliance_id, opt_headers) {
+ if (!alliance_id) throw 'alliance_id is required';
+ return getArrayResponse_(arguments.callee.name, '', opt_headers, {alliance_id: alliance_id});
+}
+
+/**
+ * Get the icon urls for a alliance
+ * @param {number} alliance_id ID of the alliance to get icons for
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Urls for icons for the given alliance id and server
+ * @customfunction
+ */
+function allianceIcons(alliance_id, opt_headers) {
+ if (!alliance_id) throw 'alliance_id is required';
+ return getObjectResponse_(arguments.callee.name, '', opt_headers, {alliance_id: alliance_id});
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Assets
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Returns a list of the character's assets.
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Returns a list of the characters assets.
+ * @customfunction
+ */
+function characterAssets(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Bookmarks
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * List your character's personal bookmarks
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of bookmarks
+ * @customfunction
+ */
+function characterBookmarks(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true, true);
+}
+
+/**
+ * List your character's personal bookmark folders
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return List of bookmark folders
+ * @customfunction
+ */
+function characterBookmarkFolders(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Calendar
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Get 50 event summaries from the calendar.
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A collection of event summaries
+ * @customfunction
+ */
+function calenderEvents(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Get all the information for a specific event
+ * @param {number} event_id ID of the event to get information for
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Full details of a specific event
+ * @customfunction
+ */
+function calenderEvent(event_id, name, opt_headers) {
+ if (!event_id) throw 'An event id is required';
+ return getObjectResponse_(arguments.callee.name, name, opt_headers, {event_id: event_id}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Character
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Return a list of blueprints the character has
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of blueprints
+ * @customfunction
+ */
+function characterBlueprints(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Contracts
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Returns contracts available to a character, only if the character is issuer, acceptor or assignee.
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of contracts
+ * @customfunction
+ */
+function characterContracts(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Return cost indices for solar systems
+ * @param {number} contract_id of the contract to get bids for
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of bids
+ * @customfunction
+ */
+function characterContractBids(contract_id, name, opt_headers) {
+ if (!contract_id) throw 'contract_id is required';
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {contract_id: contract_id}, true);
+}
+
+/**
+ * Lists Items and details of a particular contract
+ * @param {number} contract_id of the contract to get items for
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of items
+ * @customfunction
+ */
+function characterContractItems(contract_id, name, opt_headers) {
+ if (!contract_id) throw 'contract_id is required';
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {contract_id: contract_id}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Industry
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * List industry jobs placed by a character
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Industry jobs placed by a character
+ * @customfunction
+ */
+function characterIndustryJobs(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Return a list of industry facilities
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of facilities
+ * @customfunction
+ */
+function industryFacilities(opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, '', opt_headers, {});
+}
+
+/**
+ * Return cost indices for solar systems
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of cost indicies
+ * @customfunction
+ */
+function industrySystems(opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, '', opt_headers, {}, false, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Loyalty
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Return a list of loyalty points for all corporations the character has worked for
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of loyalty points
+ * @customfunction
+ */
+function characterLoyalty(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Return a list of offers from a specific corporation's loyalty store
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of offers
+ * @customfunction
+ */
+function corporationLoyalty(corporation_id, opt_headers) {
+ if (!corporation_id) throw 'corporation_id is required';
+ return getArrayObjectResponse_(arguments.callee.name, '', opt_headers, {corporation_id: corporation_id}, false);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Market
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * List market orders placed by a character
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Market orders placed by a character
+ * @customfunction
+ */
+function characterOrders(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Return a list of prices
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of prices
+ * @customfunction
+ */
+function marketPrices(opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, '', opt_headers, {});
+}
+
+/**
+ * Return a list of prices
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of prices
+ * @customfunction
+ */
+function structureOrders(structure_id, name, opt_headers) {
+ if (!structure_id) throw 'structure_id is required';
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {structure_id: structure_id}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Planets
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Returns a list of all planetary colonies owned by a character.
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Returns a list of all planetary colonies owned by a character.
+ * @customfunction
+ */
+function characterPlanets(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Returns full details on the layout of a single planetary colony, including links, pins and routes.
+ * @param {number} planet_id of the planet to get details on
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Colony layout
+ * @customfunction
+ */
+function characterPlanetDetails(planet_id, name, opt_headers) {
+ if (!planet_id) throw 'planet_id is required';
+ return characterPlanetDetails_({planet_id: planet_id}, name, opt_headers, true);
+}
+
+/**
+ * Returns information on a planetary factory schematic.
+ * @param {number} schematic_id ID of the schematic to get information on.
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Returns information on a planetary factory schematic.
+ * @customfunction
+ */
+function planetSchematic(schematic_id, name, opt_headers) {
+ if (!schematic_id) throw 'schematic_id is required';
+ return getObjectResponse_(arguments.callee.name, name, opt_headers, {schematic_id: schematic_id})
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Skills
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Return attributes of a character
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Attributes of a character
+ * @customfunction
+ */
+function characterAttributes(name, opt_headers) {
+ return getObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * List the configured skill queue for the given character
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return The current skill queue, sorted ascending by finishing time
+ * @customfunction
+ */
+function skillQueue(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * List all trained skills for the given character
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Known skills for the character
+ * @customfunction
+ */
+function characterSkills(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Universe
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Get information on a type
+ * @param {string} type_id type_id of item to get information on
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Information about a type
+ * @customfunction
+ */
+function typeId(type_id, opt_headers) {
+ if (!type_id) throw 'type_id is required';
+ return getObjectResponse_(arguments.callee.name, '', opt_headers, {type_id: type_id});
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Wallet
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Returns a character's wallet balance
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return balance
+ * @customfunction
+ */
+function characterWallet(name, opt_headers) {
+ return getSingleResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Retrieve character wallet journal
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Journal entries
+ * @customfunction
+ */
+function characterWalletJournal(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Get wallet transactions of a character
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Wallet transactions
+ * @customfunction
+ */
+function characterWalletTransactions(name, opt_headers) {
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {}, true);
+}
+
+/**
+ * Get a corporation's wallets
+ * @param {number} corporation_id ID of the corporation to get wallets for
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return List of corporation wallets
+ * @customfunction
+ */
+function corporationWallets(corporation_id, name, opt_headers) {
+ if (!corporation_id) throw 'corporation_id is required';
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {corporation_id: corporation_id}, true);
+}
+
+/**
+ * Retrieve corporation wallet journal
+ * @param {number} corporation_id ID of the corporation to get wallet journal for
+ * @param {number} division ID of the division to get wallet journal from
+ * @param {string} name Name of the character used for auth. If none is given, defaults to AUTHING_CHARACTER.
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Journal entries
+ * @customfunction
+ */
+function corporationWalletJournal(corporation_id, division, name, opt_headers) {
+ if (!corporation_id) throw 'corporation_id is required';
+ if (!division) throw 'division is required';
+ corporation_id = 98019139;
+ division = 1;
+ return getArrayObjectResponse_(arguments.callee.name, name, opt_headers, {
+ corporation_id: corporation_id,
+ division: division
+ }, true, true);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Wars
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Return a list of wars
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of war IDs, in decending order by war_id.
+ * @customfunction
+ */
+function wars(opt_headers) {
+ return getArrayResponse_(arguments.callee.name, '', opt_headers);
+}
+
+/**
+ * Return details about a war
+ * @param {number} war_id ID of the war to get information on
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return Details about a war
+ * @customfunction
+ */
+function war(war_id, opt_headers) { // 291410 RVB War ID
+ if (!war_id) throw 'war_id is required';
+ return getObjectResponse_(arguments.callee.name, '', opt_headers, {war_id: war_id}, false, true);
+}
+
+/**
+ * Return a list of kills related to a war
+ * @param {number} war_id ID of the war to get killmails for
+ * @param {boolean} opt_headers Default: True, Boolean if column headings should be listed or not.
+ * @return A list of killmail IDs and hashes
+ * @customfunction
+ */
+function warKillmails(war_id, opt_headers) {
+ if (!war_id) throw 'war_id is required';
+ return getArrayObjectResponse_(arguments.callee.name, '', opt_headers, {war_id: war_id});
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Private Functions
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+function getData_(endpoint_name, name, params) {
+ var userProperties = PropertiesService.getUserProperties();
+ var eveService = createOAuthForUser(name);
+ var url = ENDPOINTS[endpoint_name].url
+
+ if (url.indexOf('{character_id}') !== -1) {
+ url = url.replace('{character_id}', parseInt(userProperties.getProperty(name)));
+ }
+ for (var p = 0; p < URL_PARAMS.length; p++) {
+ if (url.indexOf(URL_PARAMS[p]) !== -1) {
+ url = url.replace(URL_PARAMS[p], params[URL_PARAMS[p].replace('{', '').replace('}', '')]);
+ }
+ }
+ var response = UrlFetchApp.fetch(BASE_URL + ENDPOINTS[endpoint_name].version + url, {
+ headers: {
+ Authorization: 'Bearer ' + eveService.getAccessToken()
+ }
+ });
+ if (!response) throw 'Error getting ESI data';
+ return JSON.parse(response);
+}
+function getUnauthedData_(endpoint_name, name, params) {
+ var url = BASE_URL + ENDPOINTS[endpoint_name].version + ENDPOINTS[endpoint_name].url;
+ if (endpoint_name === 'allianceNames') url = url + '?alliance_ids=' + params.join();
+ for (var p = 0; p < URL_PARAMS.length; p++) {
+ if (url.indexOf(URL_PARAMS[p]) !== -1) {
+ url = url.replace(URL_PARAMS[p], params[URL_PARAMS[p].replace('{', '').replace('}', '')]);
+ }
+ }
+ var response = UrlFetchApp.fetch(url);
+ if (!response) throw 'Error getting public ESI data';
+ return JSON.parse(response);
+}
+function getArrayObjectResponse_(endpoint_name, name, opt_headers, params, authed, isNested) {
+ if (!name) name = AUTHING_CHARACTER;
+ if (authed) {
+ var data = getData_(endpoint_name, name, params);
+ } else {
+ var data = getUnauthedData_(endpoint_name, name, params);
+ }
+ if (endpoint_name === 'industrySystems') data = deArrayIndex_(data);
+ var result = [];
+ if (opt_headers === undefined) opt_headers = true;
+ if (opt_headers) result.push(convertSnakeCase_(ENDPOINTS[endpoint_name].headers));
+
+ for (var i = 0; i < data.length; i++) {
+ var temp = [];
+ if (isNested) data[i] = flatten_(data[i]);
+ for (var k = 0; k < ENDPOINTS[endpoint_name].headers.length; k++) {
+ data_value = data[i][ENDPOINTS[endpoint_name].headers[k]];
+ temp.push(data_value);
+ }
+ result.push(temp);
+ }
+ Logger.log(result);
+ return result;
+};
+function getObjectResponse_(endpoint_name, name, opt_headers, params, authed, isNested) {
+ if (!name) name = AUTHING_CHARACTER;
+ if (authed) {
+ var data = getData_(endpoint_name, name, params);
+ } else {
+ var data = getUnauthedData_(endpoint_name, name, params);
+ }
+ var result = [];
+ if (opt_headers === undefined) opt_headers = true;
+ if (opt_headers) result.push(convertSnakeCase_(ENDPOINTS[endpoint_name].headers));
+ if (isNested) data = flatten_(data);
+
+ var temp = [];
+ for (var k = 0; k < ENDPOINTS[endpoint_name].headers.length; k++) {
+ temp.push(data[ENDPOINTS[endpoint_name].headers[k]]);
+ }
+ result.push(temp);
+ return result;
+};
+// Private function for basic array of value responses
+function getArrayResponse_(endpoint_name, name, opt_headers, params, authed) {
+ if (!name) name = AUTHING_CHARACTER;
+ if (authed) {
+ var data = getData_(endpoint_name, name, params);
+ } else {
+ var data = getUnauthedData_(endpoint_name, name, params);
+ }
+ var result = [];
+ if (opt_headers === undefined) opt_headers = true;
+ if (opt_headers) result.push(convertSnakeCase_(ENDPOINTS[endpoint_name].headers));
+ for (var i = 0; i < data.length; i++) {
+ result.push(data[i]);
+ }
+ ;
+
+ return result;
+};
+
+// Private function for basic array of value responses
+function getSingleResponse_(endpoint_name, name, opt_headers, params, authed) {
+ if (!name) name = AUTHING_CHARACTER;
+ if (authed) {
+ var data = getData_(endpoint_name, name, params);
+ } else {
+ var data = getUnauthedData_(endpoint_name, name, params);
+ }
+ var result = [];
+ if (opt_headers === undefined) opt_headers = true;
+ if (opt_headers) result.push(convertSnakeCase_(ENDPOINTS[endpoint_name].headers));
+ result.push(data);
+ return result;
+};
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // OAth2 Functions
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+function flatten_(ob) {
+ var toReturn = {};
+ for (var i in ob) {
+ if (!ob.hasOwnProperty(i)) continue;
- function getEVEService() {
- // Create a new service with the given name. The name will be used when
- // persisting the authorized token, so ensure it is unique within the
- // scope of the property store.
- return OAuth2.createService('EVE')
+ if ((typeof ob[i]) == 'object') {
+ var flatObject = flatten_(ob[i]);
+ for (var x in flatObject) {
+ if (!flatObject.hasOwnProperty(x)) continue;
- // Set the endpoint URLs, which are the same for all Google services.
- .setAuthorizationBaseUrl('https://login.eveonline.com/oauth/authorize/')
- .setTokenUrl('https://login.eveonline.com/oauth/token')
+ toReturn[i + '-' + x] = flatObject[x];
+ }
+ } else {
+ toReturn[i] = ob[i];
+ }
+ }
+ return toReturn;
+};
+
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// OAth2 Functions
+// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+function onOpen() {
+ SpreadsheetApp.getUi().createMenu('GESI')
+ .addItem('Authorize Sheet', 'showSidebar')
+ .addSeparator()
+ .addItem('Reset Auth', 'clearService')
+ .addToUi();
+
+}
+
+function showSidebar() {
+ var eveService = createOAuthForUser(AUTHING_CHARACTER);
+ if (!eveService.hasAccess()) {
+ var authorizationUrl = eveService.getAuthorizationUrl();
+ var template = HtmlService.createTemplate(
+ '
Authorize: = character ?>.');
+ template.authorizationUrl = authorizationUrl;
+ template.character = AUTHING_CHARACTER;
+ var page = template.evaluate();
+ SpreadsheetApp.getUi().showSidebar(page);
+ }
+}
+
+function authCallback(request) {
+ var eveService = createOAuthForUser(AUTHING_CHARACTER);
+ var isAuthorized = eveService.handleCallback(request);
+ if (isAuthorized) {
+ getCharacterDetails_();
+ return HtmlService.createHtmlOutput('Success! You can close this tab.');
+ } else {
+ return HtmlService.createHtmlOutput('Denied. You can close this tab');
+ }
+}
+
+function createOAuthForUser(user) {
+ return OAuth2.createService(user)
+ .setAuthorizationBaseUrl('https://login.eveonline.com/oauth/authorize/')
+ .setTokenUrl('https://login.eveonline.com/oauth/token')
+ .setClientId(CLIENT_ID)
+ .setClientSecret(CLIENT_SECRET)
+ .setCallbackFunction('authCallback')
+ .setPropertyStore(PropertiesService.getUserProperties())
+ .setScope('esi-universe.read_structures.v1 esi-wallet.read_corporation_wallets.v1 esi-calendar.read_calendar_events.v1 esi-bookmarks.read_character_bookmarks.v1 esi-contracts.read_character_contracts.v1 esi-industry.read_character_jobs.v1 esi-characters.read_blueprints.v1 esi-markets.read_character_orders.v1 esi-planets.manage_planets.v1 esi-ui.open_window.v1 esi-skills.read_skills.v1 esi-skills.read_skillqueue.v1 esi-markets.structure_markets.v1 esi-characters.read_contacts.v1 esi-assets.read_assets.v1 esi-characters.read_loyalty.v1 esi-wallet.read_character_wallet.v1 esi-ui.write_waypoint.v1')
+ .setParam('access_type', 'offline')
+ .setTokenHeaders({
+ 'Authorization': 'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET)
+ })
+}
+
+function clearService() {
+ for (var i = 0; i < CHARACTERS.length; i++) {
+ Logger.log(CHARACTERS[i]);
+ OAuth2.createService(CHARACTERS[i])
+ .setPropertyStore(PropertiesService.getUserProperties())
+ .reset();
+ }
+}
+
+function getCharacterDetails_() {
+ var userProperties = PropertiesService.getUserProperties();
+ var eveService = createOAuthForUser(AUTHING_CHARACTER);
+ var response = UrlFetchApp.fetch('https://login.eveonline.com/oauth/verify', {
+ headers: {
+ Authorization: 'Bearer ' + eveService.getAccessToken()
+ }
+ });
+ response = JSON.parse(response);
+ userProperties.setProperty(AUTHING_CHARACTER, response.CharacterID.toString());
+}
+
+function convertSnakeCase_(headers) {
+ var formatted_headers = [];
+ for (var h = 0; h < headers.length; h++) {
+ str = headers[h].replace(/\_/g, ' ');
+ formatted_headers.push(str.replace(/\w\S*/g, function (txt) {
+ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
+ }));
+ }
+ return formatted_headers;
+}
- // Set the client ID and secret, from the EVE Dev site.
- .setClientId(CLIENT_ID)
- .setClientSecret(CLIENT_SECRET)
+function deArrayIndex_(data) {
+ for (var o = 0; o < data.length; o++) {
+ for (var a in data[o].cost_indices) {
+ data[o][data[o].cost_indices[a].activity] = data[o].cost_indices[a].cost_index;
+ }
+ delete data[o].cost_indices;
+ }
+ return data;
+}
- // Set the name of the callback function in the script referenced
- // above that should be invoked to complete the OAuth flow.
- .setCallbackFunction('authCallback')
+function characterPlanetDetails_(params, name, opt_headers) {
+ var planets = new Array();
+ if (!name) name = AUTHING_CHARACTER;
- // Set the property store where authorized tokens should be persisted.
- .setPropertyStore(PropertiesService.getUserProperties())
+ var response = getData_('characterPlanetDetails', name, params);
- // Set the scopes to request (space-separated).
- .setScope('esi-contracts.read_character_contracts.v1 esi-industry.read_character_jobs.v1 esi-characters.read_blueprints.v1 esi-markets.read_character_orders.v1 esi-planets.manage_planets.v1 esi-ui.open_window.v1 esi-skills.read_skills.v1 esi-skills.read_skillqueue.v1 esi-markets.structure_markets.v1 esi-characters.read_contacts.v1 esi-assets.read_assets.v1 esi-characters.read_loyalty.v1 esi-wallet.read_character_wallet.v1 esi-ui.write_waypoint.v1')
+ // Inserting header for Links
+ planets.push(['Links']);
- // Requests offline access. Allows token to be refreshed when it expires
- .setParam('access_type', 'offline')
+ // Insert data values for links
+ planets.push(['', 'Source Pin ID', 'Dest Pin ID', 'Link Level']);
- .setTokenHeaders({
- 'Authorization': 'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET)
- })
- }
+ for (var i = 0; i < response.links.length; i++) {
+ planets.push([
+ '',
+ response.links[i].source_pin_id,
+ response.links[i].destination_pin_id,
+ response.links[i].link_level
+ ]);
+ }
- function showSidebar() {
- var eveService = getEVEService();
- if (!eveService.hasAccess()) {
- var authorizationUrl = eveService.getAuthorizationUrl();
- var template = HtmlService.createTemplate(
- 'Authorize.');
- template.authorizationUrl = authorizationUrl;
- var page = template.evaluate();
- SpreadsheetApp.getUi().showSidebar(page);
- }
- }
+ // Inserting header for Pins
+ planets.push(['Pins']);
+
+ // Insert data values for Pins
+ planets.push(['', 'Pin ID', 'Type ID', 'Schematic ID', 'Type Id', 'Install Time', 'Last Cycle Start', 'Latitude', 'Longitude']);
+
+ for (var i = 0; i < response.pins.length; i++) {
+ planets.push([
+ '',
+ response.pins[i].pin_id,
+ response.pins[i].type_id,
+ response.pins[i].schematic_id,
+ response.pins[i].type_id,
+ response.pins[i].install_time,
+ response.pins[i].last_cycle_start,
+ response.pins[i].latitude,
+ response.pins[i].longitude
+ ]);
+ }
- function authCallback(request) {
- var eveService = getEVEService();
- var isAuthorized = eveService.handleCallback(request);
- if (isAuthorized) {
- getCharacterDetails_();
- return HtmlService.createHtmlOutput('Success! You can close this tab.');
- } else {
- return HtmlService.createHtmlOutput('Denied. You can close this tab');
- }
- }
+ // Inserting header for Extractors
+ planets.push(['Extractors']);
- function clearService() {
- OAuth2.createService('EVE')
- .setPropertyStore(PropertiesService.getUserProperties())
- .reset();
- }
+ // Insert data values for Extractors
+ planets.push(['', 'Pin ID', 'Product Type ID', 'Cycle Time', 'Head Radius', 'Quantity Per Cycle']);
- /**
- * Returns the active access token.
- * @return the active access token.
- * @customfunction
- */
- function getAccessToken() {
- return getEVEService().getAccessToken();
- }
+ for (var i = 0; i < response.pins.length; i++) {
+ if (!("extractor_details" in response.pins[i])) {
+ continue;
+ }
+ planets.push(['',
+ response.pins[i].pin_id,
+ response.pins[i].extractor_details.product_type_id,
+ response.pins[i].extractor_details.cycle_time,
+ response.pins[i].extractor_details.head_radius,
+ response.pins[i].extractor_details.qty_per_cycle
+ ]);
+ }
- /**
- * Returns details on current endpoints.
- * @Returns details on current endpoints.
- * @customfunction
- */
- function help() {
- endpoint_list = [];
+ // Inserting header for Routes
+ planets.push(['Routes']);
- for(var key in endpoints){
- endpoint_list.push([
- endpoints[key].name,
- endpoints[key].description
- ]);
+ // Insert data values for Routes
+ planets.push(['', 'Route ID', 'Source Pin ID', 'Dest Pin ID', 'Content Type ID', 'Quantity']);
- for( var i = 0; i < endpoints[key].parameters.length; i++){
- endpoint_list.push([
- '',
- endpoints[key].parameters[i].name,
- endpoints[key].parameters[i].description
+ for (var i = 0; i < response.routes.length; i++) {
+ planets.push(['',
+ response.routes[i].route_id,
+ response.routes[i].source_pin_id,
+ response.routes[i].destination_pin_id,
+ response.routes[i].content_type_id,
+ response.routes[i].quantity
]);
- }
-
- endpoint_list.push(['']);
-
}
- return endpoint_list;
-
- }
-
-
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- // Private Functions
- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
- function getData_(endpoint_name, param){
- var userProperties = PropertiesService.getUserProperties();
- var eveService = getEVEService();
- var url = endpoints[endpoint_name].url
-
- if(url.indexOf('{character_id') !== -1){ url = url.replace('{character_id}', userProperties.getProperty('character_id')); }
- if(param != undefined) { url = url.replace(url.match(/{.+}/g)[0], param); }
-
- var response = UrlFetchApp.fetch(BASE_URL + endpoints[endpoint_name].version + url, {
- headers: {
- Authorization: 'Bearer ' + eveService.getAccessToken()
- }
- });
- return response;
- }
-
- function getCharacterDetails_() {
- var userProperties = PropertiesService.getUserProperties();
- var eveService = getEVEService();
- var response = UrlFetchApp.fetch('https://login.eveonline.com/oauth/verify', {
- headers: {
- Authorization: 'Bearer ' + eveService.getAccessToken()
- }
- });
- response = JSON.parse(response);
- var newProperties = {
- character_id: response.CharacterID,
- characterName: response.CharacterName,
- expires: response.ExpiresOn
- };
- userProperties.setProperties(newProperties);
- }
-
- function id2name_(ids) {
- var unique_ids = ids.filter(function(item, pos) {
- return ids.indexOf(item) == pos;
- });
-
- var options = {
- 'method': 'post',
- 'contentType': 'application/json',
- 'payload': JSON.stringify(unique_ids)
- }
- var response = UrlFetchApp.fetch('https://esi.tech.ccp.is/v2/universe/names/', options);
- return JSON.parse(response);
- }
-
- function capitalize_(string) {
- return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
-}
\ No newline at end of file
+
+ return planets;
+}
diff --git a/README.md b/README.md
index 84cb397..78056d7 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Modified version of Google's https://github.com/googlesamples/apps-script-oauth2
To request new endpoints/changes/etc create issues or mail me in game (Blacksmoke16).
-### Setup:
+### Setup for single character use:
1. Create a new google sheet or go to the one you want to use the script on.
2. In the menu bar go to Tools -> Script Editor.
3. Click on the menu item "Resources > Libraries..."
@@ -18,84 +18,49 @@ To request new endpoints/changes/etc create issues or mail me in game (Blacksmok
* Content Type: Authentication & API Access
* PERMISSIONS: Select all ESI endpoints so you wont' have to edit the app each time a new endpoint is added for GESI.
* CALLBACK URL: https://script.google.com/macros/d/{SCRIPT_ID_COPIED_IN_STEP_FIVE}/usercallback
+ * Be sure to replace the `{SCRIPT_ID_COPIED_IN_STEP_FIVE}` in the URL with YOUR script ID!
7. Replace the example CLIENT_ID and CLIENT_SECRET variables towards the top with your info from the dev app, and save.
8. Close the script and refresh the spreadsheet.
9. There will now be a GESI option in the menu bar. Click it and then click 'Authorize Sheet'.
10. Give the script permission to do what it needs.
- 11. Click 'Authorize' in the sidenav that opens -> login -> select what character you want to authorize -> Authorize.
+ 11. Click 'Authorize Sheet' in the sidenav that opens -> login -> select what character you want to authorize -> Authorize.
12. Close the sidenav.
13. Done.
-
-### Functions:
-
-##### Note: All functions, unless otherwise stated, have an optional opt_headers parameter that defaults to true and determines if column headers are shown or not.
-
-##### Global:
- * =help() - Returns information on current endpoints.
-
-##### Skills:
- * =skillQueue(opt_headers) - Returns the user's current skill queue.
- * =skills(option, opt_headers) - Returns a list of Skill names, current points in skill and current level or total skill points.
- * 'List': Returns a list of Skill names, current points in skill and current level
- * 'Total': Returns total SP.
-##### Market:
- * =marketPrices(opt_headers) - Returns the average and adjusted prices for various itemIDs.
- * =characterMarketOrders(opt_headers) - Returns a list of market orders placed by a character.
- * =structureMarketOrders(structure_id, opt_headers) - Returns all market orders in a given structure.
- * structure_id: ID of the structure you want to get market orders from.
-##### Universe:
- * =itemTypes(ids, opt_headers) - Returns Information about a type.
- * ids: Either a single typeID, or a list of typeIDs.
-
-##### Assets:
- * =characterAssets(opt_headers) - Returns a list of the characters assets.
-
-##### Loyalty:
- * =characterLoyalty(opt_headers) - Returns a list of loyalty points for all corporations the character has worked for.
- * =corporationLoyalty(corporation_id, opt_headers) - Returns a list of offers from a specific corporation's loyalty store.
- * corporation_id: Corporation ID to get the loyalty point store for.
-
-##### Wallet:
- * =characterWallet(opt_headers) - Returns the balance of your wallet.
- * =characterWalletJournal(opt_headers) - Returns a character's wallet journal.
- * =characterWalletTransactions(opt_headers) - Returns a character's wallet transactions.
+### Setup for multiple character use:
+ 1. Complete steps 1-8 in single character use.
+ 2. In the script there is a constant variable called `CHARACTERS` (line 13) which is an array of strings.
+ * Replace the contents of the array with the names of the characters you wish to authorize.
+ * E.x. `CHARACTERS = ['Blacksmoke16', 'Blacksmoke17', 'Blacksmoke18'];`
+ 4. To auth the characters:
+ * In the script there is another constant variable `AUTHING_CHARACTER` (line 15).
+ * Complete steps 9-13 in single character use.
+ * Add one (1) to the number in brackets.
+ * E.x. `AUTHING_CHARACTER = CHARACTERS[1];`
+ 5. Repeat step 4 until all characters are authorized.
+ * `AUTHING_CHARACTER = CHARACTERS[1];` -> authorize `Blacksmoke17` using steps 9-13 in single character use.
+ * `AUTHING_CHARACTER = CHARACTERS[2];` -> authorize `Blacksmoke18` using steps 9-13 in single character use.
-##### Planets:
- * =characterPlanets(opt_headers) - Returns a list of all planetary colonies owned by a character.
- * =characterPlanetDetails(planet_id) - Returns full details on the layout of a single planetary colony, including links, pins and routes.
- * planet_id: ID of the planet to get details on.
- * =planetSchematic(schematic_id, opt_headers) - Returns information on a planetary factory schematic.
- * schematic_id: ID of the schematic to get information on.
-
-##### Character:
- * =characterBlueprints(opt_headers) - Returns a list of blueprints the character has.
-
-##### Industry:
- * =characterIndustryJobs(opt_headers) - Returns a list of industry jobs placed by a character.
- * =industryFacilities(opt_headers) - Returns a list of industry facilities.
- * =industrySystems(opt_headers) - Returns cost indices for solar systems.
-
-##### Contracts:
- * =characterContracts(opt_headers) - Returns a list of a character's contracts.
- * =characterContractBids(contract_id, opt_headers) - Returns bids on a particular auction contract.
- * contract_id: ID of the contract to get bids for.
- * =characterContractItems(contract_id, opt_headers) -Returns Items and details of a particular contract.
- * contract_id: ID of the contract to get information on.
-
- ##### GESI Dropdown:
- * Authorize Sheet - Provides the link to navigate to to login and get your access token
- * Reset Auth - Clears the OAuth2 service, making all tokens invalid.
-
-### Note: In order to use new functions, you will have to re-auth your character.
- * Use 'Reset Auth' under GESI dropdown window to clear the old token/auth data.
- * Use 'Authorize Sheet' under GESI dropdown window to re-auth your character with the newly added scopes.
+### Features for advanced users
+
+##### To change order of column headers
+ 1. Find the corresponding object in the ENDPOINTS array.
+ * E.x.
+ ```
+ "allianceNames": {
+ "version": 1,
+ "url": "/alliances/names/",
+ "headers": ['alliance_id', 'alliance_name']
+ }
+ ```
+ 2. Re order the values in the `headers` array to the order you want.
+ * The value furthest to the left is first
+
+### Note: In order to use functions that use new scopes, you will have to re-auth your character(s).
### Contact Info
In-game: Blacksmoke16
Discord: Blacksmoke16#1684
-
-Donations are accepted :)
### Copyright
EVE Online and the EVE logo are the registered trademarks of CCP hf. All rights are reserved worldwide. All other