From c8a0580ac558dfc2464038e16d2e4a4804ab8cf5 Mon Sep 17 00:00:00 2001 From: versx Date: Mon, 10 May 2021 07:34:31 -0700 Subject: [PATCH 01/12] Allow custom locations per sub --- src/data/map.js | 17 + src/index.js | 2 - src/models/gym.js | 6 +- src/models/invasion.js | 4 + src/models/location.js | 126 +++++++ src/models/lure.js | 4 + src/models/pokemon.js | 4 + src/models/pvp.js | 4 + src/models/quest.js | 4 + src/models/raid.js | 4 + src/models/subscription.js | 19 +- src/routes/api.js | 337 +++++++++++++----- src/routes/ui.js | 171 ++++++--- .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../{gym-edit.mustache => gyms/edit.mustache} | 10 +- .../{gym-new.mustache => gyms/new.mustache} | 14 +- src/views/header.mustache | 2 + src/views/index.mustache | 10 + .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../edit.mustache} | 10 +- src/views/{ => invasions}/invasions.mustache | 16 +- .../new.mustache} | 14 +- src/views/locations/delete-all.mustache | 27 ++ src/views/locations/delete.mustache | 27 ++ src/views/locations/edit.mustache | 37 ++ src/views/locations/locations.mustache | 98 +++++ src/views/locations/new.mustache | 42 +++ .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../edit.mustache} | 10 +- src/views/{ => lures}/lures.mustache | 16 +- .../{lure-new.mustache => lures/new.mustache} | 14 +- src/views/navbar.mustache | 5 + .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../edit.mustache} | 12 +- .../new.mustache} | 14 +- src/views/{ => pokemon}/pokemon.mustache | 32 +- .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../{pvp-edit.mustache => pvp/edit.mustache} | 10 +- .../{pvp-new.mustache => pvp/new.mustache} | 14 +- .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../edit.mustache} | 10 +- .../new.mustache} | 14 +- src/views/{ => quests}/quests.mustache | 16 +- .../delete-all.mustache} | 0 .../delete.mustache} | 0 .../edit.mustache} | 10 +- .../{raid-new.mustache => raids/new.mustache} | 13 +- src/views/{ => raids}/raids.mustache | 32 +- .../{role-add.mustache => roles/add.mustache} | 1 - .../remove-all.mustache} | 0 .../remove.mustache} | 6 +- src/views/{ => roles}/roles.mustache | 16 +- src/views/settings.mustache | 21 +- static/img/map-pin.png | Bin 0 -> 19517 bytes static/js/city-map.js | 1 + static/js/fetch-locations.js | 8 + static/js/location-selector.js | 82 +++++ static/js/locator.js | 7 + static/locales/_de.json | 11 +- static/locales/_en.json | 11 +- static/locales/_es.json | 11 +- 67 files changed, 1148 insertions(+), 258 deletions(-) create mode 100644 src/models/location.js rename src/views/{gyms-delete-all.mustache => gyms/delete-all.mustache} (100%) rename src/views/{gym-delete.mustache => gyms/delete.mustache} (100%) rename src/views/{gym-edit.mustache => gyms/edit.mustache} (88%) rename src/views/{gym-new.mustache => gyms/new.mustache} (84%) rename src/views/{invasions-delete-all.mustache => invasions/delete-all.mustache} (100%) rename src/views/{invasion-delete.mustache => invasions/delete.mustache} (100%) rename src/views/{invasion-edit.mustache => invasions/edit.mustache} (84%) rename src/views/{ => invasions}/invasions.mustache (86%) rename src/views/{invasion-new.mustache => invasions/new.mustache} (86%) create mode 100644 src/views/locations/delete-all.mustache create mode 100644 src/views/locations/delete.mustache create mode 100644 src/views/locations/edit.mustache create mode 100644 src/views/locations/locations.mustache create mode 100644 src/views/locations/new.mustache rename src/views/{lures-delete-all.mustache => lures/delete-all.mustache} (100%) rename src/views/{lure-delete.mustache => lures/delete.mustache} (100%) rename src/views/{lure-edit.mustache => lures/edit.mustache} (81%) rename src/views/{ => lures}/lures.mustache (86%) rename src/views/{lure-new.mustache => lures/new.mustache} (76%) rename src/views/{pokemon-delete-all.mustache => pokemon/delete-all.mustache} (100%) rename src/views/{pokemon-delete.mustache => pokemon/delete.mustache} (100%) rename src/views/{pokemon-edit.mustache => pokemon/edit.mustache} (89%) rename src/views/{pokemon-new.mustache => pokemon/new.mustache} (89%) rename src/views/{ => pokemon}/pokemon.mustache (88%) rename src/views/{pvp-delete-all.mustache => pvp/delete-all.mustache} (100%) rename src/views/{pvp-delete.mustache => pvp/delete.mustache} (100%) rename src/views/{pvp-edit.mustache => pvp/edit.mustache} (88%) rename src/views/{pvp-new.mustache => pvp/new.mustache} (88%) rename src/views/{quests-delete-all.mustache => quests/delete-all.mustache} (100%) rename src/views/{quest-delete.mustache => quests/delete.mustache} (100%) rename src/views/{quest-edit.mustache => quests/edit.mustache} (81%) rename src/views/{quest-new.mustache => quests/new.mustache} (77%) rename src/views/{ => quests}/quests.mustache (86%) rename src/views/{raids-delete-all.mustache => raids/delete-all.mustache} (100%) rename src/views/{raid-delete.mustache => raids/delete.mustache} (100%) rename src/views/{raid-edit.mustache => raids/edit.mustache} (85%) rename src/views/{raid-new.mustache => raids/new.mustache} (89%) rename src/views/{ => raids}/raids.mustache (87%) rename src/views/{role-add.mustache => roles/add.mustache} (93%) rename src/views/{roles-remove-all.mustache => roles/remove-all.mustache} (100%) rename src/views/{role-remove.mustache => roles/remove.mustache} (89%) rename src/views/{ => roles}/roles.mustache (89%) create mode 100644 static/img/map-pin.png create mode 100644 static/js/fetch-locations.js create mode 100644 static/js/location-selector.js create mode 100644 static/js/locator.js diff --git a/src/data/map.js b/src/data/map.js index 277e90a..ae643a3 100644 --- a/src/data/map.js +++ b/src/data/map.js @@ -1,6 +1,7 @@ 'use strict'; const Localizer = require('../services/locale.js'); +const Location = require('../models/location.js'); const MapPokestop = require('../models/map/pokestop.js'); const config = require('../config.json'); @@ -33,6 +34,21 @@ const buildCityList = (guilds) => { return cities; }; +const buildLocationsList = async (guilds, userId) => { + const locs = []; + const locations = await Location.getAllByUserId(userId); + for (let i = 0; i < locations.length; i++) { + const location = locations[i]; + if (guilds.includes(location.guildId)) { + locs.push({ + 'name': location.name, + 'guild': location.guildId, + }); + } + } + return locs; +}; + const getQuestRewards = async () => { const quests = await MapPokestop.getAll(); const rewards = []; @@ -71,6 +87,7 @@ const getLureTypes = () => { module.exports = { getPokemonNameIdsList, buildCityList, + buildLocationsList, getQuestRewards, getInvasionTypes, getLureTypes, diff --git a/src/index.js b/src/index.js index 10c5428..713a36e 100644 --- a/src/index.js +++ b/src/index.js @@ -20,8 +20,6 @@ const { sessionStore, } = require('./services/session-store.js'); const utils = require('./services/utils.js'); const Localizer = require('./services/locale.js'); -const forms = Localizer.getFormNames(); -console.log('forms:', forms); // TODO: Convert to typescript // TODO: Import/export options diff --git a/src/models/gym.js b/src/models/gym.js index 84f904e..2d844c3 100644 --- a/src/models/gym.js +++ b/src/models/gym.js @@ -107,7 +107,11 @@ Gym.init({ ? data : JSON.parse(data || '[]'); }, - } + }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/invasion.js b/src/models/invasion.js index aac851e..1da9877 100644 --- a/src/models/invasion.js +++ b/src/models/invasion.js @@ -120,6 +120,10 @@ Invasion.init({ : JSON.parse(data || '[]'); }, }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/location.js b/src/models/location.js new file mode 100644 index 0000000..eacb80d --- /dev/null +++ b/src/models/location.js @@ -0,0 +1,126 @@ +'use strict'; + +const { DataTypes, Model, } = require('sequelize'); +const sequelize = require('../services/sequelize.js')(true); + +class Location extends Model { + + static getCount(guildId, userId) { + return Location.count({ + where: { + guildId: guildId, + userId: userId, + } + }); + } + + static getAllByUserId(userId) { + return Location.findAll({ + where: { + userId: userId, + } + }); + } + + static getAll(guildId, userId) { + return Location.findAll({ + where: { + guildId: guildId, + userId: userId, + } + }); + } + + static getByName(guildId, userId, name) { + return Location.findOne({ + where: { + guildId: guildId, + userId: userId, + name: name, + } + }); + } + + static getById(id) { + return Location.findByPk(id); + } + + static delete(guildId, userId, name) { + return Location.destroy({ + where: { + guildId: guildId, + userId: userId, + name: name, + } + }); + } + + static deleteById(id) { + return Location.destroy({ + where: { + id: id, + } + }); + } + + static deleteAll(guildId, userId) { + return Location.destroy({ + where: { + guildId: guildId, + userId: userId, + } + }); + } +} + +Location.init({ + id: { + type: DataTypes.INTEGER(11).UNSIGNED, + primaryKey: true, + autoIncrement: true, + defaultValue: 0, + }, + subscriptionId: { + type: DataTypes.INTEGER(11).UNSIGNED, + allowNull: false, + defaultValue: 0, + }, + guildId: { + type: DataTypes.BIGINT(20).UNSIGNED, + allowNull: false, + }, + userId: { + type: DataTypes.BIGINT(20).UNSIGNED, + allowNull: false, + }, + name: { + type: DataTypes.STRING(128), + allowNull: false, + unique: true, + }, + distance: { + type: DataTypes.INTEGER(11), + defaultValue: 0, + }, + latitude: { + type: DataTypes.DOUBLE(18, 14), + defaultValue: 0, + }, + longitude: { + type: DataTypes.DOUBLE(18, 14), + defaultValue: 0, + }, +}, { + sequelize, + timestamps: false, + underscored: true, + indexes: [ + { + name: 'FK_location_subscriptions_subscription_id', + fields: ['subscription_id'], + }, + ], + tableName: 'locations', +}); + +module.exports = Location; \ No newline at end of file diff --git a/src/models/lure.js b/src/models/lure.js index f703a71..14b52d9 100644 --- a/src/models/lure.js +++ b/src/models/lure.js @@ -109,6 +109,10 @@ Lure.init({ : JSON.parse(data || '[]'); }, }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/pokemon.js b/src/models/pokemon.js index a7d8764..df541a2 100644 --- a/src/models/pokemon.js +++ b/src/models/pokemon.js @@ -169,6 +169,10 @@ Pokemon.init({ } */ }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/pvp.js b/src/models/pvp.js index 584b0c6..c8b3569 100644 --- a/src/models/pvp.js +++ b/src/models/pvp.js @@ -161,6 +161,10 @@ PVP.init({ } */ }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/quest.js b/src/models/quest.js index 486221b..2bfe950 100644 --- a/src/models/quest.js +++ b/src/models/quest.js @@ -100,6 +100,10 @@ Quest.init({ : JSON.parse(data || '[]'); } }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/raid.js b/src/models/raid.js index 3ce74af..4475d69 100644 --- a/src/models/raid.js +++ b/src/models/raid.js @@ -143,6 +143,10 @@ Raid.init({ : JSON.parse(data || '[]'); }, }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/models/subscription.js b/src/models/subscription.js index 688bac3..d1b3bb7 100644 --- a/src/models/subscription.js +++ b/src/models/subscription.js @@ -73,21 +73,6 @@ Subscription.init({ allowNull: false, defaultValue: 1, }, - distance: { - type: DataTypes.INTEGER(11), - allowNull: false, - defaultValue: 0, - }, - latitude: { - type: DataTypes.DOUBLE(18, 14), - allowNull: false, - defaultValue: 0, - }, - longitude: { - type: DataTypes.DOUBLE(18, 14), - allowNull: false, - defaultValue: 0, - }, iconStyle: { type: DataTypes.TEXT, allowNull: false, @@ -98,6 +83,10 @@ Subscription.init({ allowNull: true, defaultValue: null, }, + location: { + type: DataTypes.STRING(32), + defaultValue: null, + }, }, { sequelize, timestamps: false, diff --git a/src/routes/api.js b/src/routes/api.js index f1fea1d..7b944e9 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -12,6 +12,7 @@ const Gym = require('../models/gym.js'); const Quest = require('../models/quest.js'); const Invasion = require('../models/invasion.js'); const Lure = require('../models/lure.js'); +const Location = require('../models/location.js'); const Subscription = require('../models/subscription.js'); const DiscordClient = require('../services/discord.js'); const Localizer = require('../services/locale.js'); @@ -20,6 +21,7 @@ const utils = require('../services/utils.js'); /* eslint-disable no-case-declarations */ router.post('/server/:guild_id/user/:user_id', async (req, res) => { const { guild_id, user_id } = req.params; + const formatted = (req.query.formatted || 'false') === 'true'; const type = req.query.type; switch (type) { case 'subscriptions': @@ -35,6 +37,7 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { invasions: await Invasion.getCount(guild_id, user_id), gyms: await Gym.getCount(guild_id, user_id), lures: await Lure.getCount(guild_id, user_id), + locations: await Location.getCount(guild_id, user_id), }; req.sessionStore.length((err, length) => { if (err) { @@ -186,7 +189,7 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { const pkmnIcon = await Localizer.getPokemonIcon(invasion.rewardPokemonId); invasion.name = invasion.pokestopName; invasion.reward = ` ${pkmnName}`; - invasion.type = Localizer.getInvasionName(invasion.gruntType); + invasion.type = invasion.gruntType ? Localizer.getInvasionName(invasion.gruntType) : ''; invasion.city = formatAreas(guild_id, invasion.city); invasion.buttons = ` @@ -222,6 +225,35 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { } res.json({ data: { lures: lureData } }); break; + case 'locations': + if (!guild_id || guild_id === null || guild_id === 'null') { + showErrorJson(res, guild_id, 'Select a server from the dropdown menu before creating/editing/deleting any subscriptions!', { lures: [] }); + return; + } + const subscription = await Subscription.getSubscription(guild_id, user_id); + if (!subscription) { + showErrorJson(res, guild_id, 'No subscription found'); + return; + } + const locations = await Location.getAll(guild_id, user_id); + const locationData = []; + if (locations) { + for (let location of locations) { + location = location.toJSON(); + if (formatted) { + location.location = `${location.latitude},${location.longitude}`; + location.active = location.name === subscription.location ? "Yes" : "No"; + location.buttons = ` + +   + + `; + } + locationData.push(location); + } + } + res.json({ data: { locations: locationData } }); + break; case 'roles': if (!guild_id || guild_id === null || guild_id === 'null') { showErrorJson(res, guild_id, 'Select a server from the dropdown menu before creating/editing/deleting any subscriptions!', { invasions: [] }); @@ -252,7 +284,6 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { return; } const settings = (await Subscription.getSubscription(guild_id, user_id)).toJSON(); - const formatted = req.query.formatted; if (formatted) { const list = []; const keys = Object.keys(settings); @@ -264,6 +295,13 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { }); res.json({ data: { settings: list } }); } else { + const locations = await Location.getAll(guild_id, user_id); + /* + locations.forEach(loc => { + loc.selected = loc.name === settings.location; + }); + */ + settings.locations = locations; res.json({ data: { settings: settings } }); } break; @@ -282,13 +320,14 @@ router.post('/pokemon/new', async (req, res) => { min_lvl, max_lvl, gender, - city + city, + location, } = req.body; const user_id = req.session.user_id; const areas = getAreas(guild_id, (city || '').split(',')); const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'pokemon-new', `Failed to get user subscription for GuildId: ${guild_id} and UserId: ${user_id}`); + showError(res, 'pokemon/new', `Failed to get user subscription for GuildId: ${guild_id} and UserId: ${user_id}`); return; } const sql = []; @@ -304,6 +343,7 @@ router.post('/pokemon/new', async (req, res) => { exists.maxLvl = max_lvl || 35; exists.gender = gender || '*'; exists.city = utils.arrayUnique(exists.city.concat(areas)); + exists.location = location || null; } else { exists = Pokemon.build({ id: 0, @@ -319,6 +359,7 @@ router.post('/pokemon/new', async (req, res) => { maxLvl: max_lvl || 35, gender: gender || '*', city: areas, + location: location || null, }); } sql.push(exists.toJSON()); @@ -327,7 +368,7 @@ router.post('/pokemon/new', async (req, res) => { await Pokemon.create(sql); } catch (err) { console.error(err); - showError(res, 'pokemon-new', `Failed to create Pokemon ${pokemon} subscriptions for guild: ${guild_id} user: ${user_id}`); + showError(res, 'pokemon/new', `Failed to create Pokemon ${pokemon} subscriptions for guild: ${guild_id} user: ${user_id}`); return; } res.redirect('/pokemon'); @@ -344,7 +385,8 @@ router.post('/pokemon/edit/:id', async (req, res) => { min_lvl, max_lvl, gender, - city + city, + location, } = req.body; //const user_id = req.session.user_id; const pkmn = await Pokemon.getById(id); @@ -361,12 +403,13 @@ router.post('/pokemon/edit/:id', async (req, res) => { pkmn.maxLvl = max_lvl || 35; pkmn.gender = gender || '*'; pkmn.city = areas; + pkmn.location = location || null; const result = await pkmn.save(); if (result) { // Success console.log('Pokemon subscription', id, 'updated successfully.'); } else { - showError(res, 'pokemon-edit', `Failed to update Pokemon subscription ${id}`); + showError(res, 'pokemon/edit', `Failed to update Pokemon subscription ${id}`); return; } } @@ -382,12 +425,12 @@ router.post('/pokemon/delete/:id', async (req, res) => { // Success console.log('Pokemon subscription', id, 'deleted successfully.'); } else { - showError(res, 'pokemon-delete', `Failed to delete Pokemon subscription ${id}`); + showError(res, 'pokemon/delete', `Failed to delete Pokemon subscription ${id}`); return; } } else { // Does not exist - showError(res, 'pokemon-delete', `Failed to find Pokemon subscription ${id}`); + showError(res, 'pokemon/delete', `Failed to find Pokemon subscription ${id}`); return; } res.redirect('/pokemon'); @@ -402,11 +445,11 @@ router.post('/pokemon/delete_all', async (req, res) => { // Success console.log('All Pokemon subscriptions deleted for guild:', guild_id, 'user:', user_id); } else { - showError(res, 'pokemon-delete-all', `Failed to delete all Pokemon subscriptions for guild: ${guild_id} user: ${user_id}`); + showError(res, 'pokemon/delete-all', `Failed to delete all Pokemon subscriptions for guild: ${guild_id} user: ${user_id}`); return; } } else { - showError(res, 'pokemon-delete-all', 'Guild ID or User ID not set, failed to delete all pokemon subscriptions for user.'); + showError(res, 'pokemon/delete-all', 'Guild ID or User ID not set, failed to delete all pokemon subscriptions for user.'); return; } res.redirect('/pokemon'); @@ -422,12 +465,13 @@ router.post('/pvp/new', async (req, res) => { league, min_rank, min_percent, - city + city, + location, } = req.body; const user_id = req.session.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'pvp-new', `Failed to get user subscription for GuildId: ${guild_id} and UserId: ${user_id}`); + showError(res, 'pvp/new', `Failed to get user subscription for GuildId: ${guild_id} and UserId: ${user_id}`); return; } const areas = getAreas(guild_id, (city || '').split(',')); @@ -440,6 +484,7 @@ router.post('/pvp/new', async (req, res) => { exists.minRank = min_rank || 5; exists.minPercent = min_percent || 99; exists.city = utils.arrayUnique(exists.city.concat(areas)); + exists.location = location || null; } else { exists = PVP.build({ id: 0, @@ -452,6 +497,7 @@ router.post('/pvp/new', async (req, res) => { minRank: min_rank || 5, minPercent: min_percent || 99, city: areas, + location: location || null, }); } sql.push(exists.toJSON()); @@ -469,7 +515,8 @@ router.post('/pvp/edit/:id', async (req, res) => { league, min_rank, min_percent, - city + city, + location, } = req.body; //const user_id = req.session.user_id; const exists = await PVP.getById(id); @@ -480,12 +527,13 @@ router.post('/pvp/edit/:id', async (req, res) => { exists.minRank = min_rank || 25; exists.minPercent = min_percent || 98; exists.city = areas; + exists.location = location || null; const result = await exists.save(); if (result) { // Success console.log('PVP subscription', id, 'updated successfully.'); } else { - showError(res, 'pvp-edit', `Failed to update PvP subscription ${id}`); + showError(res, 'pvp/edit', `Failed to update PvP subscription ${id}`); return; } } @@ -501,12 +549,12 @@ router.post('/pvp/delete/:id', async (req, res) => { // Success console.log('PVP subscription with id', id, 'deleted successfully.'); } else { - showError(res, 'pvp-delete', `Failed to delete PvP subscription ${id}`); + showError(res, 'pvp/delete', `Failed to delete PvP subscription ${id}`); return; } } else { // Does not exist - showError(res, 'pvp-delete', `Failed to find Pokemon subscription ${id}`); + showError(res, 'pvp/delete', `Failed to find Pokemon subscription ${id}`); return; } res.redirect('/pokemon#pvp'); @@ -521,11 +569,11 @@ router.post('/pvp/delete_all', async (req, res) => { // Success console.log('All PVP subscriptions deleted for guild:', guild_id, 'user:', user_id); } else { - showError(res, 'pvp-delete-all', `Failed to delete all PvP subscriptions for guild: ${guild_id} user: ${user_id}`); + showError(res, 'pvp/delete-all', `Failed to delete all PvP subscriptions for guild: ${guild_id} user: ${user_id}`); return; } } else { - showError(res, 'pvp-delete-all', 'Guild ID or User ID not set, failed to delete all PVP subscriptions for user.'); + showError(res, 'pvp/delete-all', 'Guild ID or User ID not set, failed to delete all PVP subscriptions for user.'); return; } res.redirect('/pokemon#pvp'); @@ -534,11 +582,11 @@ router.post('/pvp/delete_all', async (req, res) => { // Raid routes router.post('/raids/new', async (req, res) => { - const { guild_id, pokemon, form, city } = req.body; + const { guild_id, pokemon, form, city, location, } = req.body; const user_id = req.session.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'raid-new', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); + showError(res, 'raids/new', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); return; } const areas = getAreas(guild_id, (city || '').split(',')); @@ -555,6 +603,7 @@ router.post('/raids/new', async (req, res) => { pokemonId: pokemonId, form: form, city: areas, + location: location || null, }); } else { exists.city = utils.arrayUnique(exists.city.concat(areas)); @@ -567,19 +616,20 @@ router.post('/raids/new', async (req, res) => { router.post('/raids/edit/:id', async (req, res) => { const id = req.params.id; - const { guild_id, /*pokemon,*/ form, city } = req.body; + const { guild_id, /*pokemon,*/ form, city, location, } = req.body; //const user_id = req.session.user_id; const exists = await Raid.getById(id); if (exists) { const areas = getAreas(guild_id, (city || '').split(',')); exists.form = form; exists.city = areas; + exists.location = location || null; const result = await exists.save(); if (result) { // Success console.log('Raid subscription', id, 'updated successfully.'); } else { - showError(res, 'raid-edit', `Failed to update Raid subscription ${id}`); + showError(res, 'raids/edit', `Failed to update Raid subscription ${id}`); return; } } @@ -596,12 +646,12 @@ router.post('/raids/delete/:id', async (req, res) => { console.log('Raid subscription with id', id, 'deleted successfully.'); } else { console.error('Failed to delete Raid subscription', id); - showError(res, 'raid-delete', `Failed to delete Raid subscription ${id}`); + showError(res, 'raids/delete', `Failed to delete Raid subscription ${id}`); return; } } else { // Does not exist - showError(res, 'raid-delete', `Failed to find Raid subscription ${id}`); + showError(res, 'raids/delete', `Failed to find Raid subscription ${id}`); return; } res.redirect('/raids'); @@ -617,7 +667,7 @@ router.post('/raids/delete_all', async (req, res) => { console.log('All raid subscriptions deleted for guild:', guild_id, 'user:', user_id); } } else { - showError(res, 'raids-delete-all', 'Guild ID or User ID not set, failed to delete all raid subscriptions for user.'); + showError(res, 'raids/delete-all', 'Guild ID or User ID not set, failed to delete all raid subscriptions for user.'); return; } res.redirect('/raids'); @@ -626,11 +676,11 @@ router.post('/raids/delete_all', async (req, res) => { // Gym routes router.post('/gyms/new', async (req, res) => { - const { guild_id, name, min_level, max_level, pokemon } = req.body; + const { guild_id, name, min_level, max_level, pokemon, location, } = req.body; const user_id = req.session.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'gym-new', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); + showError(res, 'gyms/new', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); return; } // TODO: Validate gym name exists in scanner database @@ -638,7 +688,7 @@ router.post('/gyms/new', async (req, res) => { if (exists) { // Already exists console.log('Gym subscription with name', name, 'already exists'); - showError(res, 'gym-new', `Gym subscription with name ${name} already exists`); + showError(res, 'gyms/new', `Gym subscription with name ${name} already exists`); } else { const gym = Gym.build({ id: 0, @@ -649,13 +699,14 @@ router.post('/gyms/new', async (req, res) => { minLevel: min_level, maxLevel: max_level, pokemonIds: (pokemon || '').split(','), + location: location || null, }); const result = await gym.save(); if (result) { // Success console.log('Gym subscription for gym', name, 'created successfully.'); } else { - showError(res, 'gym-new', `Failed to create Gym subscription ${name}`); + showError(res, 'gyms/new', `Failed to create Gym subscription ${name}`); return; } } @@ -663,11 +714,11 @@ router.post('/gyms/new', async (req, res) => { }); router.post('/gyms/edit/:id', async (req, res) => { - const { guild_id, name, min_level, max_level, pokemon } = req.body; + const { guild_id, name, min_level, max_level, pokemon, location, } = req.body; const user_id = req.session.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'gym-edit', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); + showError(res, 'gyms/edit', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); return; } // TODO: Validate gym name exists in scanner database @@ -675,17 +726,18 @@ router.post('/gyms/edit/:id', async (req, res) => { if (!exists) { // Does not exist console.log('Gym subscription with name', name, 'does not exist'); - showError(res, 'gym-edit', `Gym subscription with name ${name} does not exist`); + showError(res, 'gyms/edit', `Gym subscription with name ${name} does not exist`); } else { exists.minLevel = min_level; exists.maxLevel = max_level; exists.pokemonIds = (pokemon || '').split(','); + exists.location = location || null; const result = await exists.save(); if (result) { // Success console.log('Gym subscription for gym', name, 'updated successfully.'); } else { - showError(res, 'gym-edit', `Failed to update Gym subscription ${name}`); + showError(res, 'gyms/edit', `Failed to update Gym subscription ${name}`); return; } } @@ -701,12 +753,12 @@ router.post('/gyms/delete/:id', async (req, res) => { // Success console.log('Gym subscription with id', id, 'deleted successfully.'); } else { - showError(res, 'gym-delete', `Failed to delete Gym subscription ${id}`); + showError(res, 'gyms/delete', `Failed to delete Gym subscription ${id}`); return; } } else { // Does not exist - showError(res, 'gym-delete', `Failed to delete Gym subscription ${id}`); + showError(res, 'gyms/delete', `Failed to delete Gym subscription ${id}`); return; } res.redirect('/raids#gyms'); @@ -721,12 +773,12 @@ router.post('/gyms/delete_all', async (req, res) => { // Success console.log('All Gym subscriptions deleted for guild:', guild_id, 'user:', user_id); } else { - showError(res, 'gyms-delete-all', `Failed to delete all Gym subscriptions for guild: ${guild_id} and user: ${user_id}`); + showError(res, 'gyms/delete-all', `Failed to delete all Gym subscriptions for guild: ${guild_id} and user: ${user_id}`); return; } } else { console.error(''); - showError(res, 'gyms-delete-all', 'Guild ID or User ID not set, failed to delete all gym subscriptions for user.'); + showError(res, 'gyms/delete-all', 'Guild ID or User ID not set, failed to delete all gym subscriptions for user.'); return; } res.redirect('/raids#gyms'); @@ -735,11 +787,11 @@ router.post('/gyms/delete_all', async (req, res) => { // Quest routes router.post('/quests/new', async (req, res) => { - const { guild_id, reward, city } = req.body; + const { guild_id, reward, city, location, } = req.body; const user_id = req.session.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'quest-new', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); + showError(res, 'quests/new', `Failed to get user subscription ID for GuildId: ${guild_id} and UserId: ${user_id}`); return; } const areas = getAreas(guild_id, (city || '').split(',')); @@ -755,6 +807,7 @@ router.post('/quests/new', async (req, res) => { userId: user_id, reward: reward, city: areas, + location: location || null, }); } const results = await exists.save(); @@ -762,7 +815,7 @@ router.post('/quests/new', async (req, res) => { // Success console.log('Quest subscription for reward', reward, 'created successfully.'); } else { - showError(res, 'quest-new', `Failed to create or update Quest subscription reward ${reward}`); + showError(res, 'quests/new', `Failed to create or update Quest subscription reward ${reward}`); return; } res.redirect('/quests'); @@ -770,18 +823,19 @@ router.post('/quests/new', async (req, res) => { router.post('/quests/edit/:id', async (req, res) => { const id = req.params.id; - const { guild_id, /*reward,*/ city } = req.body; + const { guild_id, /*reward,*/ citylocation, } = req.body; //const user_id = req.session.user_id; const quest = await Quest.getById(id); if (quest) { const areas = getAreas(guild_id, (city || '').split(',')); quest.city = areas; + quest.location = location || null; const result = await quest.save(); if (result) { // Success console.log('Quest subscription', id, 'updated successfully.'); } else { - showError(res, 'quest-edit', `Failed to update Quest subscription ${id}`); + showError(res, 'quests/edit', `Failed to update Quest subscription ${id}`); return; } } @@ -797,12 +851,12 @@ router.post('/quests/delete/:id', async (req, res) => { // Success console.log('Quest subscription with id', id, 'deleted successfully.'); } else { - showError(res, 'quest-delete', `Failed to delete Quest subscription ${id}`); + showError(res, 'quests/delete', `Failed to delete Quest subscription ${id}`); return; } } else { // Does not exist - showError(res, 'quest-delete', `Failed to find Quest subscription ${id}`); + showError(res, 'quests/delete', `Failed to find Quest subscription ${id}`); return; } res.redirect('/quests'); @@ -817,11 +871,11 @@ router.post('/quests/delete_all', async (req, res) => { // Success console.log('All quest subscriptions deleted for guild:', guild_id, 'user:', user_id); } else { - showError(res, 'quest-delete-all', `Failed to delete all Quest subscriptions for guild: ${guild_id} user: ${user_id}`); + showError(res, 'quests/delete-all', `Failed to delete all Quest subscriptions for guild: ${guild_id} user: ${user_id}`); return; } } else { - showError(res, 'quests-delete-all', 'Guild ID or User ID not set, failed to delete all quest subscriptions for user.'); + showError(res, 'quests/delete-all', 'Guild ID or User ID not set, failed to delete all quest subscriptions for user.'); return; } res.redirect('/quests'); @@ -830,7 +884,7 @@ router.post('/quests/delete_all', async (req, res) => { // Invasion routes router.post('/invasions/new', async (req, res) => { - const { guild_id, name, pokemon, grunt_type, city } = req.body; + const { guild_id, name, pokemon, grunt_type, city, location, } = req.body; const user_id = req.session.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { @@ -845,6 +899,7 @@ router.post('/invasions/new', async (req, res) => { if (exists) { // Already exists exists.city = utils.arrayUnique(exists.city.concat(areas || [])); + exists.location = location || null; } else { exists = Invasion.build({ id: 0, @@ -855,6 +910,7 @@ router.post('/invasions/new', async (req, res) => { gruntType: grunt_type, rewardPokemonId: pokemonId, city: areas, + location: location || null, }); } const results = await exists.save(); @@ -862,7 +918,7 @@ router.post('/invasions/new', async (req, res) => { // Success console.log('Invasion subscription for reward', pokemonId, 'created successfully.'); } else { - showError(res, 'invasions', `Failed to create Invasion subscription for reward ${pokemonId}`); + showError(res, 'invasions/invasions', `Failed to create Invasion subscription for reward ${pokemonId}`); return; } } @@ -871,7 +927,7 @@ router.post('/invasions/new', async (req, res) => { router.post('/invasions/edit/:id', async (req, res) => { const id = req.params.id; - const { guild_id, name, grunt_type, city } = req.body; + const { guild_id, name, grunt_type, city, location, } = req.body; //const user_id = req.session.user_id; const invasion = await Invasion.getById(id); if (invasion) { @@ -879,12 +935,13 @@ router.post('/invasions/edit/:id', async (req, res) => { invasion.name = name; invasion.gruntType = grunt_type; invasion.city = areas; + invasion.location = location || null; const result = invasion.save(); if (result) { // Success console.log('Invasion subscription', id, 'updated successfully.'); } else { - showError(res, 'invasions', `Failed to update Invasion subscription ${id}`); + showError(res, 'invasions/invasions', `Failed to update Invasion subscription ${id}`); } } res.redirect('/invasions'); @@ -899,12 +956,12 @@ router.post('/invasions/delete/:id', async (req, res) => { // Success console.log('Invasion subscription with id', id, 'deleted successfully.'); } else { - showError(res, 'invasions', `Failed to delete Invasion subscription ${id}`); + showError(res, 'invasions/invasions', `Failed to delete Invasion subscription ${id}`); return; } } else { // Does not exist - showError(res, 'invasions', `Failed to find Invasion subscription ${id}`); + showError(res, 'invasions/invasions', `Failed to find Invasion subscription ${id}`); return; } res.redirect('/invasions'); @@ -922,7 +979,7 @@ router.post('/invasions/delete_all', async (req, res) => { console.error('Failed to delete all Invasion subscriptions for guild:', guild_id, 'user_id:', user_id); } } else { - showError(res, 'invasions', 'Guild ID or User ID not set, failed to delete all invasion subscriptions.'); + showError(res, 'invasions/invasions', 'Guild ID or User ID not set, failed to delete all invasion subscriptions.'); return; } res.redirect('/invasions'); @@ -931,12 +988,12 @@ router.post('/invasions/delete_all', async (req, res) => { // Lure routes router.post('/lures/new', async (req, res) => { - const { guild_id, city } = req.body; + const { guild_id, city, location, } = req.body; let lureTypes = req.body.lure_types; const user_id = defaultData.user_id; const subscription = await Subscription.getSubscription(guild_id, user_id); if (!subscription) { - showError(res, 'invasions', `Failed to get user subscription ID for GuildId: ${guild_id} user: ${user_id}`); + showError(res, 'invasions/invasions', `Failed to get user subscription ID for GuildId: ${guild_id} user: ${user_id}`); return; } if (!Array.isArray(lureTypes)) { @@ -950,6 +1007,7 @@ router.post('/lures/new', async (req, res) => { if (exists) { // Already exists exists.city = utils.arrayUnique(exists.city.concat(areas || [])); + exists.location = location || null; } else { exists = Lure.build({ id: 0, @@ -958,6 +1016,7 @@ router.post('/lures/new', async (req, res) => { userId: user_id, lureType: lureType, city: areas, + location: location || null, }); } const results = await exists.save(); @@ -965,7 +1024,7 @@ router.post('/lures/new', async (req, res) => { // Success console.log('Lure subscription for type', lureType, 'created successfully.'); } else { - showError(res, 'lures', `Failed to create Lure subscription for type ${lureType}`); + showError(res, 'lures/lures', `Failed to create Lure subscription for type ${lureType}`); return; } } @@ -974,18 +1033,19 @@ router.post('/lures/new', async (req, res) => { router.post('/lures/edit/:id', async (req, res) => { const id = req.params.id; - const { guild_id, city } = req.body; + const { guild_id, city, location, } = req.body; //const user_id = defaultData.user_id; const lure = await Lure.getById(id); if (lure) { const areas = getAreas(guild_id, (city || '').split(',')); lure.city = areas; + lure.location = location || null; const result = lure.save(); if (result) { // Success console.log('Lure subscription', id, 'updated successfully.'); } else { - showError(res, 'lures', `Failed to update Lure subscription ${id}`); + showError(res, 'lures/lures', `Failed to update Lure subscription ${id}`); } } res.redirect('/lures'); @@ -1000,12 +1060,12 @@ router.post('/lures/delete/:id', async (req, res) => { // Success console.log('Lure subscription with id', id, 'deleted successfully.'); } else { - showError(res, 'lures', `Failed to delete Lure subscription ${id}`); + showError(res, 'lures/lures', `Failed to delete Lure subscription ${id}`); return; } } else { // Does not exist - showError(res, 'lures', `Failed to find Lure subscription ${id}`); + showError(res, 'lures/lures', `Failed to find Lure subscription ${id}`); return; } res.redirect('/lures'); @@ -1023,65 +1083,144 @@ router.post('/lures/delete_all', async (req, res) => { console.error('Failed to delete all Lure subscriptions for guild:', guild_id, 'user_id:', user_id); } } else { - showError(res, 'lures', 'Guild ID or User ID not set, failed to delete all lure subscriptions.'); + showError(res, 'lures/lures', 'Guild ID or User ID not set, failed to delete all lure subscriptions.'); return; } res.redirect('/lures'); }); -// Role assignment/unassignment routes -router.post('/role/add', async (req, res) => { - const { guild_id, roles } = req.body; - const user_id = req.session.user_id; - const areas = getAreas(guild_id, roles); - let error = false; - for (const area of areas) { - const result = await DiscordClient.addRole(guild_id, user_id, area); - if (!result) { - console.error('Failed to assign city role', area, 'to guild', guild_id, 'user', user_id); - error = true; - } +// Location routes +router.post('/location/new', async (req, res) => { + const { guild_id, name, distance, location, } = req.body; + const user_id = defaultData.user_id; + const subscription = await Subscription.getSubscription(guild_id, user_id); + if (!subscription) { + showError(res, 'locations/locations', `Failed to get user subscription ID for GuildId: ${guild_id} user: ${user_id}`); + return; } - if (error) { - showError(res, 'role-add', `Failed to assign city role(s) to guild ${guild_id} user ${user_id}`); + let exists = await Location.getByName(guild_id, user_id, name); + const split = location.split(','); + if (!exists) { + exists = Location.build({ + subscriptionId: subscription.id, + guildId: guild_id, + userId: user_id, + name: name, + distance: distance, + latitude: split[0], + longitude: split[1], + }); + } else { + exists.name = name, + exists.latitude = split[0], + exists.longitude = split[1], + exists.distance = distance; + } + const results = await exists.save(); + if (results) { + // Success + console.log('Location ', name, ' with distance', distance, 'and location', location, 'created successfully.'); + } else { + showError(res, 'locations/locations', `Failed to create Location subscription for ${name}`); return; } - res.redirect('/roles'); + res.redirect('/locations'); }); -router.get('/role/remove/:guild_id/:id', async (req, res) => { - const { id, guild_id} = req.params; - const userId = req.session.user_id; - const result = await DiscordClient.removeRole(guild_id, userId, id); - if (!result) { - // Failed to remove city role - showError(res, 'role-remove', `Failed to remove city role with id ${id} from guild ${guild_id} user ${userId}`); +router.post('/locations/delete/:id', async (req, res) => { + const id = req.params.id; + const exists = await Location.getById(id); + if (exists) { + const result = await Location.deleteById(id); + if (result) { + // Success + console.log('Location with name', exists.name, 'deleted successfully.'); + } else { + showError(res, 'locations/locations', `Failed to delete location ${exists.name}`); + return; + } + } else { + // Does not exist + showError(res, 'locations/locations', `Failed to find location ${id}`); return; } - res.redirect('/roles'); + res.redirect('/locations'); }); -router.post('/roles/remove_all', async (req, res) => { +router.post('/locations/delete_all', async (req, res) => { const { guild_id } = req.body; - const userId = req.session.user_id; - const guild = config.discord.guilds.find(x => x.id === guild_id); - if (!guild) { - // Failed to find guild - showError(res, 'roles-remove-all', `Failed to find guild ${guild_id} to remove all city roles for user ${userId}`); - return; - } - const roles = guild.geofences; - const result = await DiscordClient.removeAllRoles(guild_id, userId, roles); - if (!result) { - // Failed to remove all city roles - showError(res, 'roles-remove-all', `Failed to remove all city roles from guild ${guild_id} user ${userId}`); + const user_id = defaultData.user_id; + if (guild_id && user_id) { + const result = await Location.deleteAll(guild_id, user_id); + if (result) { + // Success + console.log('All locations deleted for guild:', guild_id, 'user:', user_id); + } else { + console.error('Failed to delete all locations for guild:', guild_id, 'user_id:', user_id); + } + } else { + showError(res, 'locations/locations', 'Guild ID or User ID not set, failed to delete all locations.'); return; } - res.redirect('/roles'); + res.redirect('/locations'); }); +// Role assignment/unassignment routes +if (config.enableGeofenceRoles) { + router.post('/role/add', async (req, res) => { + const { guild_id, roles } = req.body; + const user_id = req.session.user_id; + const areas = getAreas(guild_id, roles); + let error = false; + for (const area of areas) { + const result = await DiscordClient.addRole(guild_id, user_id, area); + if (!result) { + console.error('Failed to assign city role', area, 'to guild', guild_id, 'user', user_id); + error = true; + } + } + if (error) { + showError(res, 'role-add', `Failed to assign city role(s) to guild ${guild_id} user ${user_id}`); + return; + } + res.redirect('/roles'); + }); + + router.get('/role/remove/:guild_id/:id', async (req, res) => { + const { id, guild_id} = req.params; + const userId = req.session.user_id; + const result = await DiscordClient.removeRole(guild_id, userId, id); + if (!result) { + // Failed to remove city role + showError(res, 'role-remove', `Failed to remove city role with id ${id} from guild ${guild_id} user ${userId}`); + return; + } + res.redirect('/roles'); + }); + + router.post('/roles/remove_all', async (req, res) => { + const { guild_id } = req.body; + const userId = req.session.user_id; + const guild = config.discord.guilds.find(x => x.id === guild_id); + if (!guild) { + // Failed to find guild + showError(res, 'roles-remove-all', `Failed to find guild ${guild_id} to remove all city roles for user ${userId}`); + return; + } + const roles = guild.geofences; + const result = await DiscordClient.removeAllRoles(guild_id, userId, roles); + if (!result) { + // Failed to remove all city roles + showError(res, 'roles-remove-all', `Failed to remove all city roles from guild ${guild_id} user ${userId}`); + return; + } + res.redirect('/roles'); + }); +} + + // Settings routes router.post('/settings', async (req, res) => { const { diff --git a/src/routes/ui.js b/src/routes/ui.js index 45606fa..25df5a2 100644 --- a/src/routes/ui.js +++ b/src/routes/ui.js @@ -14,6 +14,7 @@ const MapGym = require('../models/map/gym.js'); const Quest = require('../models/quest.js'); const Invasion = require('../models/invasion.js'); const Lure = require('../models/lure.js'); +const Location = require('../models/location.js'); const Localizer = require('../services/locale.js'); const utils = require('../services/utils.js'); const PokestopQuest = require('../models/map/pokestop'); @@ -44,7 +45,7 @@ router.get('/logout', (req, res) => { router.get('/pokemon', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('pokemon', data); + res.render('pokemon/pokemon', data); }); router.get('/pokemon/new', async (req, res) => { @@ -53,7 +54,8 @@ router.get('/pokemon/new', async (req, res) => { data.pokemon = await map.getPokemonNameIdsList(); data.forms = Localizer.getFormNames(); data.cities = map.buildCityList(req.session.guilds); - res.render('pokemon-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('pokemon/new', data); }); router.get('/pokemon/edit/:id', async (req, res) => { @@ -88,20 +90,24 @@ router.get('/pokemon/edit/:id', async (req, res) => { map.buildCityList(req.session.guilds) ); data.cities = JSON.stringify(cities.filter(x => x.selected).map(y => y.name)); - res.render('pokemon-edit', data); + data.locations = await Location.getAll(pokemon.guildId, pokemon.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === pokemon.location; + }); + res.render('pokemon/edit', data); }); router.get('/pokemon/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('pokemon-delete', data); + res.render('pokemon/delete', data); }); router.get('/pokemon/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('pokemon-delete-all', data); + res.render('pokemon/delete-all', data); }); @@ -112,7 +118,8 @@ router.get('/pvp/new', async (req, res) => { data.pokemon = await map.getPokemonNameIdsList(); data.forms = Localizer.getFormNames(); data.cities = map.buildCityList(req.session.guilds); - res.render('pvp-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('pvp/new', data); }); router.get('/pvp/edit/:id', async (req, res) => { @@ -145,20 +152,24 @@ router.get('/pvp/edit/:id', async (req, res) => { map.buildCityList(req.session.guilds) ); data.cities = JSON.stringify(cities.filter(x => x.selected).map(y => y.name)); - res.render('pvp-edit', data); + data.locations = await Location.getAll(pvp.guildId, pvp.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === pvp.location; + }); + res.render('pvp/edit', data); }); router.get('/pvp/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('pvp-delete', data); + res.render('pvp/delete', data); }); router.get('/pvp/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('pvp-delete-all', data); + res.render('pvp/delete-all', data); }); @@ -166,7 +177,7 @@ router.get('/pvp/delete_all', (req, res) => { router.get('/raids', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('raids', data); + res.render('raids/raids', data); }); router.get('/raid/new', async (req, res) => { @@ -175,7 +186,8 @@ router.get('/raid/new', async (req, res) => { data.pokemon = await map.getPokemonNameIdsList(); data.forms = Localizer.getFormNames(); data.cities = map.buildCityList(req.session.guilds); - res.render('raid-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('raids/new', data); }); router.get('/raid/edit/:id', async (req, res) => { @@ -203,20 +215,24 @@ router.get('/raid/edit/:id', async (req, res) => { map.buildCityList(req.session.guilds) ); data.cities = JSON.stringify(cities.filter(x => x.selected).map(y => y.name)); - res.render('raid-edit', data); + data.locations = await Location.getAll(raid.guildId, raid.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === raid.location; + }); + res.render('raids/edit', data); }); router.get('/raid/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('raid-delete', data); + res.render('raids/delete', data); }); router.get('/raids/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('raids-delete-all', data); + res.render('raids/delete-all', data); }); @@ -228,7 +244,8 @@ router.get('/gym/new', async (req, res) => { const sorted = gyms.map(x => x.name).sort(); data.gyms = [...new Set(sorted)]; data.pokemon = await map.getPokemonNameIdsList(); - res.render('gym-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('gyms/new', data); }); router.get('/gym/edit/:id', async (req, res) => { @@ -252,20 +269,24 @@ router.get('/gym/edit/:id', async (req, res) => { data.name = gym.name; data.min_level = gym.minLevel; data.max_level = gym.maxLevel; - res.render('gym-edit', data); + data.locations = await Location.getAll(gym.guildId, gym.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === gym.location; + }); + res.render('gyms/edit', data); }); router.get('/gym/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('gym-delete', data); + res.render('gyms/delete', data); }); router.get('/gyms/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('gyms-delete-all', data); + res.render('gyms/delete-all', data); }); @@ -273,7 +294,7 @@ router.get('/gyms/delete_all', (req, res) => { router.get('/quests', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('quests', data); + res.render('quests/quests', data); }); router.get('/quest/new', async (req, res) => { @@ -281,7 +302,8 @@ router.get('/quest/new', async (req, res) => { data.servers = validateRoles(req, res); data.rewards = await map.getQuestRewards(); data.cities = map.buildCityList(req.session.guilds); - res.render('quest-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('quests/new', data); }); router.get('/quest/edit/:id', async (req, res) => { @@ -304,20 +326,24 @@ router.get('/quest/edit/:id', async (req, res) => { map.buildCityList(req.session.guilds) ); data.cities = JSON.stringify(cities.filter(x => x.selected).map(y => y.name)); - res.render('quest-edit', data); + data.locations = await Location.getAll(quest.guildId, quest.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === quest.location; + }); + res.render('quests/edit', data); }); router.get('/quest/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('quest-delete', data); + res.render('quests/delete', data); }); router.get('/quests/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('quests-delete-all', data); + res.render('quests/delete-all', data); }); @@ -325,7 +351,7 @@ router.get('/quests/delete_all', (req, res) => { router.get('/invasions', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('invasions', data); + res.render('invasions/invasions', data); }); router.get('/invasion/new', async (req, res) => { @@ -336,7 +362,8 @@ router.get('/invasion/new', async (req, res) => { data.pokestops = [...new Set(pokestopNames)]; data.rewards = await map.getPokemonNameIdsList(); data.cities = map.buildCityList(req.session.guilds); - res.render('invasion-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('invasions/new', data); }); router.get('/invasion/edit/:id', async (req, res) => { @@ -369,20 +396,24 @@ router.get('/invasion/edit/:id', async (req, res) => { map.buildCityList(req.session.guilds) ); data.cities = JSON.stringify(cities.filter(x => x.selected).map(y => y.name)); - res.render('invasion-edit', data); + data.locations = await Location.getAll(invasion.guildId, invasion.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === invasion.location; + }); + res.render('invasions/edit', data); }); router.get('/invasion/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('invasion-delete', data); + res.render('invasions/delete', data); }); router.get('/invasions/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('invasions-delete-all', data); + res.render('invasions/delete-all', data); }); @@ -390,7 +421,7 @@ router.get('/invasions/delete_all', (req, res) => { router.get('/lures', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('lures', data); + res.render('lures/lures', data); }); router.get('/lure/new', async (req, res) => { @@ -398,7 +429,8 @@ router.get('/lure/new', async (req, res) => { data.servers = validateRoles(req, res); data.lureTypes = map.getLureTypes(); data.cities = map.buildCityList(req.session.guilds); - res.render('lure-new', data); + data.locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + res.render('lures/new', data); }); router.get('/lure/edit/:id', async (req, res) => { @@ -424,20 +456,67 @@ router.get('/lure/edit/:id', async (req, res) => { map.buildCityList(req.session.guilds) ); data.cities = JSON.stringify(cities.filter(x => x.selected).map(y => y.name)); - res.render('lure-edit', data); + data.locations = await Location.getAll(lure.guildId, lure.userId); + data.locations.forEach(loc => { + loc.selected = loc.name === lure.location; + }); + res.render('lures/edit', data); }); router.get('/lure/delete/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.id = req.params.id; - res.render('lure-delete', data); + res.render('lures/delete', data); }); router.get('/lures/delete_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('lures-delete-all', data); + res.render('lures/delete-all', data); +}); + + +// Location routes +router.get('/locations', (req, res) => { + const data = { ...defaultData }; + data.servers = validateRoles(req, res); + res.render('locations/locations', data); +}); + +router.get('/location/new', async (req, res) => { + const data = { ...defaultData }; + data.servers = validateRoles(req, res); + res.render('locations/new', data); +}); + +router.get('/location/edit/:id', async (req, res) => { + const data = { ...defaultData }; + data.servers = validateRoles(req, res); + const id = req.params.id; + data.id = id; + const location = await Location.getById(id); + if (!location) { + res.redirect('/locations'); + return; + } + data.name = location.name; + data.distance = location.distance; + data.location = `${location.latitude},${location.longitude}`; + res.render('locations/edit', data); +}); + +router.get('/location/delete/:id', (req, res) => { + const data = { ...defaultData }; + data.servers = validateRoles(req, res); + data.id = req.params.id; + res.render('locations/delete', data); +}); + +router.get('/locations/delete_all', (req, res) => { + const data = { ...defaultData }; + data.servers = validateRoles(req, res); + res.render('locations/delete-all', data); }); @@ -446,34 +525,40 @@ if (config.enableGeofenceRoles) { router.get('/roles', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('roles', data); + res.render('roles/roles', data); }); router.get('/role/add', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); data.roles = map.buildCityList(req.session.guilds); - res.render('role-add', data); + res.render('roles/add', data); }); router.get('/role/remove/:id', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('role-remove', data); + res.render('roles/remove', data); }); router.get('/roles/remove_all', (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); - res.render('roles-remove-all', data); + res.render('roles/remove-all', data); }); } // Settings routes -router.get('/settings', (req, res) => { +router.get('/settings', async (req, res) => { const data = { ...defaultData }; data.servers = validateRoles(req, res); + const locations = await map.buildLocationsList(req.session.guilds, req.session.user_id); + data.locations = locations.map(x => { return { + name: x.name, + guild: x.guild, + selected: false, + }}); res.render('settings', data); }); @@ -519,16 +604,6 @@ const getSelectedAreas = (guildId, currentAreas, availableAreas) => { city.selected = currentAreas.includes(city.name.toLowerCase()); } }); - // If no areas then insert 'None' as selected - /* - if (currentAreas.length === 0) { - availableAreas.splice(0, 0, { - name: 'None', - guild: guildId, - selected: true, - }); - } - */ return availableAreas; }; diff --git a/src/views/gyms-delete-all.mustache b/src/views/gyms/delete-all.mustache similarity index 100% rename from src/views/gyms-delete-all.mustache rename to src/views/gyms/delete-all.mustache diff --git a/src/views/gym-delete.mustache b/src/views/gyms/delete.mustache similarity index 100% rename from src/views/gym-delete.mustache rename to src/views/gyms/delete.mustache diff --git a/src/views/gym-edit.mustache b/src/views/gyms/edit.mustache similarity index 88% rename from src/views/gym-edit.mustache rename to src/views/gyms/edit.mustache index d42af94..60afa43 100644 --- a/src/views/gym-edit.mustache +++ b/src/views/gyms/edit.mustache @@ -59,6 +59,15 @@ {{Maximum Level}} +
+ {{Location}} + +

@@ -72,5 +81,4 @@ window.location.href = '/'; } $('#guild_id').val(guildId); - $('#server_selector').prop('disabled', true); diff --git a/src/views/gym-new.mustache b/src/views/gyms/new.mustache similarity index 84% rename from src/views/gym-new.mustache rename to src/views/gyms/new.mustache index 6a28bd1..f1737c4 100644 --- a/src/views/gym-new.mustache +++ b/src/views/gyms/new.mustache @@ -59,6 +59,12 @@ {{Maximum Level}} +
+ {{Location}} + +

@@ -66,11 +72,17 @@ + diff --git a/src/views/header.mustache b/src/views/header.mustache index 10f76e2..bf941e0 100644 --- a/src/views/header.mustache +++ b/src/views/header.mustache @@ -8,6 +8,7 @@ + @@ -23,6 +24,7 @@ + {{#analytics}} diff --git a/src/views/index.mustache b/src/views/index.mustache index 5512caa..76d9f81 100644 --- a/src/views/index.mustache +++ b/src/views/index.mustache @@ -84,6 +84,15 @@ +
+ +
@@ -153,6 +162,7 @@ updateCounter(".quests_count", result.data.subscriptions.quests); updateCounter(".invasions_count", result.data.subscriptions.invasions); updateCounter(".lures_count", result.data.subscriptions.lures); + updateCounter(".locations_count", result.data.subscriptions.locations); $('#clients_online').text(result.data.clients_online); showError('Select a server from the dropdown menu before creating/editing/deleting any subscriptions!'); diff --git a/src/views/invasions-delete-all.mustache b/src/views/invasions/delete-all.mustache similarity index 100% rename from src/views/invasions-delete-all.mustache rename to src/views/invasions/delete-all.mustache diff --git a/src/views/invasion-delete.mustache b/src/views/invasions/delete.mustache similarity index 100% rename from src/views/invasion-delete.mustache rename to src/views/invasions/delete.mustache diff --git a/src/views/invasion-edit.mustache b/src/views/invasions/edit.mustache similarity index 84% rename from src/views/invasion-edit.mustache rename to src/views/invasions/edit.mustache index ef4a73c..020cdcc 100644 --- a/src/views/invasion-edit.mustache +++ b/src/views/invasions/edit.mustache @@ -34,6 +34,15 @@
+
+ {{Location}} + +

@@ -54,6 +63,5 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); diff --git a/src/views/invasions.mustache b/src/views/invasions/invasions.mustache similarity index 86% rename from src/views/invasions.mustache rename to src/views/invasions/invasions.mustache index 908e6b2..7238099 100644 --- a/src/views/invasions.mustache +++ b/src/views/invasions/invasions.mustache @@ -20,6 +20,7 @@ {{Invasion Type}} {{Reward}} {{City}} + {{Location}} @@ -41,7 +42,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=invasions", "dataSrc": "data.invasions", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -54,11 +55,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -70,16 +71,17 @@ { "data": "type" }, { "data": "reward" }, { "data": "city" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [2], - "orderable": false + "targets": [4], + "orderable": false, }], - "responsive": true + "responsive": true, }); function refreshData() { diff --git a/src/views/invasion-new.mustache b/src/views/invasions/new.mustache similarity index 86% rename from src/views/invasion-new.mustache rename to src/views/invasions/new.mustache index cf8b53b..d9a8b8f 100644 --- a/src/views/invasion-new.mustache +++ b/src/views/invasions/new.mustache @@ -61,6 +61,12 @@
+
+ {{Location}} + +

@@ -69,6 +75,7 @@ + diff --git a/src/views/locations/delete-all.mustache b/src/views/locations/delete-all.mustache new file mode 100644 index 0000000..4889985 --- /dev/null +++ b/src/views/locations/delete-all.mustache @@ -0,0 +1,27 @@ +{{> header}} + +{{> navbar}} + +
+
+
Error! {{error}}
+
+{{#show_error}}
{{/show_error}} + +

{{Delete All Locations}}

+
+
+
+
+

{{Are you sure that you want to delete all of your locations?}}

+ {{Cancel}} + + +
+
+
+
+ + \ No newline at end of file diff --git a/src/views/locations/delete.mustache b/src/views/locations/delete.mustache new file mode 100644 index 0000000..60480d5 --- /dev/null +++ b/src/views/locations/delete.mustache @@ -0,0 +1,27 @@ +{{> header}} + +{{> navbar}} + +
+
+
Error! {{error}}
+
+{{#show_error}}
{{/show_error}} + +

{{Delete Location}} {{name}}

+
+
+
+
+

{{Are you sure that you want to delete location}} {{name}}?

+ {{Cancel}} + + +
+
+
+
+ + \ No newline at end of file diff --git a/src/views/locations/edit.mustache b/src/views/locations/edit.mustache new file mode 100644 index 0000000..2b2ed91 --- /dev/null +++ b/src/views/locations/edit.mustache @@ -0,0 +1,37 @@ +{{> header}} + +{{> navbar}} + +
+
+
Error! {{error}}
+
+{{#show_error}}
{{/show_error}} + +

{{Edit Location}} {{name}}

+
+
+
+
+ {{Location Name}} + +
+
+ {{Max Distance}} + +
+
+
+ + +
+ +
+
+
+ + + diff --git a/src/views/locations/locations.mustache b/src/views/locations/locations.mustache new file mode 100644 index 0000000..ee9481b --- /dev/null +++ b/src/views/locations/locations.mustache @@ -0,0 +1,98 @@ +{{> header}} + +{{> navbar}} + +
+
+
+
+ +

{{Locations}}

+
+
+ {{Delete All}} + {{New Location}} +

+ + + + + + + + + + + + +
{{Name}}{{Distance}}{{Location}}{{Active}}
+
+
+ +{{> footer}} + + \ No newline at end of file diff --git a/src/views/locations/new.mustache b/src/views/locations/new.mustache new file mode 100644 index 0000000..270d743 --- /dev/null +++ b/src/views/locations/new.mustache @@ -0,0 +1,42 @@ +{{> header}} + +{{> navbar}} + +
+
+
Error! {{error}}
+
+{{#show_error}}
{{/show_error}} + +

{{New Location}}

+
+
+
+
+ {{Location Name}} + +
+
+ {{Max Distance}} + +
+
+
+ + +
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/views/lures-delete-all.mustache b/src/views/lures/delete-all.mustache similarity index 100% rename from src/views/lures-delete-all.mustache rename to src/views/lures/delete-all.mustache diff --git a/src/views/lure-delete.mustache b/src/views/lures/delete.mustache similarity index 100% rename from src/views/lure-delete.mustache rename to src/views/lures/delete.mustache diff --git a/src/views/lure-edit.mustache b/src/views/lures/edit.mustache similarity index 81% rename from src/views/lure-edit.mustache rename to src/views/lures/edit.mustache index 3d0f62c..44d4467 100644 --- a/src/views/lure-edit.mustache +++ b/src/views/lures/edit.mustache @@ -20,6 +20,15 @@
+
+ {{Location}} + +

@@ -40,6 +49,5 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); diff --git a/src/views/lures.mustache b/src/views/lures/lures.mustache similarity index 86% rename from src/views/lures.mustache rename to src/views/lures/lures.mustache index fd9929f..692591f 100644 --- a/src/views/lures.mustache +++ b/src/views/lures/lures.mustache @@ -18,6 +18,7 @@ {{Lure Type}} {{City}} + {{Location}} @@ -39,7 +40,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=lures", "dataSrc": "data.lures", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -52,11 +53,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -66,16 +67,17 @@ "columns": [ { "data": "type" }, { "data": "city" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [2], - "orderable": false + "targets": [3], + "orderable": false, }], - "responsive": true + "responsive": true, }); function refreshData() { diff --git a/src/views/lure-new.mustache b/src/views/lures/new.mustache similarity index 76% rename from src/views/lure-new.mustache rename to src/views/lures/new.mustache index 6ffb7e7..fb3796e 100644 --- a/src/views/lure-new.mustache +++ b/src/views/lures/new.mustache @@ -29,6 +29,12 @@
+
+ {{Location}} + +

@@ -37,6 +43,7 @@ + diff --git a/src/views/navbar.mustache b/src/views/navbar.mustache index 918c554..b4dd561 100644 --- a/src/views/navbar.mustache +++ b/src/views/navbar.mustache @@ -63,6 +63,7 @@  {{username}} @@ -81,6 +82,9 @@ const guildId = get("guild_id"); $("#server_selector").val(guildId); $('#guild_id').val(guildId); + if (!guildId) { + window.location.href = '/'; + } $(document).ready(function() { // Get current URL path and assign 'active' class var pathname = window.location.pathname; @@ -91,4 +95,5 @@ // If no server/guild selected hide subscription pages $('.nav-pages').prop('hidden', true); } + $('#server_selector').prop('disabled', true); diff --git a/src/views/pokemon-delete-all.mustache b/src/views/pokemon/delete-all.mustache similarity index 100% rename from src/views/pokemon-delete-all.mustache rename to src/views/pokemon/delete-all.mustache diff --git a/src/views/pokemon-delete.mustache b/src/views/pokemon/delete.mustache similarity index 100% rename from src/views/pokemon-delete.mustache rename to src/views/pokemon/delete.mustache diff --git a/src/views/pokemon-edit.mustache b/src/views/pokemon/edit.mustache similarity index 89% rename from src/views/pokemon-edit.mustache rename to src/views/pokemon/edit.mustache index 8493d92..40b735b 100644 --- a/src/views/pokemon-edit.mustache +++ b/src/views/pokemon/edit.mustache @@ -62,6 +62,15 @@
+
+ {{Location}} + +

@@ -88,7 +97,6 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); $('#iv').change(function() { $('#iv_list').prop('disabled', this.value.length > 0); }); @@ -96,4 +104,6 @@ $('#iv').prop('disabled', this.value.length > 0); }); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); + + console.log("{{{locations}}}"); \ No newline at end of file diff --git a/src/views/pokemon-new.mustache b/src/views/pokemon/new.mustache similarity index 89% rename from src/views/pokemon-new.mustache rename to src/views/pokemon/new.mustache index 079bbbd..2969f1b 100644 --- a/src/views/pokemon-new.mustache +++ b/src/views/pokemon/new.mustache @@ -89,6 +89,12 @@
+
+ {{Location}} + +

@@ -97,6 +103,7 @@ + \ No newline at end of file diff --git a/src/views/pokemon.mustache b/src/views/pokemon/pokemon.mustache similarity index 88% rename from src/views/pokemon.mustache rename to src/views/pokemon/pokemon.mustache index 87b8f72..745e597 100644 --- a/src/views/pokemon.mustache +++ b/src/views/pokemon/pokemon.mustache @@ -38,6 +38,7 @@ {{Level}} {{Gender}} {{City}} + {{Location}} @@ -59,6 +60,7 @@ {{Minimum Rank}} {{Minimum Percent}} {{City}} + {{Location}} @@ -91,7 +93,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=pokemon", "dataSrc": "data.pokemon", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -104,11 +106,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -125,16 +127,17 @@ { "data": "lvl" }, { "data": "genderName" }, { "data": "city" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [9], - "orderable": false + "targets": [10], + "orderable": false, }], - "responsive": true + "responsive": true, }); const tablePVP = $('#table-pvp').DataTable({ @@ -142,7 +145,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=pvp", "dataSrc": "data.pvp", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -155,11 +158,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -174,16 +177,17 @@ { "data": "minRank" }, { "data": "minPercent" }, { "data": "city" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [7], - "orderable": false + "targets": [8], + "orderable": false, }], - "responsive": true + "responsive": true, }); function refreshData() { diff --git a/src/views/pvp-delete-all.mustache b/src/views/pvp/delete-all.mustache similarity index 100% rename from src/views/pvp-delete-all.mustache rename to src/views/pvp/delete-all.mustache diff --git a/src/views/pvp-delete.mustache b/src/views/pvp/delete.mustache similarity index 100% rename from src/views/pvp-delete.mustache rename to src/views/pvp/delete.mustache diff --git a/src/views/pvp-edit.mustache b/src/views/pvp/edit.mustache similarity index 88% rename from src/views/pvp-edit.mustache rename to src/views/pvp/edit.mustache index c4f48cf..f805d2a 100644 --- a/src/views/pvp-edit.mustache +++ b/src/views/pvp/edit.mustache @@ -49,6 +49,15 @@
+
+ {{Location}} + +

@@ -74,6 +83,5 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); \ No newline at end of file diff --git a/src/views/pvp-new.mustache b/src/views/pvp/new.mustache similarity index 88% rename from src/views/pvp-new.mustache rename to src/views/pvp/new.mustache index 865bf02..3ff82c7 100644 --- a/src/views/pvp-new.mustache +++ b/src/views/pvp/new.mustache @@ -76,6 +76,12 @@
+
+ {{Location}} + +

@@ -84,6 +90,7 @@ + diff --git a/src/views/quests-delete-all.mustache b/src/views/quests/delete-all.mustache similarity index 100% rename from src/views/quests-delete-all.mustache rename to src/views/quests/delete-all.mustache diff --git a/src/views/quest-delete.mustache b/src/views/quests/delete.mustache similarity index 100% rename from src/views/quest-delete.mustache rename to src/views/quests/delete.mustache diff --git a/src/views/quest-edit.mustache b/src/views/quests/edit.mustache similarity index 81% rename from src/views/quest-edit.mustache rename to src/views/quests/edit.mustache index 117c653..5b05b3b 100644 --- a/src/views/quest-edit.mustache +++ b/src/views/quests/edit.mustache @@ -20,6 +20,15 @@
+
+ {{Location}} + +

@@ -40,6 +49,5 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); diff --git a/src/views/quest-new.mustache b/src/views/quests/new.mustache similarity index 77% rename from src/views/quest-new.mustache rename to src/views/quests/new.mustache index e97dd8d..26218e2 100644 --- a/src/views/quest-new.mustache +++ b/src/views/quests/new.mustache @@ -36,6 +36,12 @@
+
+ {{Location}} + +

@@ -44,6 +50,7 @@ + diff --git a/src/views/quests.mustache b/src/views/quests/quests.mustache similarity index 86% rename from src/views/quests.mustache rename to src/views/quests/quests.mustache index 5787ee1..0472bdd 100644 --- a/src/views/quests.mustache +++ b/src/views/quests/quests.mustache @@ -18,6 +18,7 @@ {{Reward}} {{City}} + {{Location}} @@ -39,7 +40,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=quests", "dataSrc": "data.quests", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -52,11 +53,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -66,16 +67,17 @@ "columns": [ { "data": "reward" }, { "data": "city" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [2], - "orderable": false + "targets": [3], + "orderable": false, }], - "responsive": true + "responsive": true, }); function refreshData() { diff --git a/src/views/raids-delete-all.mustache b/src/views/raids/delete-all.mustache similarity index 100% rename from src/views/raids-delete-all.mustache rename to src/views/raids/delete-all.mustache diff --git a/src/views/raid-delete.mustache b/src/views/raids/delete.mustache similarity index 100% rename from src/views/raid-delete.mustache rename to src/views/raids/delete.mustache diff --git a/src/views/raid-edit.mustache b/src/views/raids/edit.mustache similarity index 85% rename from src/views/raid-edit.mustache rename to src/views/raids/edit.mustache index 5d4fffc..65543a9 100644 --- a/src/views/raid-edit.mustache +++ b/src/views/raids/edit.mustache @@ -32,6 +32,15 @@
+
+ {{Location}} + +

@@ -56,6 +65,5 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); diff --git a/src/views/raid-new.mustache b/src/views/raids/new.mustache similarity index 89% rename from src/views/raid-new.mustache rename to src/views/raids/new.mustache index 737c9db..9efbf2c 100644 --- a/src/views/raid-new.mustache +++ b/src/views/raids/new.mustache @@ -60,6 +60,12 @@
+
+ {{Location}} + +

@@ -68,6 +74,7 @@ + diff --git a/src/views/raids.mustache b/src/views/raids/raids.mustache similarity index 87% rename from src/views/raids.mustache rename to src/views/raids/raids.mustache index cad4f6c..a5e26aa 100644 --- a/src/views/raids.mustache +++ b/src/views/raids/raids.mustache @@ -25,6 +25,7 @@ {{Pokemon}} {{Form}} {{City}} + {{Location}} @@ -43,6 +44,7 @@ {{Minimum Level}} {{Maximum Level}} {{Pokemon}} + {{Location}} @@ -82,7 +84,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=raids", "dataSrc": "data.raids", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -95,11 +97,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -110,23 +112,24 @@ { "data": "name" }, { "data": "form" }, { "data": "city" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [3], - "orderable": false + "targets": [4], + "orderable": false, }], - "responsive": true + "responsive": true, }); const tableGyms = $('#table-gyms').DataTable({ "ajax": { "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=gyms", "dataSrc": "data.gyms", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -139,11 +142,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -155,16 +158,17 @@ { "data": "minLevel" }, { "data": "maxLevel" }, { "data": "pokemonIds" }, - { "data": "buttons" } + { "data": "location" }, + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ - "targets": [1], - "orderable": false + "targets": [5], + "orderable": false, }], - "responsive": true + "responsive": true, }); function refreshData() { diff --git a/src/views/role-add.mustache b/src/views/roles/add.mustache similarity index 93% rename from src/views/role-add.mustache rename to src/views/roles/add.mustache index cef3b3f..00d2f28 100644 --- a/src/views/role-add.mustache +++ b/src/views/roles/add.mustache @@ -37,5 +37,4 @@ if (guilds) { guilds.forEach(guild => guild.hidden = false); } - $('#server_selector').prop('disabled', true); diff --git a/src/views/roles-remove-all.mustache b/src/views/roles/remove-all.mustache similarity index 100% rename from src/views/roles-remove-all.mustache rename to src/views/roles/remove-all.mustache diff --git a/src/views/role-remove.mustache b/src/views/roles/remove.mustache similarity index 89% rename from src/views/role-remove.mustache rename to src/views/roles/remove.mustache index 4453480..82532b3 100644 --- a/src/views/role-remove.mustache +++ b/src/views/roles/remove.mustache @@ -20,8 +20,4 @@
- - - \ No newline at end of file + \ No newline at end of file diff --git a/src/views/roles.mustache b/src/views/roles/roles.mustache similarity index 89% rename from src/views/roles.mustache rename to src/views/roles/roles.mustache index eec20ef..cb5a61e 100644 --- a/src/views/roles.mustache +++ b/src/views/roles/roles.mustache @@ -51,7 +51,7 @@ "url": "/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=roles", "dataSrc": "data.roles", "async": true, - "type": "POST" + "type": "POST", }, //"dom": "Bfrtip", // Reference: https://stackoverflow.com/a/43176143 @@ -64,11 +64,11 @@ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", "fixedHeader": { "header": true, - "headerOffset": $('.navbar').height() + 15 + "headerOffset": $('.navbar').height() + 15, }, "buttons": [ "colvis", - "pageLength" + "pageLength", ], "colReorder": true, "stateSave": true, @@ -77,23 +77,19 @@ "pageLength": 100, "columns": [ { "data": "name" }, - { "data": "buttons" } + { "data": "buttons" }, ], "info": true, "order": [[ 0, "asc" ]], "search.caseInsensitive": true, "columnDefs": [{ "targets": [1], - "orderable": false + "orderable": false, }], - "responsive": true + "responsive": true, }); function refreshData() { $("#table").DataTable().ajax.url("/api/server/" + $('#server_selector').val() + "/user/{{user_id}}?type=roles").load(); } - - function testRemove() { - - } \ No newline at end of file diff --git a/src/views/settings.mustache b/src/views/settings.mustache index abf0880..f37a068 100644 --- a/src/views/settings.mustache +++ b/src/views/settings.mustache @@ -25,12 +25,16 @@
- {{Location}} - -
-
- {{Max Distance}} - + Global {{Location}} +
{{^hide_phone_number}}
@@ -70,10 +74,11 @@ type: "json", success: function(result) { $('#icon_style').val(result.data.settings.iconStyle); - $('#distance').val(result.data.settings.distance); - $('#location').val(`${result.data.settings.latitude},${result.data.settings.longitude}`); $('#phone_number').val(result.data.settings.phoneNumber); $('#enabled').prop('checked', result.data.settings.enabled); + for (const location of result.data.settings.locations) { + $('#location').append(new Option(location.name, location.name, location.name === result.data.settings.location, location.name === result.data.settings.location)); + } } }); } diff --git a/static/img/map-pin.png b/static/img/map-pin.png new file mode 100644 index 0000000000000000000000000000000000000000..7a2b9b30b1152ca14587d71a47d53bd324c2b101 GIT binary patch literal 19517 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 Jm2dc0{|9E|$yfjY literal 0 HcmV?d00001 diff --git a/static/js/city-map.js b/static/js/city-map.js index 6c520c9..5bdd9a2 100644 --- a/static/js/city-map.js +++ b/static/js/city-map.js @@ -89,6 +89,7 @@ function loadGeofences(selected) { }); } } + // Set dom value to selected geofences $('#city').val(selectedGeofences.join(',')); } diff --git a/static/js/fetch-locations.js b/static/js/fetch-locations.js new file mode 100644 index 0000000..54e161a --- /dev/null +++ b/static/js/fetch-locations.js @@ -0,0 +1,8 @@ +function fetchLocations(guildId, userId, resultCallback) { + $.ajax({ + url: `/api/server/${guildId}/user/${userId}?type=locations`, + async: true, + type: 'POST', + success: resultCallback, + }); +} \ No newline at end of file diff --git a/static/js/location-selector.js b/static/js/location-selector.js new file mode 100644 index 0000000..48baf0c --- /dev/null +++ b/static/js/location-selector.js @@ -0,0 +1,82 @@ +let tileLayer; +let locationLayer = new L.LayerGroup(); +let editableLayers = new L.FeatureGroup(); +let initialLocation; + +// TODO: Save last latlng +// TODO: Keep track of circle + +function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, location = null, radius = 1000) { + const map = L.map('map', { + preferCanvas: true, + //worldCopyJump: true, + updateWhenIdle: true, + updateWhenZooming: false, + layers: [locationLayer], + maxZoom: maxZoom, + //renderer: L.canvas() + }); + map.setView(startLocation, startZoom); + map.on('click', function(e) { + locationLayer.clearLayers(); + const radius = $('#distance').val(); + //console.log('latlng:', e.target); + //const radius = e.target._size.x; + const circle = createCircle(e.latlng.lat, e.latlng.lng, radius); + locationLayer.addLayer(circle); + $('#location').val(`${e.latlng.lat},${e.latlng.lng}`); + }); + + let scale = ''; + if (L.Browser.retina) { + scale = '@2x'; + } + const split = tileserver.split(';'); + tileLayer = L.tileLayer(split[0], { + attribution: split[1], + minZoom: minZoom, + maxZoom: maxZoom, + scale: scale, + hq: L.Browser.retina + }); + tileLayer.addTo(map); + + // FeatureGroup is to store editable layers + const options = { + position: 'topleft', + draw: { + polyline: false, + polygon: false, + circle: true, + rectangle: false, + marker: false, + }, + edit: false, + }; + map.addControl(new L.Control.Draw(options)); + map.on(L.Draw.Event.CREATED, function (e) { + editableLayers.addLayer(e.layer); + }); + + initialLocation = location; + if (initialLocation) { + loadLocation(initialLocation, radius); + } +} + +function loadLocation(location, radius) { + const split = location.split(','); + const circle = createCircle(split[0], split[1], radius); + locationLayer.addLayer(circle); + $('#location').val(location); +} + +function createCircle(lat, lng, radius) { + const circle = L.circle([lat, lng], { + color: 'red', + fillColor: '#f03', + fillOpacity: 0.5, + radius: radius + }); + return circle; +} \ No newline at end of file diff --git a/static/js/locator.js b/static/js/locator.js new file mode 100644 index 0000000..2457d33 --- /dev/null +++ b/static/js/locator.js @@ -0,0 +1,7 @@ +function getLocation(positionCallback) { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition(positionCallback); + } else { + console.warn("Geolocation is not supported by this browser."); + } +} \ No newline at end of file diff --git a/static/locales/_de.json b/static/locales/_de.json index ac88f40..61760c9 100644 --- a/static/locales/_de.json +++ b/static/locales/_de.json @@ -118,8 +118,15 @@ "Assign": "Assign", "Lure Type": "Lure Type", "Server Selector": "Server Selector", - "None": "None/Location", + "None": "None", "Invasion Type": "Invasion Type", "Pokestop Name": "Pokestop Name", - "Search": "Search" + "Search": "Search", + "Locations": "Locations", + "Location Name": "Location Name", + "New Location": "New Location", + "Edit Location": "Edit Location", + "Active": "Active", + "Distance": "Distance", + "Choose a Location": "Choose a Location" } diff --git a/static/locales/_en.json b/static/locales/_en.json index b0df19f..a4c7eef 100644 --- a/static/locales/_en.json +++ b/static/locales/_en.json @@ -118,8 +118,15 @@ "Assign": "Assign", "Lure Type": "Lure Type", "Server Selector": "Server Selector", - "None": "None/Location", + "None": "None", "Invasion Type": "Invasion Type", "Pokestop Name": "Pokestop Name", - "Search": "Search" + "Search": "Search", + "Locations": "Locations", + "Location Name": "Location Name", + "New Location": "New Location", + "Edit Location": "Edit Location", + "Active": "Active", + "Distance": "Distance", + "Choose a Location": "Choose a Location" } \ No newline at end of file diff --git a/static/locales/_es.json b/static/locales/_es.json index b0df19f..a4c7eef 100644 --- a/static/locales/_es.json +++ b/static/locales/_es.json @@ -118,8 +118,15 @@ "Assign": "Assign", "Lure Type": "Lure Type", "Server Selector": "Server Selector", - "None": "None/Location", + "None": "None", "Invasion Type": "Invasion Type", "Pokestop Name": "Pokestop Name", - "Search": "Search" + "Search": "Search", + "Locations": "Locations", + "Location Name": "Location Name", + "New Location": "New Location", + "Edit Location": "Edit Location", + "Active": "Active", + "Distance": "Distance", + "Choose a Location": "Choose a Location" } \ No newline at end of file From 4e0d901c6015da1da6ceecdb7e218254e852b07a Mon Sep 17 00:00:00 2001 From: versx Date: Mon, 10 May 2021 16:24:24 -0700 Subject: [PATCH 02/12] Add auto locate button and adjust circle radius when changed --- src/routes/api.js | 2 +- src/views/header.mustache | 5 ++++- static/js/location-selector.js | 31 +++++++++++++++++++++---------- static/locales/_de.json | 2 +- static/locales/_en.json | 2 +- static/locales/_es.json | 2 +- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/routes/api.js b/src/routes/api.js index 7b944e9..7f2be9c 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -241,7 +241,7 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { for (let location of locations) { location = location.toJSON(); if (formatted) { - location.location = `${location.latitude},${location.longitude}`; + location.location = `${location.latitude},${location.longitude}`; location.active = location.name === subscription.location ? "Yes" : "No"; location.buttons = ` diff --git a/src/views/header.mustache b/src/views/header.mustache index bf941e0..820c8b8 100644 --- a/src/views/header.mustache +++ b/src/views/header.mustache @@ -3,12 +3,14 @@ - + + + @@ -25,6 +27,7 @@ + {{#analytics}} diff --git a/static/js/location-selector.js b/static/js/location-selector.js index 48baf0c..f8b190a 100644 --- a/static/js/location-selector.js +++ b/static/js/location-selector.js @@ -1,10 +1,14 @@ let tileLayer; let locationLayer = new L.LayerGroup(); -let editableLayers = new L.FeatureGroup(); +//let editableLayers = new L.FeatureGroup(); let initialLocation; +let lastLocation; +let circleMarker; -// TODO: Save last latlng -// TODO: Keep track of circle +$('#distance').change(function(e) { + const radius = $('#distance').val(); + circle.setRadius(radius) ; +}); function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, location = null, radius = 1000) { const map = L.map('map', { @@ -20,10 +24,9 @@ function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, locatio map.on('click', function(e) { locationLayer.clearLayers(); const radius = $('#distance').val(); - //console.log('latlng:', e.target); - //const radius = e.target._size.x; - const circle = createCircle(e.latlng.lat, e.latlng.lng, radius); + circle = createCircle(e.latlng.lat, e.latlng.lng, radius); locationLayer.addLayer(circle); + lastLocation = e.latlng; $('#location').val(`${e.latlng.lat},${e.latlng.lng}`); }); @@ -37,11 +40,12 @@ function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, locatio minZoom: minZoom, maxZoom: maxZoom, scale: scale, - hq: L.Browser.retina + hq: L.Browser.retina, }); tileLayer.addTo(map); - // FeatureGroup is to store editable layers + // FeatureGroup is to store editable layers + /* const options = { position: 'topleft', draw: { @@ -57,6 +61,13 @@ function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, locatio map.on(L.Draw.Event.CREATED, function (e) { editableLayers.addLayer(e.layer); }); + */ + + L.control.locate({ + icon: 'fa fa-crosshairs', + setView: 'untilPan', + keepCurrentZoomLevel: true, + }).addTo(map); initialLocation = location; if (initialLocation) { @@ -66,13 +77,13 @@ function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, locatio function loadLocation(location, radius) { const split = location.split(','); - const circle = createCircle(split[0], split[1], radius); + circle = createCircle(split[0], split[1], radius); locationLayer.addLayer(circle); $('#location').val(location); } function createCircle(lat, lng, radius) { - const circle = L.circle([lat, lng], { + circle = L.circle([lat, lng], { color: 'red', fillColor: '#f03', fillOpacity: 0.5, diff --git a/static/locales/_de.json b/static/locales/_de.json index 61760c9..7fedaaa 100644 --- a/static/locales/_de.json +++ b/static/locales/_de.json @@ -109,7 +109,7 @@ "Enable Subscriptions": "Abonnements aktivieren", "Icon Style": "Icon Stil", "Location": "Standort", - "Max Distance": "Maximale Distanz", + "Max Distance": "Maximale Distanz (Meters)", "Phone Number": "Phone Number", "Value": "Wert", "Assign Role": "Assign Role", diff --git a/static/locales/_en.json b/static/locales/_en.json index a4c7eef..9adba61 100644 --- a/static/locales/_en.json +++ b/static/locales/_en.json @@ -109,7 +109,7 @@ "Enable Subscriptions": "Enable Subscriptions", "Icon Style": "Icon Style", "Location": "Location", - "Max Distance": "Max Distance", + "Max Distance": "Max Distance (Meters)", "Phone Number": "Phone Number", "Value": "Value", "Assign Role": "Assign Role", diff --git a/static/locales/_es.json b/static/locales/_es.json index a4c7eef..9adba61 100644 --- a/static/locales/_es.json +++ b/static/locales/_es.json @@ -109,7 +109,7 @@ "Enable Subscriptions": "Enable Subscriptions", "Icon Style": "Icon Style", "Location": "Location", - "Max Distance": "Max Distance", + "Max Distance": "Max Distance (Meters)", "Phone Number": "Phone Number", "Value": "Value", "Assign Role": "Assign Role", From 7e32198617fb483f6dce96762a88f3dc4987701a Mon Sep 17 00:00:00 2001 From: versx Date: Mon, 10 May 2021 16:26:27 -0700 Subject: [PATCH 03/12] Fix typo --- static/js/location-selector.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/static/js/location-selector.js b/static/js/location-selector.js index f8b190a..67a4ea6 100644 --- a/static/js/location-selector.js +++ b/static/js/location-selector.js @@ -5,9 +5,13 @@ let initialLocation; let lastLocation; let circleMarker; +// TODO: Maybe upon location found, set circle position. + $('#distance').change(function(e) { - const radius = $('#distance').val(); - circle.setRadius(radius) ; + if (circleMarker) { + const radius = $('#distance').val(); + circleMarker.setRadius(radius); + } }); function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, location = null, radius = 1000) { @@ -24,8 +28,8 @@ function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, locatio map.on('click', function(e) { locationLayer.clearLayers(); const radius = $('#distance').val(); - circle = createCircle(e.latlng.lat, e.latlng.lng, radius); - locationLayer.addLayer(circle); + circleMarker = createCircle(e.latlng.lat, e.latlng.lng, radius); + locationLayer.addLayer(circleMarker); lastLocation = e.latlng; $('#location').val(`${e.latlng.lat},${e.latlng.lng}`); }); @@ -77,17 +81,17 @@ function initMap(startLocation, startZoom, minZoom, maxZoom, tileserver, locatio function loadLocation(location, radius) { const split = location.split(','); - circle = createCircle(split[0], split[1], radius); - locationLayer.addLayer(circle); + circleMarker = createCircle(split[0], split[1], radius); + locationLayer.addLayer(circleMarker); $('#location').val(location); } function createCircle(lat, lng, radius) { - circle = L.circle([lat, lng], { + circleMarker = L.circle([lat, lng], { color: 'red', fillColor: '#f03', fillOpacity: 0.5, radius: radius }); - return circle; + return circleMarker; } \ No newline at end of file From e3d0154d659ef130f8085005d238dcbd278b06df Mon Sep 17 00:00:00 2001 From: versx Date: Mon, 10 May 2021 16:52:52 -0700 Subject: [PATCH 04/12] Comment out unused css/js links --- src/views/header.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/header.mustache b/src/views/header.mustache index 820c8b8..353530c 100644 --- a/src/views/header.mustache +++ b/src/views/header.mustache @@ -9,7 +9,7 @@ - + @@ -26,7 +26,7 @@ - + From 9f9ebf55c2e4e8f6ca963c3782f563f904201f0e Mon Sep 17 00:00:00 2001 From: versx Date: Mon, 10 May 2021 18:00:36 -0700 Subject: [PATCH 05/12] Add back disabled server selector within add/edit/delete pages --- src/views/gyms/edit.mustache | 1 + src/views/gyms/new.mustache | 1 + src/views/invasions/edit.mustache | 1 + src/views/invasions/new.mustache | 1 + src/views/locations/delete-all.mustache | 1 + src/views/locations/delete.mustache | 1 + src/views/locations/edit.mustache | 1 + src/views/locations/new.mustache | 1 + src/views/lures/edit.mustache | 1 + src/views/lures/new.mustache | 1 + src/views/navbar.mustache | 1 - src/views/pokemon/edit.mustache | 1 + src/views/pokemon/new.mustache | 1 + src/views/pvp/edit.mustache | 1 + src/views/pvp/new.mustache | 5 +++++ src/views/quests/edit.mustache | 1 + src/views/quests/new.mustache | 1 + src/views/raids/edit.mustache | 1 + src/views/raids/new.mustache | 1 + src/views/roles/add.mustache | 1 + src/views/roles/remove.mustache | 6 +++++- static/locales/_de.json | 3 ++- static/locales/_en.json | 3 ++- static/locales/_es.json | 3 ++- 24 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/views/gyms/edit.mustache b/src/views/gyms/edit.mustache index 60afa43..4eff6bb 100644 --- a/src/views/gyms/edit.mustache +++ b/src/views/gyms/edit.mustache @@ -81,4 +81,5 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); diff --git a/src/views/gyms/new.mustache b/src/views/gyms/new.mustache index f1737c4..2f68a6f 100644 --- a/src/views/gyms/new.mustache +++ b/src/views/gyms/new.mustache @@ -79,6 +79,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); fetchLocations($('#server_selector').val(), '{{user_id}}', function(result) { for (const location of result.data.locations) { diff --git a/src/views/invasions/edit.mustache b/src/views/invasions/edit.mustache index 020cdcc..78f7de4 100644 --- a/src/views/invasions/edit.mustache +++ b/src/views/invasions/edit.mustache @@ -59,6 +59,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/invasions/new.mustache b/src/views/invasions/new.mustache index d9a8b8f..4b2a2c0 100644 --- a/src/views/invasions/new.mustache +++ b/src/views/invasions/new.mustache @@ -82,6 +82,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/locations/delete-all.mustache b/src/views/locations/delete-all.mustache index 4889985..c3aa7df 100644 --- a/src/views/locations/delete-all.mustache +++ b/src/views/locations/delete-all.mustache @@ -24,4 +24,5 @@ \ No newline at end of file diff --git a/src/views/locations/delete.mustache b/src/views/locations/delete.mustache index 60480d5..9185baa 100644 --- a/src/views/locations/delete.mustache +++ b/src/views/locations/delete.mustache @@ -24,4 +24,5 @@ \ No newline at end of file diff --git a/src/views/locations/edit.mustache b/src/views/locations/edit.mustache index 2b2ed91..5d53c3f 100644 --- a/src/views/locations/edit.mustache +++ b/src/views/locations/edit.mustache @@ -33,5 +33,6 @@ diff --git a/src/views/locations/new.mustache b/src/views/locations/new.mustache index 270d743..fc56675 100644 --- a/src/views/locations/new.mustache +++ b/src/views/locations/new.mustache @@ -33,6 +33,7 @@ diff --git a/src/views/pokemon/edit.mustache b/src/views/pokemon/edit.mustache index 40b735b..50e30d7 100644 --- a/src/views/pokemon/edit.mustache +++ b/src/views/pokemon/edit.mustache @@ -93,6 +93,7 @@ } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/pokemon/new.mustache b/src/views/pokemon/new.mustache index 2969f1b..49b0f28 100644 --- a/src/views/pokemon/new.mustache +++ b/src/views/pokemon/new.mustache @@ -115,6 +115,7 @@ } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/pvp/edit.mustache b/src/views/pvp/edit.mustache index f805d2a..4f3cbca 100644 --- a/src/views/pvp/edit.mustache +++ b/src/views/pvp/edit.mustache @@ -79,6 +79,7 @@ event.target.setCustomValidity('Please leave blank if you want all pokemon forms'); } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/pvp/new.mustache b/src/views/pvp/new.mustache index 3ff82c7..0180a8e 100644 --- a/src/views/pvp/new.mustache +++ b/src/views/pvp/new.mustache @@ -11,6 +11,10 @@

{{New PVP Subscription}}


+
+
{{Description}}: PvP subscriptions are based on wild spawns. If you want to receive a rank 1 Venasuar, you should subscribe to Bulbsaur, Ivysaur, and Venusaur at rank 1 since all three are wild and valid candidates.
+
+
@@ -101,6 +105,7 @@ event.target.setCustomValidity('Please leave blank if you want all pokemon forms'); } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/quests/edit.mustache b/src/views/quests/edit.mustache index 5b05b3b..988a088 100644 --- a/src/views/quests/edit.mustache +++ b/src/views/quests/edit.mustache @@ -45,6 +45,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/quests/new.mustache b/src/views/quests/new.mustache index 26218e2..132e65c 100644 --- a/src/views/quests/new.mustache +++ b/src/views/quests/new.mustache @@ -56,6 +56,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/raids/edit.mustache b/src/views/raids/edit.mustache index 65543a9..4d84327 100644 --- a/src/views/raids/edit.mustache +++ b/src/views/raids/edit.mustache @@ -61,6 +61,7 @@ event.target.setCustomValidity('Please leave blank if you want all pokemon forms'); } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/raids/new.mustache b/src/views/raids/new.mustache index 9efbf2c..224f029 100644 --- a/src/views/raids/new.mustache +++ b/src/views/raids/new.mustache @@ -85,6 +85,7 @@ event.target.setCustomValidity('Please leave blank if you want all pokemon forms'); } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/roles/add.mustache b/src/views/roles/add.mustache index 00d2f28..0d45205 100644 --- a/src/views/roles/add.mustache +++ b/src/views/roles/add.mustache @@ -33,6 +33,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); + $('#server_selector').prop('disabled', false); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/roles/remove.mustache b/src/views/roles/remove.mustache index 82532b3..34269d2 100644 --- a/src/views/roles/remove.mustache +++ b/src/views/roles/remove.mustache @@ -20,4 +20,8 @@

-
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/static/locales/_de.json b/static/locales/_de.json index 7fedaaa..9f10410 100644 --- a/static/locales/_de.json +++ b/static/locales/_de.json @@ -128,5 +128,6 @@ "Edit Location": "Edit Location", "Active": "Active", "Distance": "Distance", - "Choose a Location": "Choose a Location" + "Choose a Location": "Choose a Location", + "Description": "Description" } diff --git a/static/locales/_en.json b/static/locales/_en.json index 9adba61..ea83b6b 100644 --- a/static/locales/_en.json +++ b/static/locales/_en.json @@ -128,5 +128,6 @@ "Edit Location": "Edit Location", "Active": "Active", "Distance": "Distance", - "Choose a Location": "Choose a Location" + "Choose a Location": "Choose a Location", + "Description": "Description" } \ No newline at end of file diff --git a/static/locales/_es.json b/static/locales/_es.json index 9adba61..ea83b6b 100644 --- a/static/locales/_es.json +++ b/static/locales/_es.json @@ -128,5 +128,6 @@ "Edit Location": "Edit Location", "Active": "Active", "Distance": "Distance", - "Choose a Location": "Choose a Location" + "Choose a Location": "Choose a Location", + "Description": "Description" } \ No newline at end of file From 499e40c8ca7a1b8b27fbb3fc19e7c60b0239d742 Mon Sep 17 00:00:00 2001 From: versx Date: Tue, 11 May 2021 01:35:30 -0700 Subject: [PATCH 06/12] Add visual map of current location to settings --- src/routes/api.js | 15 +++++++++- src/views/settings.mustache | 34 +++++++++++++++++++++-- static/js/location-viewer.js | 53 ++++++++++++++++++++++++++++++++++++ static/js/locator.js | 7 ----- 4 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 static/js/location-viewer.js delete mode 100644 static/js/locator.js diff --git a/src/routes/api.js b/src/routes/api.js index 7f2be9c..789e406 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -301,10 +301,23 @@ router.post('/server/:guild_id/user/:user_id', async (req, res) => { loc.selected = loc.name === settings.location; }); */ - settings.locations = locations; + settings.locations = locations.map(x => { + return { + name: x.name, + location: `${x.latitude},${x.longitude}`, + distance: x.distance, + } + }); res.json({ data: { settings: settings } }); } break; + case 'get_location': + const locationName = req.query.name; + if (locationName) { + const location = await Location.getByName(guild_id, user_id, locationName); + res.json({ data: { location: `${location.latitude},${location.longitude}`, radius: location.distance, } }); + } + break; } }); diff --git a/src/views/settings.mustache b/src/views/settings.mustache index f37a068..781fe11 100644 --- a/src/views/settings.mustache +++ b/src/views/settings.mustache @@ -36,6 +36,9 @@ -->
+
+
+
{{^hide_phone_number}}
{{Phone Number}} @@ -56,7 +59,8 @@
- + diff --git a/src/views/gyms/new.mustache b/src/views/gyms/new.mustache index 4d22780..78ad18d 100644 --- a/src/views/gyms/new.mustache +++ b/src/views/gyms/new.mustache @@ -80,7 +80,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); - $('#server_selector').prop('disabled', false); + $('#server_selector').prop('disabled', true); fetchLocations($('#server_selector').val(), '{{user_id}}', function(result) { for (const location of result.data.locations) { diff --git a/src/views/invasions/edit.mustache b/src/views/invasions/edit.mustache index 78f7de4..37a023d 100644 --- a/src/views/invasions/edit.mustache +++ b/src/views/invasions/edit.mustache @@ -59,7 +59,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); - $('#server_selector').prop('disabled', false); + $('#server_selector').prop('disabled', true); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/invasions/new.mustache b/src/views/invasions/new.mustache index fc5d325..cd59873 100644 --- a/src/views/invasions/new.mustache +++ b/src/views/invasions/new.mustache @@ -83,7 +83,7 @@ window.location.href = '/'; } $('#guild_id').val(guildId); - $('#server_selector').prop('disabled', false); + $('#server_selector').prop('disabled', true); const guilds = document.querySelectorAll('*[id^="g_' + guildId + '"]'); if (guilds) { guilds.forEach(guild => guild.hidden = false); diff --git a/src/views/locations/delete-all.mustache b/src/views/locations/delete-all.mustache index c3aa7df..388520b 100644 --- a/src/views/locations/delete-all.mustache +++ b/src/views/locations/delete-all.mustache @@ -24,5 +24,5 @@ \ No newline at end of file diff --git a/src/views/locations/delete.mustache b/src/views/locations/delete.mustache index 9185baa..8e9049b 100644 --- a/src/views/locations/delete.mustache +++ b/src/views/locations/delete.mustache @@ -24,5 +24,5 @@ \ No newline at end of file diff --git a/src/views/locations/edit.mustache b/src/views/locations/edit.mustache index 5d53c3f..ef5d8de 100644 --- a/src/views/locations/edit.mustache +++ b/src/views/locations/edit.mustache @@ -33,6 +33,6 @@ diff --git a/src/views/locations/new.mustache b/src/views/locations/new.mustache index fc56675..cdbb75d 100644 --- a/src/views/locations/new.mustache +++ b/src/views/locations/new.mustache @@ -33,7 +33,7 @@ \ No newline at end of file From fd0cd24bb51af24d4b3ff328a82c9112758c718e Mon Sep 17 00:00:00 2001 From: versx Date: Thu, 27 May 2021 17:36:45 -0700 Subject: [PATCH 12/12] Fix dashboard loop and create city list from city selection --- src/index.js | 46 +++++++++++++++---------------- src/views/invasions/edit.mustache | 13 +++++++-- src/views/invasions/new.mustache | 13 +++++++-- src/views/lures/edit.mustache | 13 +++++++-- src/views/lures/new.mustache | 13 +++++++-- src/views/navbar.mustache | 3 -- src/views/pokemon/edit.mustache | 15 +++++++--- src/views/pokemon/new.mustache | 13 +++++++-- src/views/pvp/edit.mustache | 13 +++++++-- src/views/pvp/new.mustache | 13 +++++++-- src/views/quests/edit.mustache | 13 +++++++-- src/views/quests/new.mustache | 13 +++++++-- src/views/raids/edit.mustache | 13 +++++++-- src/views/raids/new.mustache | 13 +++++++-- static/js/city-map.js | 38 +++++++++++++++++++++++++ 15 files changed, 193 insertions(+), 52 deletions(-) diff --git a/src/index.js b/src/index.js index 49e99e2..5c50acd 100644 --- a/src/index.js +++ b/src/index.js @@ -105,7 +105,7 @@ const utils = require('./services/utils.js'); await Session.clearOthers(req.session.user_id, req.sessionID); } */ - if (config.discord.enabled && !req.session.valid) { + if (!req.session.valid && req.path !== '/login') { console.error('Invalid user authenticated', req.session.user_id); req.session.current_path = req.path; res.redirect('/login'); @@ -117,32 +117,32 @@ const utils = require('./services/utils.js'); return next(); } - if (req.session.logged_in) { - defaultData.logged_in = req.session.logged_in; - defaultData.username = req.session.username || 'root'; - defaultData.user_id = req.session.user_id; - let valid = false; - const guilds = req.session.guilds; - const roles = req.session.roles; - defaultData.servers.forEach(server => { - if (roles[server.id]) { - const userRoles = roles[server.id]; - const requiredRoles = config.discord.guilds.filter(x => x.id === server.id); - if (requiredRoles.length > 0) { - if (guilds.includes(server.id) && utils.hasRole(userRoles, requiredRoles[0].roles)) { - valid = true; - } + if (!req.session.logged_in) { + res.redirect('/login'); + } + defaultData.logged_in = req.session.logged_in; + defaultData.username = req.session.username || 'root'; + defaultData.user_id = req.session.user_id; + let valid = false; + const guilds = req.session.guilds; + const roles = req.session.roles; + defaultData.servers.forEach(server => { + if (roles[server.id]) { + const userRoles = roles[server.id]; + const requiredRoles = config.discord.guilds.filter(x => x.id === server.id); + if (requiredRoles.length > 0) { + if (guilds.includes(server.id) && utils.hasRole(userRoles, requiredRoles[0].roles)) { + valid = true; } } - }); - if (!req.session.valid || !valid) { - console.error('Invalid user authentication, no valid roles for user', req.session.user_id); - res.redirect('/login'); - return; } - return next(); + }); + if (!req.session.valid || !valid) { + console.error('Invalid user authentication, no valid roles for user', req.session.user_id); + res.redirect('/login'); + return; } - res.redirect('/login'); + return next(); }); // API routes diff --git a/src/views/invasions/edit.mustache b/src/views/invasions/edit.mustache index 37a023d..410ffb8 100644 --- a/src/views/invasions/edit.mustache +++ b/src/views/invasions/edit.mustache @@ -29,10 +29,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/invasions/new.mustache b/src/views/invasions/new.mustache index cd59873..5609197 100644 --- a/src/views/invasions/new.mustache +++ b/src/views/invasions/new.mustache @@ -57,10 +57,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/lures/edit.mustache b/src/views/lures/edit.mustache index ec76cdd..1820fcc 100644 --- a/src/views/lures/edit.mustache +++ b/src/views/lures/edit.mustache @@ -15,10 +15,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/lures/new.mustache b/src/views/lures/new.mustache index 16daebf..787d9f4 100644 --- a/src/views/lures/new.mustache +++ b/src/views/lures/new.mustache @@ -24,10 +24,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/navbar.mustache b/src/views/navbar.mustache index 337d66a..40276f3 100644 --- a/src/views/navbar.mustache +++ b/src/views/navbar.mustache @@ -82,9 +82,6 @@ const guildId = get("guild_id"); $("#server_selector").val(guildId); $('#guild_id').val(guildId); - if (!guildId) { - window.location.href = '/'; - } $(document).ready(function() { // Get current URL path and assign 'active' class var pathname = window.location.pathname; diff --git a/src/views/pokemon/edit.mustache b/src/views/pokemon/edit.mustache index 2f2f672..4d53955 100644 --- a/src/views/pokemon/edit.mustache +++ b/src/views/pokemon/edit.mustache @@ -57,10 +57,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} @@ -105,6 +114,4 @@ $('#iv').prop('disabled', this.value.length > 0); }); initMap([{{start_lat}}, {{start_lon}}], {{start_zoom}}, {{min_zoom}}, {{max_zoom}}, "{{{tileserver}}}", {{{cities}}}); - - console.log("{{{locations}}}"); \ No newline at end of file diff --git a/src/views/pokemon/new.mustache b/src/views/pokemon/new.mustache index e3dd878..37041ed 100644 --- a/src/views/pokemon/new.mustache +++ b/src/views/pokemon/new.mustache @@ -85,10 +85,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/pvp/edit.mustache b/src/views/pvp/edit.mustache index 018ab1f..66952fe 100644 --- a/src/views/pvp/edit.mustache +++ b/src/views/pvp/edit.mustache @@ -44,10 +44,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/pvp/new.mustache b/src/views/pvp/new.mustache index bc4e467..abf3cb8 100644 --- a/src/views/pvp/new.mustache +++ b/src/views/pvp/new.mustache @@ -76,10 +76,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/quests/edit.mustache b/src/views/quests/edit.mustache index af267ec..d17551c 100644 --- a/src/views/quests/edit.mustache +++ b/src/views/quests/edit.mustache @@ -15,10 +15,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/quests/new.mustache b/src/views/quests/new.mustache index 4e24d7e..1fe3d6f 100644 --- a/src/views/quests/new.mustache +++ b/src/views/quests/new.mustache @@ -31,10 +31,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/raids/edit.mustache b/src/views/raids/edit.mustache index d06cf9e..58db87b 100644 --- a/src/views/raids/edit.mustache +++ b/src/views/raids/edit.mustache @@ -27,10 +27,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/src/views/raids/new.mustache b/src/views/raids/new.mustache index ca7ce4d..ef9ff8f 100644 --- a/src/views/raids/new.mustache +++ b/src/views/raids/new.mustache @@ -56,10 +56,19 @@
{{City}}
- -
+
+ +
+
+
+
+
+
    +
+
+
{{Location}} diff --git a/static/js/city-map.js b/static/js/city-map.js index 5bdd9a2..ac08be1 100644 --- a/static/js/city-map.js +++ b/static/js/city-map.js @@ -87,6 +87,7 @@ function loadGeofences(selected) { featureLayer.setStyle({ fillColor: 'green', }); + createCityListItem(area); } } // Set dom value to selected geofences @@ -103,6 +104,7 @@ function loadGeofence(feature, featureLayer, isClick) { featureLayer.setStyle({ fillColor: 'green', }); + createCityListItem(feature.properties.name); } else { // Get index of de-selected geofence const index = selectedGeofences.indexOf(feature.properties.name); @@ -115,6 +117,7 @@ function loadGeofence(feature, featureLayer, isClick) { featureLayer.setStyle({ fillColor: 'red', }); + removeCityListItem(feature.properties.name); } } else { // Check if geofence is in initially selected geofences to edit @@ -123,16 +126,48 @@ function loadGeofence(feature, featureLayer, isClick) { featureLayer.setStyle({ fillColor: 'green', }); + createCityListItem(feature.properties.name); } else { featureLayer.setStyle({ fillColor: 'red', }); + removeCityListItem(feature.properties.name); } } // Set dom value to selected geofences $('#city').val(selectedGeofences.join(',')); } +function createCityListItem(name) { + const ul = document.getElementById('city-list'); + if (!containsCityListItem(name)) { + const li = document.createElement('li'); + li.classList.add('list-group-item'); + li.id = name; + const node = document.createTextNode(name); + li.appendChild(node); + ul.appendChild(li); + } +} + +function removeCityListItem(name) { + const ul = document.getElementById('city-list'); + if (containsCityListItem(name)) { + const li = document.getElementById(name); + ul.removeChild(li) + } +} + +function containsCityListItem(name) { + let found = false; + $("#city-list li").each((id, elem) => { + if (elem.innerText === name) { + found = true; + } + }); + return found; +} + function selectGeofences(all) { // Clear selected geofences list selectedGeofences = []; @@ -141,6 +176,9 @@ function selectGeofences(all) { // Check if we need to select all if (all) { selectedGeofences.push(layer.feature.properties.name); + createCityListItem(layer.feature.properties.name); + } else { + removeCityListItem(layer.feature.properties.name); } // Set color based on selection layer.setStyle({